aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,audmix.txt50
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,audmix.yaml83
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt68
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.yaml116
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml14
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,sai.yaml6
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.yaml35
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-asoc-card.txt117
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml195
-rw-r--r--Documentation/devicetree/bindings/sound/nuvoton,nau8325.yaml80
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml98
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8776.yaml41
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8974.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8974.yaml41
-rw-r--r--Documentation/devicetree/bindings/sound/wm8776.txt18
-rw-r--r--MAINTAINERS7
-rw-r--r--include/sound/control.h23
-rw-r--r--include/sound/dmaengine_pcm.h2
-rw-r--r--include/sound/soc-acpi-intel-ssp-common.h (renamed from sound/soc/intel/boards/sof_ssp_common.h)29
-rw-r--r--include/sound/soc-acpi.h12
-rw-r--r--include/sound/soc-jack.h2
-rw-r--r--include/sound/soc.h12
-rw-r--r--sound/soc/Kconfig8
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/amd/Kconfig5
-rw-r--r--sound/soc/codecs/Kconfig11
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/es8326.c41
-rw-r--r--sound/soc/codecs/hdac_hda.c44
-rw-r--r--sound/soc/codecs/max98373-sdw.c1
-rw-r--r--sound/soc/codecs/nau8325.c900
-rw-r--r--sound/soc/codecs/nau8325.h391
-rw-r--r--sound/soc/codecs/rk3308_codec.c974
-rw-r--r--sound/soc/codecs/rk3308_codec.h579
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt1308-sdw.c1
-rw-r--r--sound/soc/codecs/rt1316-sdw.c1
-rw-r--r--sound/soc/codecs/rt1318-sdw.c1
-rw-r--r--sound/soc/codecs/rt5682-sdw.c1
-rw-r--r--sound/soc/codecs/rt700-sdw.c1
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt711-sdw.c1
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c1
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt715-sdca.c4
-rw-r--r--sound/soc/codecs/rt715-sdw.c1
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/sdw-mockup.c1
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c1
-rw-r--r--sound/soc/codecs/tlv320aic3x-spi.c1
-rw-r--r--sound/soc/fsl/fsl_rpmsg.c43
-rw-r--r--sound/soc/fsl/fsl_ssi.c4
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c21
-rw-r--r--sound/soc/fsl/imx-es8328.c17
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c11
-rw-r--r--sound/soc/fsl/imx-rpmsg.c28
-rw-r--r--sound/soc/generic/simple-card-utils.c2
-rw-r--r--sound/soc/intel/avs/avs.h2
-rw-r--r--sound/soc/intel/avs/boards/es8336.c2
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c6
-rw-r--r--sound/soc/intel/avs/boards/i2s_test.c79
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c2
-rw-r--r--sound/soc/intel/avs/boards/rt274.c2
-rw-r--r--sound/soc/intel/avs/boards/rt286.c2
-rw-r--r--sound/soc/intel/avs/boards/rt298.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c2
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c5
-rw-r--r--sound/soc/intel/avs/utils.c8
-rw-r--r--sound/soc/intel/boards/Kconfig15
-rw-r--r--sound/soc/intel/boards/Makefile7
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c1
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c1
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c1
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c4
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c1
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c2
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c1
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c1
-rw-r--r--sound/soc/intel/boards/skl_rt286.c1
-rw-r--r--sound/soc/intel/boards/sof_board_helpers.c161
-rw-r--r--sound/soc/intel/boards/sof_board_helpers.h106
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.h2
-rw-r--r--sound/soc/intel/boards/sof_cs42l42.c89
-rw-r--r--sound/soc/intel/boards/sof_da7219.c410
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.h2
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c97
-rw-r--r--sound/soc/intel/boards/sof_nuvoton_common.h2
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.h2
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c218
-rw-r--r--sound/soc/intel/boards/sof_sdw.c1090
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h42
-rw-r--r--sound/soc/intel/boards/sof_sdw_cs42l42.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_cs42l43.c50
-rw-r--r--sound/soc/intel/boards/sof_sdw_cs_amp.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_maxim.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt5682.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt700.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt711.c2
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt712_sdca.c25
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715.c26
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715_sdca.c26
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt722_sdca.c38
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt_amp.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt_dmic.c54
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c4
-rw-r--r--sound/soc/intel/boards/sof_ssp_amp.c268
-rw-r--r--sound/soc/intel/boards/sof_ssp_common.c122
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c141
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c24
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c4
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c87
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c92
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ssp-common.c159
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c85
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c3
-rw-r--r--sound/soc/loongson/loongson_i2s_pci.c1
-rw-r--r--sound/soc/mediatek/common/Makefile2
-rw-r--r--sound/soc/mediatek/common/mtk-dai-adda-common.c70
-rw-r--r--sound/soc/mediatek/common/mtk-dai-adda-common.h45
-rw-r--r--sound/soc/mediatek/common/mtk-soundcard-driver.c6
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-adda.c85
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-adda.c90
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-adda.c92
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-adda.c89
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-pcm.c95
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-adda.c90
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-adda.c90
-rw-r--r--sound/soc/sh/rcar/cmd.c6
-rw-r--r--sound/soc/sh/rcar/core.c4
-rw-r--r--sound/soc/sh/rcar/ctu.c6
-rw-r--r--sound/soc/sh/rcar/dma.c6
-rw-r--r--sound/soc/sh/rcar/dvc.c6
-rw-r--r--sound/soc/sh/rcar/gen.c519
-rw-r--r--sound/soc/sh/rcar/mix.c6
-rw-r--r--sound/soc/sh/rcar/rsnd.h22
-rw-r--r--sound/soc/sh/rcar/src.c12
-rw-r--r--sound/soc/sh/rcar/ssi.c2
-rw-r--r--sound/soc/sh/rcar/ssiu.c2
-rw-r--r--sound/soc/soc-card-test.c184
-rw-r--r--sound/soc/soc-card.c21
-rw-r--r--sound/soc/soc-core.c8
-rw-r--r--sound/soc/soc-dai.c2
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c3
-rw-r--r--sound/soc/soc-jack.c23
-rw-r--r--sound/soc/soc-topology.c11
-rw-r--r--sound/soc/sof/amd/acp-loader.c2
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c41
-rw-r--r--sound/soc/sof/intel/hda-dai.c124
-rw-r--r--sound/soc/sof/intel/hda.c111
-rw-r--r--sound/soc/sof/intel/hda.h11
-rw-r--r--sound/soc/sof/ipc4-loader.c8
-rw-r--r--sound/soc/sof/ipc4-priv.h2
-rw-r--r--sound/soc/sof/ipc4-topology.c63
-rw-r--r--sound/soc/sof/ipc4-topology.h3
-rw-r--r--sound/soc/sof/pcm.c58
-rw-r--r--sound/soc/sof/sof-audio.c29
-rw-r--r--sound/soc/sof/sof-audio.h2
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c73
-rw-r--r--sound/soc/sunxi/sun8i-codec.c346
165 files changed, 6729 insertions, 3510 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,audmix.txt b/Documentation/devicetree/bindings/sound/fsl,audmix.txt
deleted file mode 100644
index 840b7e0d6a63..000000000000
--- a/Documentation/devicetree/bindings/sound/fsl,audmix.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-NXP Audio Mixer (AUDMIX).
-
-The Audio Mixer is a on-chip functional module that allows mixing of two
-audio streams into a single audio stream. Audio Mixer has two input serial
-audio interfaces. These are driven by two Synchronous Audio interface
-modules (SAI). Each input serial interface carries 8 audio channels in its
-frame in TDM manner. Mixer mixes audio samples of corresponding channels
-from two interfaces into a single sample. Before mixing, audio samples of
-two inputs can be attenuated based on configuration. The output of the
-Audio Mixer is also a serial audio interface. Like input interfaces it has
-the same TDM frame format. This output is used to drive the serial DAC TDM
-interface of audio codec and also sent to the external pins along with the
-receive path of normal audio SAI module for readback by the CPU.
-
-The output of Audio Mixer can be selected from any of the three streams
- - serial audio input 1
- - serial audio input 2
- - mixed audio
-
-Mixing operation is independent of audio sample rate but the two audio
-input streams must have same audio sample rate with same number of channels
-in TDM frame to be eligible for mixing.
-
-Device driver required properties:
-=================================
- - compatible : Compatible list, contains "fsl,imx8qm-audmix"
-
- - reg : Offset and length of the register set for the device.
-
- - clocks : Must contain an entry for each entry in clock-names.
-
- - clock-names : Must include the "ipg" for register access.
-
- - power-domains : Must contain the phandle to AUDMIX power domain node
-
- - dais : Must contain a list of phandles to AUDMIX connected
- DAIs. The current implementation requires two phandles
- to SAI interfaces to be provided, the first SAI in the
- list being used to route the AUDMIX output.
-
-Device driver configuration example:
-======================================
- audmix: audmix@59840000 {
- compatible = "fsl,imx8qm-audmix";
- reg = <0x0 0x59840000 0x0 0x10000>;
- clocks = <&clk IMX8QXP_AUD_AUDMIX_IPG>;
- clock-names = "ipg";
- power-domains = <&pd_audmix>;
- dais = <&sai4>, <&sai5>;
- };
diff --git a/Documentation/devicetree/bindings/sound/fsl,audmix.yaml b/Documentation/devicetree/bindings/sound/fsl,audmix.yaml
new file mode 100644
index 000000000000..9413b901cf77
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,audmix.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,audmix.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Audio Mixer (AUDMIX).
+
+maintainers:
+ - Shengjiu Wang <shengjiu.wang@nxp.com>
+ - Frank Li <Frank.Li@nxp.com>
+
+description: |
+ The Audio Mixer is a on-chip functional module that allows mixing of two
+ audio streams into a single audio stream. Audio Mixer has two input serial
+ audio interfaces. These are driven by two Synchronous Audio interface
+ modules (SAI). Each input serial interface carries 8 audio channels in its
+ frame in TDM manner. Mixer mixes audio samples of corresponding channels
+ from two interfaces into a single sample. Before mixing, audio samples of
+ two inputs can be attenuated based on configuration. The output of the
+ Audio Mixer is also a serial audio interface. Like input interfaces it has
+ the same TDM frame format. This output is used to drive the serial DAC TDM
+ interface of audio codec and also sent to the external pins along with the
+ receive path of normal audio SAI module for readback by the CPU.
+
+ The output of Audio Mixer can be selected from any of the three streams
+ - serial audio input 1
+ - serial audio input 2
+ - mixed audio
+
+ Mixing operation is independent of audio sample rate but the two audio
+ input streams must have same audio sample rate with same number of channels
+ in TDM frame to be eligible for mixing.
+
+properties:
+ compatible:
+ const: fsl,imx8qm-audmix
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: ipg
+
+ power-domains:
+ maxItems: 1
+
+ dais:
+ description: contain a list of phandles to AUDMIX connected DAIs.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ minItems: 2
+ items:
+ - description: the AUDMIX output
+ maxItems: 1
+ - description: serial audio input 1
+ maxItems: 1
+ - description: serial audio input 2
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - power-domains
+ - dais
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ audmix@59840000 {
+ compatible = "fsl,imx8qm-audmix";
+ reg = <0x59840000 0x10000>;
+ clocks = <&amix_lpcg 0>;
+ clock-names = "ipg";
+ power-domains = <&pd_audmix>;
+ dais = <&sai4>, <&sai5>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
deleted file mode 100644
index 90112ca1ff42..000000000000
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-Freescale Enhanced Serial Audio Interface (ESAI) Controller
-
-The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
-for serial communication with a variety of serial devices, including industry
-standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
-other DSPs. It has up to six transmitters and four receivers.
-
-Required properties:
-
- - compatible : Compatible list, should contain one of the following
- compatibles:
- "fsl,imx35-esai",
- "fsl,vf610-esai",
- "fsl,imx6ull-esai",
- "fsl,imx8qm-esai",
-
- - reg : Offset and length of the register set for the device.
-
- - interrupts : Contains the spdif interrupt.
-
- - dmas : Generic dma devicetree binding as described in
- Documentation/devicetree/bindings/dma/dma.txt.
-
- - dma-names : Two dmas have to be defined, "tx" and "rx".
-
- - clocks : Contains an entry for each entry in clock-names.
-
- - clock-names : Includes the following entries:
- "core" The core clock used to access registers
- "extal" The esai baud clock for esai controller used to
- derive HCK, SCK and FS.
- "fsys" The system clock derived from ahb clock used to
- derive HCK, SCK and FS.
- "spba" The spba clock is required when ESAI is placed as a
- bus slave of the Shared Peripheral Bus and when two
- or more bus masters (CPU, DMA or DSP) try to access
- it. This property is optional depending on the SoC
- design.
-
- - fsl,fifo-depth : The number of elements in the transmit and receive
- FIFOs. This number is the maximum allowed value for
- TFCR[TFWM] or RFCR[RFWM].
-
- - fsl,esai-synchronous: This is a boolean property. If present, indicating
- that ESAI would work in the synchronous mode, which
- means all the settings for Receiving would be
- duplicated from Transmission related registers.
-
-Optional properties:
-
- - big-endian : If this property is absent, the native endian mode
- will be in use as default, or the big endian mode
- will be in use for all the device registers.
-
-Example:
-
-esai: esai@2024000 {
- compatible = "fsl,imx35-esai";
- reg = <0x02024000 0x4000>;
- interrupts = <0 51 0x04>;
- clocks = <&clks 208>, <&clks 118>, <&clks 208>;
- clock-names = "core", "extal", "fsys";
- dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
- dma-names = "rx", "tx";
- fsl,fifo-depth = <128>;
- fsl,esai-synchronous;
- big-endian;
-};
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.yaml b/Documentation/devicetree/bindings/sound/fsl,esai.yaml
new file mode 100644
index 000000000000..f167f1634d7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,esai.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Enhanced Serial Audio Interface (ESAI) Controller
+
+maintainers:
+ - Shengjiu Wang <shengjiu.wang@nxp.com>
+ - Frank Li <Frank.Li@nxp.com>
+
+description:
+ The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
+ for serial communication with a variety of serial devices, including industry
+ standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
+ other DSPs. It has up to six transmitters and four receivers.
+
+properties:
+ compatible:
+ enum:
+ - fsl,imx35-esai
+ - fsl,imx6ull-esai
+ - fsl,imx8qm-esai
+ - fsl,vf610-esai
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 3
+ items:
+ - description:
+ The core clock used to access registers.
+ - description:
+ The esai baud clock for esai controller used to
+ derive HCK, SCK and FS.
+ - description:
+ The system clock derived from ahb clock used to
+ derive HCK, SCK and FS.
+ - description:
+ The spba clock is required when ESAI is placed as a
+ bus slave of the Shared Peripheral Bus and when two
+ or more bus masters (CPU, DMA or DSP) try to access
+ it. This property is optional depending on the SoC
+ design.
+
+ clock-names:
+ minItems: 3
+ items:
+ - const: core
+ - const: extal
+ - const: fsys
+ - const: spba
+
+ dmas:
+ minItems: 2
+ maxItems: 2
+
+ dma-names:
+ items:
+ - const: rx
+ - const: tx
+
+ fsl,fifo-depth:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ The number of elements in the transmit and receive
+ FIFOs. This number is the maximum allowed value for
+ TFCR[TFWM] or RFCR[RFWM].
+
+ fsl,esai-synchronous:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ This is a boolean property. If present, indicating
+ that ESAI would work in the synchronous mode, which
+ means all the settings for Receiving would be
+ duplicated from Transmission related registers.
+
+ big-endian:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ If this property is absent, the native endian mode
+ will be in use as default, or the big endian mode
+ will be in use for all the device registers.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - dmas
+ - dma-names
+ - fsl,fifo-depth
+ - fsl,esai-synchronous
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ esai@2024000 {
+ compatible = "fsl,imx35-esai";
+ reg = <0x02024000 0x4000>;
+ interrupts = <0 51 0x04>;
+ clocks = <&clks 208>, <&clks 118>, <&clks 208>;
+ clock-names = "core", "extal", "fsys";
+ dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
+ dma-names = "rx", "tx";
+ fsl,fifo-depth = <128>;
+ fsl,esai-synchronous;
+ big-endian;
+ };
diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
index bfef2fcb75b1..76aa1f248488 100644
--- a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
@@ -74,6 +74,9 @@ properties:
- const: asrck_f
- const: spba
+ power-domains:
+ maxItems: 1
+
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
description: The mutual sample rate used by DPCM Back Ends
@@ -131,6 +134,17 @@ allOf:
properties:
fsl,asrc-clk-map: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx8qm-asrc
+ - fsl,imx8qxp-asrc
+ then:
+ required:
+ - power-domains
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/sound/fsl,sai.yaml b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
index 2456d958adee..a5d9c246cc47 100644
--- a/Documentation/devicetree/bindings/sound/fsl,sai.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,sai.yaml
@@ -81,14 +81,12 @@ properties:
dmas:
minItems: 1
- items:
- - description: DMA controller phandle and request line for RX
- - description: DMA controller phandle and request line for TX
+ maxItems: 2
dma-names:
minItems: 1
items:
- - const: rx
+ - enum: [ rx, tx ]
- const: tx
interrupts:
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml
index 1d64e8337aa4..204f361cea27 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml
@@ -31,7 +31,10 @@ properties:
maxItems: 1
interrupts:
- maxItems: 1
+ minItems: 1
+ items:
+ - description: Combined or receive interrupt
+ - description: Transmit interrupt
dmas:
items:
@@ -86,6 +89,9 @@ properties:
registers. Set this flag for HCDs with big endian descriptors and big
endian registers.
+ power-domains:
+ maxItems: 1
+
required:
- compatible
- reg
@@ -97,6 +103,33 @@ required:
additionalProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ enum:
+ - fsl,imx8qm-spdif
+ - fsl,imx8qxp-spdif
+ then:
+ properties:
+ interrupts:
+ minItems: 2
+ else:
+ properties:
+ interrupts:
+ maxItems: 1
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx8qm-spdif
+ - fsl,imx8qxp-spdif
+ then:
+ required:
+ - power-domains
+
examples:
- |
spdif@2004000 {
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
deleted file mode 100644
index 4e8dbc5abfd1..000000000000
--- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
+++ /dev/null
@@ -1,117 +0,0 @@
-Freescale Generic ASoC Sound Card with ASRC support
-
-The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale
-SoCs connecting with external CODECs.
-
-The idea of this generic sound card is a bit like ASoC Simple Card. However,
-for Freescale SoCs (especially those released in recent years), most of them
-have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And
-this is a specific feature that might be painstakingly controlled and merged
-into the Simple Card.
-
-So having this generic sound card allows all Freescale SoC users to benefit
-from the simplification of a new card support and the capability of the wide
-sample rates support through ASRC.
-
-Note: The card is initially designed for those sound cards who use AC'97, I2S
- and PCM DAI formats. However, it'll be also possible to support those non
- AC'97/I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as
- long as the driver has been properly upgraded.
-
-
-The compatible list for this generic sound card currently:
- "fsl,imx-audio-ac97"
-
- "fsl,imx-audio-cs42888"
-
- "fsl,imx-audio-cs427x"
- (compatible with CS4271 and CS4272)
-
- "fsl,imx-audio-wm8962"
-
- "fsl,imx-audio-sgtl5000"
- (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
-
- "fsl,imx-audio-wm8960"
-
- "fsl,imx-audio-mqs"
-
- "fsl,imx-audio-wm8524"
-
- "fsl,imx-audio-tlv320aic32x4"
-
- "fsl,imx-audio-tlv320aic31xx"
-
- "fsl,imx-audio-si476x"
-
- "fsl,imx-audio-wm8958"
-
- "fsl,imx-audio-nau8822"
-
-Required properties:
-
- - compatible : Contains one of entries in the compatible list.
-
- - model : The user-visible name of this sound complex
-
- - audio-cpu : The phandle of an CPU DAI controller
-
- - audio-codec : The phandle of an audio codec
-
-Optional properties:
-
- - audio-asrc : The phandle of ASRC. It can be absent if there's no
- need to add ASRC support via DPCM.
-
- - audio-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. There're a few pre-designed board connectors:
- * Line Out Jack
- * Line In Jack
- * Headphone Jack
- * Mic Jack
- * Ext Spk
- * AMIC (stands for Analog Microphone Jack)
- * DMIC (stands for Digital Microphone Jack)
-
- Note: The "Mic Jack" and "AMIC" are redundant while
- coexisting in order to support the old bindings
- of wm8962 and sgtl5000.
-
- - hp-det-gpio : The GPIO that detect headphones are plugged in
- - mic-det-gpio : The GPIO that detect microphones are plugged in
- - bitclock-master : Indicates dai-link bit clock master; for details see simple-card.yaml.
- - frame-master : Indicates dai-link frame master; for details see simple-card.yaml.
- - dai-format : audio format, for details see simple-card.yaml.
- - frame-inversion : dai-link uses frame clock inversion, for details see simple-card.yaml.
- - bitclock-inversion : dai-link uses bit clock inversion, for details see simple-card.yaml.
- - mclk-id : main clock id, specific for each card configuration.
-
-Optional unless SSI is selected as a CPU DAI:
-
- - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
-
- - mux-ext-port : The external port of the i.MX audio muxer
-
-Example:
-sound-cs42888 {
- compatible = "fsl,imx-audio-cs42888";
- model = "cs42888-audio";
- audio-cpu = <&esai>;
- audio-asrc = <&asrc>;
- audio-codec = <&cs42888>;
- audio-routing =
- "Line Out Jack", "AOUT1L",
- "Line Out Jack", "AOUT1R",
- "Line Out Jack", "AOUT2L",
- "Line Out Jack", "AOUT2R",
- "Line Out Jack", "AOUT3L",
- "Line Out Jack", "AOUT3R",
- "Line Out Jack", "AOUT4L",
- "Line Out Jack", "AOUT4R",
- "AIN1L", "Line In Jack",
- "AIN1R", "Line In Jack",
- "AIN2L", "Line In Jack",
- "AIN2R", "Line In Jack";
-};
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml
new file mode 100644
index 000000000000..42ca39eebd49
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.yaml
@@ -0,0 +1,195 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl-asoc-card.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Generic ASoC Sound Card with ASRC support
+
+description:
+ The Freescale Generic ASoC Sound Card can be used, ideally,
+ for all Freescale SoCs connecting with external CODECs.
+
+ The idea of this generic sound card is a bit like ASoC Simple Card.
+ However, for Freescale SoCs (especially those released in recent years),
+ most of them have ASRC inside. And this is a specific feature that might
+ be painstakingly controlled and merged into the Simple Card.
+
+ So having this generic sound card allows all Freescale SoC users to
+ benefit from the simplification of a new card support and the capability
+ of the wide sample rates support through ASRC.
+
+ Note, The card is initially designed for those sound cards who use AC'97, I2S
+ and PCM DAI formats. However, it'll be also possible to support those non
+ AC'97/I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as
+ long as the driver has been properly upgraded.
+
+maintainers:
+ - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,imx-sgtl5000
+ - fsl,imx53-cpuvo-sgtl5000
+ - fsl,imx51-babbage-sgtl5000
+ - fsl,imx53-m53evk-sgtl5000
+ - fsl,imx53-qsb-sgtl5000
+ - fsl,imx53-voipac-sgtl5000
+ - fsl,imx6-armadeus-sgtl5000
+ - fsl,imx6-rex-sgtl5000
+ - fsl,imx6-sabreauto-cs42888
+ - fsl,imx6-wandboard-sgtl5000
+ - fsl,imx6dl-nit6xlite-sgtl5000
+ - fsl,imx6q-ba16-sgtl5000
+ - fsl,imx6q-nitrogen6_max-sgtl5000
+ - fsl,imx6q-nitrogen6_som2-sgtl5000
+ - fsl,imx6q-nitrogen6x-sgtl5000
+ - fsl,imx6q-sabrelite-sgtl5000
+ - fsl,imx6q-sabresd-wm8962
+ - fsl,imx6q-udoo-ac97
+ - fsl,imx6q-ventana-sgtl5000
+ - fsl,imx6sl-evk-wm8962
+ - fsl,imx6sx-sdb-mqs
+ - fsl,imx6sx-sdb-wm8962
+ - fsl,imx7d-evk-wm8960
+ - karo,tx53-audio-sgtl5000
+ - tq,imx53-mba53-sgtl5000
+ - enum:
+ - fsl,imx-audio-ac97
+ - fsl,imx-audio-cs42888
+ - fsl,imx-audio-mqs
+ - fsl,imx-audio-sgtl5000
+ - fsl,imx-audio-wm8960
+ - fsl,imx-audio-wm8962
+ - items:
+ - enum:
+ - fsl,imx-audio-ac97
+ - fsl,imx-audio-cs42888
+ - fsl,imx-audio-cs427x
+ - fsl,imx-audio-mqs
+ - fsl,imx-audio-nau8822
+ - fsl,imx-audio-sgtl5000
+ - fsl,imx-audio-si476x
+ - fsl,imx-audio-tlv320aic31xx
+ - fsl,imx-audio-tlv320aic32x4
+ - fsl,imx-audio-wm8524
+ - fsl,imx-audio-wm8960
+ - fsl,imx-audio-wm8962
+ - fsl,imx-audio-wm8958
+
+ model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: The user-visible name of this sound complex
+
+ audio-asrc:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle of ASRC. It can be absent if there's no
+ need to add ASRC support via DPCM.
+
+ audio-codec:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of an audio codec
+
+ audio-cpu:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of an CPU DAI controller
+
+ audio-routing:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ A list of the connections between audio components. Each entry is a
+ pair of strings, the first being the connection's sink, the second
+ being the connection's source. There're a few pre-designed board
+ connectors. "AMIC" stands for Analog Microphone Jack.
+ "DMIC" stands for Digital Microphone Jack. The "Mic Jack" and "AMIC"
+ are redundant while coexisting in order to support the old bindings
+ of wm8962 and sgtl5000.
+
+ hp-det-gpio:
+ deprecated: true
+ maxItems: 1
+ description: The GPIO that detect headphones are plugged in
+
+ hp-det-gpios:
+ maxItems: 1
+ description: The GPIO that detect headphones are plugged in
+
+ mic-det-gpio:
+ deprecated: true
+ maxItems: 1
+ description: The GPIO that detect microphones are plugged in
+
+ mic-det-gpios:
+ maxItems: 1
+ description: The GPIO that detect microphones are plugged in
+
+ bitclock-master:
+ $ref: simple-card.yaml#/definitions/bitclock-master
+ description: Indicates dai-link bit clock master.
+
+ frame-master:
+ $ref: simple-card.yaml#/definitions/frame-master
+ description: Indicates dai-link frame master.
+
+ format:
+ $ref: simple-card.yaml#/definitions/format
+ description: audio format.
+
+ frame-inversion:
+ $ref: simple-card.yaml#/definitions/frame-inversion
+ description: dai-link uses frame clock inversion.
+
+ bitclock-inversion:
+ $ref: simple-card.yaml#/definitions/bitclock-inversion
+ description: dai-link uses bit clock inversion.
+
+ mclk-id:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: main clock id, specific for each card configuration.
+
+ mux-int-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 2, 7]
+ description: The internal port of the i.MX audio muxer (AUDMUX)
+
+ mux-ext-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [3, 4, 5, 6]
+ description: The external port of the i.MX audio muxer
+
+ ssi-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of an CPU DAI controller
+
+required:
+ - compatible
+ - model
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ sound-cs42888 {
+ compatible = "fsl,imx-audio-cs42888";
+ model = "cs42888-audio";
+ audio-cpu = <&esai>;
+ audio-asrc = <&asrc>;
+ audio-codec = <&cs42888>;
+ audio-routing =
+ "Line Out Jack", "AOUT1L",
+ "Line Out Jack", "AOUT1R",
+ "Line Out Jack", "AOUT2L",
+ "Line Out Jack", "AOUT2R",
+ "Line Out Jack", "AOUT3L",
+ "Line Out Jack", "AOUT3R",
+ "Line Out Jack", "AOUT4L",
+ "Line Out Jack", "AOUT4R",
+ "AIN1L", "Line In Jack",
+ "AIN1R", "Line In Jack",
+ "AIN2L", "Line In Jack",
+ "AIN2R", "Line In Jack";
+ };
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8325.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8325.yaml
new file mode 100644
index 000000000000..979be0d336da
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8325.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nuvoton,nau8325.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NAU8325 audio Amplifier
+
+maintainers:
+ - Seven Lee <WTLI@nuvoton.com>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: nuvoton,nau8325
+
+ reg:
+ maxItems: 1
+
+ nuvoton,vref-impedance-ohms:
+ description:
+ The vref impedance to be used in ohms. Middle of voltage enables
+ Tie-Off selection options. Due to the high impedance of the VREF
+ pin, it is important to use a low-leakage capacitor.
+
+ enum: [0, 25000, 125000, 2500]
+
+ nuvoton,dac-vref-microvolt:
+ description:
+ The DAC vref to be used in voltage. DAC reference voltage setting. Can
+ be used for minor tuning of the output level. Since the VDDA is range
+ between 1.62 to 1.98 voltage, the typical value for design is 1.8V. After
+ the minor tuning, the final microvolt are as the below.
+
+ enum: [1800000, 2700000, 2880000, 3060000]
+
+ nuvoton,alc-enable:
+ description:
+ Enable digital automatic level control (ALC) function.
+ type: boolean
+
+ nuvoton,clock-detection-disable:
+ description:
+ When clock detection is enabled, it will detect whether MCLK
+ and FS are within the range. MCLK range is from 2.048MHz to 24.576MHz.
+ FS range is from 8kHz to 96kHz. And also needs to detect the ratio
+ MCLK_SRC/LRCK of 256, 400 or 500, and needs to detect the BCLK
+ to make sure data is present. There needs to be at least 8 BCLK
+ cycles per Frame Sync.
+ type: boolean
+
+ nuvoton,clock-det-data:
+ description:
+ Request clock detection to require 2048 non-zero samples before enabling
+ the audio paths. If set then non-zero samples is required, otherwise it
+ doesn't matter.
+ type: boolean
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ codec@21 {
+ compatible = "nuvoton,nau8325";
+ reg = <0x21>;
+ nuvoton,vref-impedance-ohms = <125000>;
+ nuvoton,dac-vref-microvolt = <2880000>;
+ nuvoton,alc-enable;
+ nuvoton,clock-det-data;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
new file mode 100644
index 000000000000..ecf3d7d968c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/rockchip,rk3308-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3308 Internal Codec
+
+description: |
+ This is the audio codec embedded in the Rockchip RK3308
+ SoC. It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
+ sampling rate is 192 kHz.
+
+ It is connected internally to one out of a selection of the internal I2S
+ controllers.
+
+ The RK3308 audio codec has 8 independent capture channels, but some
+ features work on stereo pairs called groups:
+ * grp 0 -- MIC1 / MIC2
+ * grp 1 -- MIC3 / MIC4
+ * grp 2 -- MIC5 / MIC6
+ * grp 3 -- MIC7 / MIC8
+
+maintainers:
+ - Luca Ceresoli <luca.ceresoli@bootlin.com>
+
+properties:
+ compatible:
+ const: rockchip,rk3308-codec
+
+ reg:
+ maxItems: 1
+
+ rockchip,grf:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to the General Register Files (GRF)
+
+ clocks:
+ items:
+ - description: clock for TX
+ - description: clock for RX
+ - description: AHB clock driving the interface
+
+ clock-names:
+ items:
+ - const: mclk_tx
+ - const: mclk_rx
+ - const: hclk
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ items:
+ - const: codec
+
+ "#sound-dai-cells":
+ const: 0
+
+ rockchip,micbias-avdd-percent:
+ description: |
+ Voltage setting for the MICBIAS pins expressed as a percentage of
+ AVDD.
+
+ E.g. if rockchip,micbias-avdd-percent = 85 and AVDD = 3v3, then the
+ MIC BIAS voltage will be 3.3 V * 85% = 2.805 V.
+
+ enum: [ 50, 55, 60, 65, 70, 75, 80, 85 ]
+
+required:
+ - compatible
+ - reg
+ - rockchip,grf
+ - clocks
+ - resets
+ - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/rk3308-cru.h>
+
+ audio_codec: audio-codec@ff560000 {
+ compatible = "rockchip,rk3308-codec";
+ reg = <0xff560000 0x10000>;
+ rockchip,grf = <&grf>;
+ clock-names = "mclk_tx", "mclk_rx", "hclk";
+ clocks = <&cru SCLK_I2S2_8CH_TX_OUT>,
+ <&cru SCLK_I2S2_8CH_RX_OUT>,
+ <&cru PCLK_ACODEC>;
+ reset-names = "codec";
+ resets = <&cru SRST_ACODEC_P>;
+ #sound-dai-cells = <0>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8776.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8776.yaml
new file mode 100644
index 000000000000..7bbc96ee81be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8776.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8776.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: WM8776 audio CODEC
+
+maintainers:
+ - patches@opensource.cirrus.com
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: wlf,wm8776
+
+ reg:
+ maxItems: 1
+
+ "#sound-dai-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec@1a {
+ compatible = "wlf,wm8776";
+ reg = <0x1a>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
deleted file mode 100644
index 01d3a7c83419..000000000000
--- a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-WM8974 audio CODEC
-
-This device supports both I2C and SPI (configured with pin strapping
-on the board).
-
-Required properties:
- - compatible: "wlf,wm8974"
- - reg: the I2C address or SPI chip select number of the device
-
-Examples:
-
-codec: wm8974@1a {
- compatible = "wlf,wm8974";
- reg = <0x1a>;
-};
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8974.yaml
new file mode 100644
index 000000000000..d27300207c67
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8974.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8974.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: WM8974 audio CODEC
+
+maintainers:
+ - patches@opensource.cirrus.com
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: wlf,wm8974
+
+ reg:
+ maxItems: 1
+
+ "#sound-dai-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec@1a {
+ compatible = "wlf,wm8974";
+ reg = <0x1a>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/wm8776.txt b/Documentation/devicetree/bindings/sound/wm8776.txt
deleted file mode 100644
index 01173369c3ed..000000000000
--- a/Documentation/devicetree/bindings/sound/wm8776.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-WM8776 audio CODEC
-
-This device supports both I2C and SPI (configured with pin strapping
-on the board).
-
-Required properties:
-
- - compatible : "wlf,wm8776"
-
- - reg : the I2C address of the device for I2C, the chip select
- number for SPI.
-
-Example:
-
-wm8776: codec@1a {
- compatible = "wlf,wm8776";
- reg = <0x1a>;
-};
diff --git a/MAINTAINERS b/MAINTAINERS
index aa3b947fb080..74ab768c0f6f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19046,6 +19046,13 @@ S: Maintained
F: Documentation/devicetree/bindings/media/rockchip-rga.yaml
F: drivers/media/platform/rockchip/rga/
+ROCKCHIP RK3308 INTERNAL AUDIO CODEC
+M: Luca Ceresoli <luca.ceresoli@bootlin.com>
+S: Maintained
+F: Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
+F: sound/soc/codecs/rk3308_codec.c
+F: sound/soc/codecs/rk3308_codec.h
+
ROCKCHIP VIDEO DECODER DRIVER
M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
L: linux-media@vger.kernel.org
diff --git a/include/sound/control.h b/include/sound/control.h
index 9a4f4f7138da..c1659036c4a7 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -167,6 +167,29 @@ snd_ctl_find_id_mixer(struct snd_card *card, const char *name)
return snd_ctl_find_id(card, &id);
}
+/**
+ * snd_ctl_find_id_mixer_locked - find the control instance with the given name string
+ * @card: the card instance
+ * @name: the name string
+ *
+ * Finds the control instance with the given name and
+ * @SNDRV_CTL_ELEM_IFACE_MIXER. Other fields are set to zero.
+ *
+ * This is merely a wrapper to snd_ctl_find_id_locked().
+ * The caller must down card->controls_rwsem before calling this function.
+ *
+ * Return: The pointer of the instance if found, or %NULL if not.
+ */
+static inline struct snd_kcontrol *
+snd_ctl_find_id_mixer_locked(struct snd_card *card, const char *name)
+{
+ struct snd_ctl_elem_id id = {};
+
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ strscpy(id.name, name, sizeof(id.name));
+ return snd_ctl_find_id_locked(card, &id);
+}
+
int snd_ctl_create(struct snd_card *card);
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index d70c55f17df7..c11aaf8079fb 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -118,6 +118,7 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
* which do not use devicetree.
* @process: Callback used to apply processing on samples transferred from/to
* user space.
+ * @name: Component name. If null, dev_name will be used.
* @compat_filter_fn: Will be used as the filter function when requesting a
* channel for platforms which do not use devicetree. The filter parameter
* will be the DAI's DMA data.
@@ -143,6 +144,7 @@ struct snd_dmaengine_pcm_config {
int (*process)(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
unsigned long bytes);
+ const char *name;
dma_filter_fn compat_filter_fn;
struct device *dma_dev;
const char *chan_names[SNDRV_PCM_STREAM_LAST + 1];
diff --git a/sound/soc/intel/boards/sof_ssp_common.h b/include/sound/soc-acpi-intel-ssp-common.h
index d24888bc99fd..b4597c8dac78 100644
--- a/sound/soc/intel/boards/sof_ssp_common.h
+++ b/include/sound/soc-acpi-intel-ssp-common.h
@@ -3,8 +3,8 @@
* Copyright(c) 2023 Intel Corporation.
*/
-#ifndef __SOF_SSP_COMMON_H
-#define __SOF_SSP_COMMON_H
+#ifndef __LINUX_SND_SOC_ACPI_INTEL_SSP_COMMON_H
+#define __LINUX_SND_SOC_ACPI_INTEL_SSP_COMMON_H
/* Cirrus Logic */
#define CS35L41_ACPI_HID "CSC3541"
@@ -37,7 +37,7 @@
#define RT5682_ACPI_HID "10EC5682"
#define RT5682S_ACPI_HID "RTL5682"
-enum sof_ssp_codec {
+enum snd_soc_acpi_intel_codec {
CODEC_NONE,
/* headphone codec */
@@ -65,16 +65,17 @@ enum sof_ssp_codec {
CODEC_RT1308,
};
-enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev);
-enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev);
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_codec_type(struct device *dev);
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_amp_type(struct device *dev);
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON)
-const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type);
-#else
-static inline const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type)
-{
- return NULL;
-}
-#endif
+const char *
+snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type);
-#endif /* __SOF_SSP_COMMON_H */
+const char *
+snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type);
+const char *
+snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type);
+
+#endif /* __LINUX_SND_SOC_ACPI_INTEL_SSP_COMMON_H */
diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index 23d6d6bfb073..1d8f35ca1d6f 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -151,6 +151,18 @@ struct snd_soc_acpi_link_adr {
*/
#define SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER BIT(2)
+/*
+ * when set the speaker amplifier name suffix (i.e. "-max98360a") will be
+ * appended to topology file name
+ */
+#define SND_SOC_ACPI_TPLG_INTEL_AMP_NAME BIT(3)
+
+/*
+ * when set the headphone codec name suffix (i.e. "-rt5682") will be appended to
+ * topology file name
+ */
+#define SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME BIT(4)
+
/**
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
* related to the hardware, except for the firmware and topology file names.
diff --git a/include/sound/soc-jack.h b/include/sound/soc-jack.h
index a0abb1ee5110..3a81d4b8ca8a 100644
--- a/include/sound/soc-jack.h
+++ b/include/sound/soc-jack.h
@@ -44,7 +44,6 @@ struct snd_soc_jack_zone {
/**
* struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
*
- * @gpio: legacy gpio number
* @idx: gpio descriptor index within the function of the GPIO
* consumer device
* @gpiod_dev: GPIO consumer device
@@ -59,7 +58,6 @@ struct snd_soc_jack_zone {
* ADC).
*/
struct snd_soc_jack_gpio {
- unsigned int gpio;
unsigned int idx;
struct device *gpiod_dev;
const char *name;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 39613b406b1d..0376f7e4c15d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -149,6 +149,18 @@
{.reg = xreg, .rreg = xreg, \
.shift = shift_left, .rshift = shift_right, \
.max = xmax, .min = xmin} }
+#define SOC_DOUBLE_RANGE_TLV(xname, xreg, xshift_left, xshift_right, xmin, xmax, \
+ xinvert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .rreg = xreg, \
+ .shift = xshift_left, .rshift = xshift_right, \
+ .min = xmin, .max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 439fa631c342..a52afb423b46 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -66,6 +66,14 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST
userspace applications such as pulseaudio, to prevent unnecessary
problems.
+config SND_SOC_CARD_KUNIT_TEST
+ tristate "KUnit tests for SoC card"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ If you want to perform tests on ALSA SoC card functions say Y here.
+ If unsure, say N.
+
config SND_SOC_UTILS_KUNIT_TEST
tristate "KUnit tests for SoC utils"
depends on KUNIT
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8376fdb217ed..f90f5300b36e 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,6 +12,10 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o
endif
+ifneq ($(CONFIG_SND_SOC_CARD_KUNIT_TEST),)
+obj-$(CONFIG_SND_SOC_CARD_KUNIT_TEST) += soc-card-test.o
+endif
+
ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
# snd-soc-test-objs := soc-utils-test.o
obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index fa74635cee08..3508f5a96b75 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -134,15 +134,14 @@ config SND_SOC_AMD_RPL_ACP6x
config SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
tristate
- select SOUNDWIRE_AMD if SND_SOC_AMD_SOUNDWIRE != n
select SND_AMD_SOUNDWIRE_ACPI if ACPI
config SND_SOC_AMD_SOUNDWIRE
tristate "Support for SoundWire based AMD platforms"
default SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
depends on SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
- depends on ACPI && SOUNDWIRE
- depends on !(SOUNDWIRE=m && SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=y)
+ depends on ACPI
+ depends on SOUNDWIRE_AMD
help
This adds support for SoundWire for AMD platforms.
Say Y if you want to enable SoundWire links with SOF.
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f78ea2f86fa6..1752814fffdd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -180,6 +180,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_PCM512x_I2C
imply SND_SOC_PCM512x_SPI
imply SND_SOC_PEB2466
+ imply SND_SOC_RK3308
imply SND_SOC_RK3328
imply SND_SOC_RK817
imply SND_SOC_RT274
@@ -1433,6 +1434,16 @@ config SND_SOC_PEB2466
To compile this driver as a module, choose M here: the module
will be called snd-soc-peb2466.
+config SND_SOC_RK3308
+ tristate "Rockchip RK3308 audio CODEC"
+ select REGMAP_MMIO
+ help
+ This is a device driver for the audio codec embedded in the
+ Rockchip RK3308 SoC.
+
+ It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
+ sampling rate is 192 kHz.
+
config SND_SOC_RK3328
tristate "Rockchip RK3328 audio CODEC"
select REGMAP_MMIO
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7c075539dc47..9ba24fb870b1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -205,6 +205,7 @@ snd-soc-pcm512x-objs := pcm512x.o
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-peb2466-objs := peb2466.o
+snd-soc-rk3308-objs := rk3308_codec.o
snd-soc-rk3328-objs := rk3328_codec.o
snd-soc-rk817-objs := rk817_codec.o
snd-soc-rl6231-objs := rl6231.o
@@ -595,6 +596,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_PEB2466) += snd-soc-peb2466.o
+obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 17bd6b516077..93385f181d2c 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -292,11 +292,6 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
- 4, 7, 0, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
- 0, 7, 0, 0),
-
SND_SOC_DAPM_OUTPUT("HPOL"),
SND_SOC_DAPM_OUTPUT("HPOR"),
};
@@ -316,9 +311,6 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
{"LHPMIX", NULL, "Left DAC"},
{"RHPMIX", NULL, "Right DAC"},
- {"HPOR", NULL, "HPOR Supply"},
- {"HPOL", NULL, "HPOL Supply"},
-
{"HPOL", NULL, "LHPMIX"},
{"HPOR", NULL, "RHPMIX"},
};
@@ -1077,12 +1069,13 @@ static int es8326_suspend(struct snd_soc_component *component)
regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
regcache_cache_only(es8326->regmap, true);
- regcache_mark_dirty(es8326->regmap);
/* reset register value to default */
regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
usleep_range(1000, 3000);
regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
+
+ regcache_mark_dirty(es8326->regmap);
return 0;
}
@@ -1168,8 +1161,13 @@ static int es8326_set_jack(struct snd_soc_component *component,
static void es8326_remove(struct snd_soc_component *component)
{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
es8326_disable_jack_detect(component);
es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
}
static const struct snd_soc_component_driver soc_component_dev_es8326 = {
@@ -1241,6 +1239,29 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
&es8326_dai, 1);
}
+
+static void es8326_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct snd_soc_component *component;
+ struct es8326_priv *es8326;
+
+ es8326 = i2c_get_clientdata(i2c);
+ component = es8326->component;
+ dev_dbg(component->dev, "Enter into %s\n", __func__);
+ cancel_delayed_work_sync(&es8326->jack_detect_work);
+ cancel_delayed_work_sync(&es8326->button_press_work);
+
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
+
+}
+
+static void es8326_i2c_remove(struct i2c_client *i2c)
+{
+ es8326_i2c_shutdown(i2c);
+}
+
static const struct i2c_device_id es8326_i2c_id[] = {
{"es8326", 0 },
{}
@@ -1270,6 +1291,8 @@ static struct i2c_driver es8326_i2c_driver = {
.of_match_table = of_match_ptr(es8326_of_match),
},
.probe = es8326_i2c_probe,
+ .shutdown = es8326_i2c_shutdown,
+ .remove = es8326_i2c_remove,
.id_table = es8326_i2c_id,
};
module_i2c_driver(es8326_i2c_driver);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 6aa3223985be..29c88de5508b 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -230,7 +230,8 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream,
format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
if (!format_val) {
dev_err(dai->dev,
- "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n",
+ "%s: invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n",
+ __func__,
params_rate(params), params_channels(params),
params_format(params), maxbps);
@@ -266,14 +267,12 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct hda_pcm_stream *hda_stream;
struct hdac_hda_priv *hda_pvt;
- struct hdac_device *hdev;
unsigned int format_val;
struct hda_pcm *pcm;
unsigned int stream;
int ret = 0;
hda_pvt = snd_soc_component_get_drvdata(component);
- hdev = &hda_pvt->codec->core;
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
@@ -286,7 +285,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
ret = snd_hda_codec_prepare(hda_pvt->codec, hda_stream,
stream, format_val, substream);
if (ret < 0)
- dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
+ dev_err(dai->dev, "%s: failed %d\n", __func__, ret);
return ret;
}
@@ -298,6 +297,7 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
struct hdac_hda_priv *hda_pvt;
struct hda_pcm_stream *hda_stream;
struct hda_pcm *pcm;
+ int ret;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
@@ -308,7 +308,11 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
hda_stream = &pcm->stream[substream->stream];
- return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream);
+ ret = hda_stream->ops.open(hda_stream, hda_pvt->codec, substream);
+ if (ret < 0)
+ dev_err(dai->dev, "%s: failed %d\n", __func__, ret);
+
+ return ret;
}
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
@@ -367,7 +371,7 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
pcm_name = "HDMI 3";
break;
default:
- dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
+ dev_err(dai->dev, "%s: invalid dai id %d\n", __func__, dai->id);
return NULL;
}
@@ -381,7 +385,7 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
}
}
- dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
+ dev_err(dai->dev, "%s: didn't find PCM for DAI %s\n", __func__, dai->name);
return NULL;
}
@@ -411,7 +415,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return -EIO;
}
@@ -429,7 +433,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
hdev->addr, hcodec, true);
if (ret < 0) {
- dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
+ dev_err(&hdev->dev, "%s: failed to create hda codec %d\n", __func__, ret);
goto error_no_pm;
}
@@ -446,7 +450,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
if (fw) {
ret = snd_hda_load_patch(hcodec->bus, fw->size, fw->data);
if (ret < 0) {
- dev_err(&hdev->dev, "failed to load hda patch %d\n", ret);
+ dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret);
goto error_no_pm;
}
release_firmware(fw);
@@ -470,13 +474,13 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
if (ret < 0) {
- dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
+ dev_err(&hdev->dev, "%s: name failed %s\n", __func__, hcodec->preset->name);
goto error_pm;
}
ret = snd_hdac_regmap_init(&hcodec->core);
if (ret < 0) {
- dev_err(&hdev->dev, "regmap init failed\n");
+ dev_err(&hdev->dev, "%s: regmap init failed\n", __func__);
goto error_pm;
}
@@ -484,16 +488,16 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
if (patch) {
ret = patch(hcodec);
if (ret < 0) {
- dev_err(&hdev->dev, "patch failed %d\n", ret);
+ dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
goto error_regmap;
}
} else {
- dev_dbg(&hdev->dev, "no patch file found\n");
+ dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
}
ret = snd_hda_codec_parse_pcms(hcodec);
if (ret < 0) {
- dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+ dev_err(&hdev->dev, "%s: unable to map pcms to dai %d\n", __func__, ret);
goto error_patch;
}
@@ -501,8 +505,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
if (!is_hdmi_codec(hcodec)) {
ret = snd_hda_codec_build_controls(hcodec);
if (ret < 0) {
- dev_err(&hdev->dev, "unable to create controls %d\n",
- ret);
+ dev_err(&hdev->dev, "%s: unable to create controls %d\n",
+ __func__, ret);
goto error_patch;
}
}
@@ -548,7 +552,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return;
}
@@ -624,7 +628,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
@@ -640,7 +644,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
ARRAY_SIZE(hdac_hda_dais));
if (ret < 0) {
- dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
+ dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
return ret;
}
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 383e551f3bc7..26860882fd91 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -872,7 +872,6 @@ MODULE_DEVICE_TABLE(sdw, max98373_id);
static struct sdw_driver max98373_sdw_driver = {
.driver = {
.name = "max98373",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(max98373_of_match),
.acpi_match_table = ACPI_PTR(max98373_acpi_match),
.pm = &max98373_pm,
diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c
new file mode 100644
index 000000000000..d65f73144597
--- /dev/null
+++ b/sound/soc/codecs/nau8325.c
@@ -0,0 +1,900 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// nau8325.c -- Nuvoton NAU8325 audio codec driver
+//
+// Copyright 2023 Nuvoton Technology Crop.
+// Author: Seven Lee <WTLI@nuvoton.com>
+// David Lin <CTLIN0@nuvoton.com>
+//
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "nau8325.h"
+
+/* Range of Master Clock MCLK (Hz) */
+#define MASTER_CLK_MAX 49152000
+#define MASTER_CLK_MIN 2048000
+
+/* scaling for MCLK source */
+#define CLK_PROC_BYPASS (-1)
+
+/* the maximum CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
+
+/* from MCLK input */
+#define MCLK_SRC 4
+
+static const struct nau8325_src_attr mclk_n1_div[] = {
+ { 1, 0x0 },
+ { 2, 0x1 },
+ { 3, 0x2 },
+};
+
+/* over sampling rate */
+static const struct nau8325_osr_attr osr_dac_sel[] = {
+ { 64, 2 }, /* OSR 64, SRC 1/4 */
+ { 256, 0 }, /* OSR 256, SRC 1 */
+ { 128, 1 }, /* OSR 128, SRC 1/2 */
+ { 0, 0 },
+ { 32, 3 }, /* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8325_src_attr mclk_n2_div[] = {
+ { 0, 0x0 },
+ { 1, 0x1 },
+ { 2, 0x2 },
+ { 3, 0x3 },
+ { 4, 0x4 },
+};
+
+static const struct nau8325_src_attr mclk_n3_mult[] = {
+ { 0, 0x1 },
+ { 1, 0x2 },
+ { 2, 0x3 },
+ { 3, 0x4 },
+};
+
+/* Sample Rate and MCLK_SRC selections */
+static const struct nau8325_srate_attr target_srate_table[] = {
+ /* { FS, range, max, { MCLK source }} */
+ { 48000, 2, true, { 12288000, 19200000, 24000000 } },
+ { 16000, 1, false, { 4096000, 6400000, 8000000 } },
+ { 8000, 0, false, { 2048000, 3200000, 4000000 }},
+ { 44100, 2, true, { 11289600, 17640000, 22050000 }},
+ { 64000, 3, false, { 16384000, 25600000, 32000000 } },
+ { 96000, 3, true, { 24576000, 38400000, 48000000 } },
+ { 12000, 0, true, { 3072000, 4800000, 6000000 } },
+ { 24000, 1, true, { 6144000, 9600000, 12000000 } },
+ { 32000, 2, false, { 8192000, 12800000, 16000000 } },
+};
+
+static const struct reg_default nau8325_reg_defaults[] = {
+ { NAU8325_R00_HARDWARE_RST, 0x0000 },
+ { NAU8325_R01_SOFTWARE_RST, 0x0000 },
+ { NAU8325_R03_CLK_CTRL, 0x0000 },
+ { NAU8325_R04_ENA_CTRL, 0x0000 },
+ { NAU8325_R05_INTERRUPT_CTRL, 0x007f },
+ { NAU8325_R09_IRQOUT, 0x0000 },
+ { NAU8325_R0A_IO_CTRL, 0x0000 },
+ { NAU8325_R0B_PDM_CTRL, 0x0000 },
+ { NAU8325_R0C_TDM_CTRL, 0x0000 },
+ { NAU8325_R0D_I2S_PCM_CTRL1, 0x000a },
+ { NAU8325_R0E_I2S_PCM_CTRL2, 0x0000 },
+ { NAU8325_R0F_L_TIME_SLOT, 0x0000 },
+ { NAU8325_R10_R_TIME_SLOT, 0x0000 },
+ { NAU8325_R11_HPF_CTRL, 0x0000 },
+ { NAU8325_R12_MUTE_CTRL, 0x0000 },
+ { NAU8325_R13_DAC_VOLUME, 0xf3f3 },
+ { NAU8325_R29_DAC_CTRL1, 0x0081 },
+ { NAU8325_R2A_DAC_CTRL2, 0x0000 },
+ { NAU8325_R2C_ALC_CTRL1, 0x000e },
+ { NAU8325_R2D_ALC_CTRL2, 0x8400 },
+ { NAU8325_R2E_ALC_CTRL3, 0x0000 },
+ { NAU8325_R2F_ALC_CTRL4, 0x003f },
+ { NAU8325_R40_CLK_DET_CTRL, 0xa801 },
+ { NAU8325_R50_MIXER_CTRL, 0x0000 },
+ { NAU8325_R55_MISC_CTRL, 0x0000 },
+ { NAU8325_R60_BIAS_ADJ, 0x0000 },
+ { NAU8325_R61_ANALOG_CONTROL_1, 0x0000 },
+ { NAU8325_R62_ANALOG_CONTROL_2, 0x0000 },
+ { NAU8325_R63_ANALOG_CONTROL_3, 0x0000 },
+ { NAU8325_R64_ANALOG_CONTROL_4, 0x0000 },
+ { NAU8325_R65_ANALOG_CONTROL_5, 0x0000 },
+ { NAU8325_R66_ANALOG_CONTROL_6, 0x0000 },
+ { NAU8325_R69_CLIP_CTRL, 0x0000 },
+ { NAU8325_R73_RDAC, 0x0008 },
+};
+
+static bool nau8325_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R02_DEVICE_ID ... NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME:
+ case NAU8325_R1D_DEBUG_READ1:
+ case NAU8325_R1F_DEBUG_READ2:
+ case NAU8325_R22_DEBUG_READ3:
+ case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2:
+ case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4:
+ case NAU8325_R40_CLK_DET_CTRL:
+ case NAU8325_R49_TEST_STATUS ... NAU8325_R4A_ANALOG_READ:
+ case NAU8325_R50_MIXER_CTRL:
+ case NAU8325_R55_MISC_CTRL:
+ case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6:
+ case NAU8325_R69_CLIP_CTRL:
+ case NAU8325_R73_RDAC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8325_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R00_HARDWARE_RST:
+ case NAU8325_R03_CLK_CTRL ... NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME:
+ case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2:
+ case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4:
+ case NAU8325_R40_CLK_DET_CTRL:
+ case NAU8325_R50_MIXER_CTRL:
+ case NAU8325_R55_MISC_CTRL:
+ case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6:
+ case NAU8325_R69_CLIP_CTRL:
+ case NAU8325_R73_RDAC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8325_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R00_HARDWARE_RST ... NAU8325_R02_DEVICE_ID:
+ case NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R1D_DEBUG_READ1:
+ case NAU8325_R1F_DEBUG_READ2:
+ case NAU8325_R22_DEBUG_READ3:
+ case NAU8325_R4A_ANALOG_READ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const nau8325_dac_oversampl_texts[] = {
+ "64", "256", "128", "32",
+};
+
+static const unsigned int nau8325_dac_oversampl_values[] = {
+ 0, 1, 2, 4,
+};
+
+static const struct soc_enum nau8325_dac_oversampl_enum =
+ SOC_VALUE_ENUM_SINGLE(NAU8325_R29_DAC_CTRL1,
+ NAU8325_DAC_OVERSAMPLE_SFT, 0x7,
+ ARRAY_SIZE(nau8325_dac_oversampl_texts),
+ nau8325_dac_oversampl_texts,
+ nau8325_dac_oversampl_values);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(dac_vol_tlv, -8000, 600);
+
+static const struct snd_kcontrol_new nau8325_snd_controls[] = {
+ SOC_ENUM("DAC Oversampling Rate", nau8325_dac_oversampl_enum),
+ SOC_DOUBLE_TLV("Speaker Volume", NAU8325_R13_DAC_VOLUME,
+ NAU8325_DAC_VOLUME_L_SFT, NAU8325_DAC_VOLUME_R_SFT,
+ NAU8325_DAC_VOLUME_R_EN, 0, dac_vol_tlv),
+ SOC_SINGLE("ALC Max Gain", NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MAXGAIN_SFT, NAU8325_ALC_MAXGAIN_MAX, 0),
+ SOC_SINGLE("ALC Min Gain", NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MINGAIN_SFT, NAU8325_ALC_MINGAIN_MAX, 0),
+ SOC_SINGLE("ALC Decay Timer", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_DCY_SFT, NAU8325_ALC_DCY_MAX, 0),
+ SOC_SINGLE("ALC Attack Timer", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_ATK_SFT, NAU8325_ALC_ATK_MAX, 0),
+ SOC_SINGLE("ALC Hold Time", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_HLD_SFT, NAU8325_ALC_HLD_MAX, 0),
+ SOC_SINGLE("ALC Target Level", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_LVL_SFT, NAU8325_ALC_LVL_MAX, 0),
+ SOC_SINGLE("ALC Enable Switch", NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN_SFT, 1, 0),
+};
+
+static int nau8325_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8325->regmap, NAU8325_R12_MUTE_CTRL,
+ NAU8325_SOFT_MUTE, 0);
+ msleep(30);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Soft mute the output to prevent the pop noise. */
+ regmap_update_bits(nau8325->regmap, NAU8325_R12_MUTE_CTRL,
+ NAU8325_SOFT_MUTE, NAU8325_SOFT_MUTE);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8325_powerup_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ if (nau8325->clock_detection)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_PWRUP_DFT, NAU8325_PWRUP_DFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_PWRUP_DFT, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8325_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Power Up", SND_SOC_NOPM, 0, 0,
+ nau8325_powerup_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DACL", NULL, NAU8325_R04_ENA_CTRL,
+ NAU8325_DAC_LEFT_CH_EN_SFT, 0, nau8325_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("DACR", NULL, NAU8325_R04_ENA_CTRL,
+ NAU8325_DAC_RIGHT_CH_EN_SFT, 0, nau8325_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("AIFRX", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+};
+
+static const struct snd_soc_dapm_route nau8325_dapm_routes[] = {
+ { "DACL", NULL, "Power Up" },
+ { "DACR", NULL, "Power Up" },
+
+ { "DACL", NULL, "AIFRX" },
+ { "DACR", NULL, "AIFRX" },
+ { "SPKL", NULL, "DACL" },
+ { "SPKR", NULL, "DACR" },
+};
+
+static int nau8325_srate_clk_apply(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr *srate_table,
+ int n1_sel, int mclk_mult_sel, int n2_sel)
+{
+ if (!srate_table || n2_sel < 0 || n2_sel >= ARRAY_SIZE(mclk_n2_div) ||
+ n1_sel < 0 || n1_sel >= ARRAY_SIZE(mclk_n1_div)) {
+ dev_dbg(nau8325->dev, "The CLK isn't supported.");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_REG_SRATE_MASK | NAU8325_REG_DIV_MAX,
+ (srate_table->range << NAU8325_REG_SRATE_SFT) |
+ (srate_table->max ? NAU8325_REG_DIV_MAX : 0));
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SRC_MASK, mclk_n2_div[n2_sel].val);
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_CLK_MUL_SRC_MASK,
+ mclk_n1_div[n1_sel].val << NAU8325_CLK_MUL_SRC_SFT);
+
+ if (mclk_mult_sel != CLK_PROC_BYPASS) {
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SEL_MASK,
+ mclk_n3_mult[mclk_mult_sel].val <<
+ NAU8325_MCLK_SEL_SFT);
+ } else {
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SEL_MASK, 0);
+ }
+
+ switch (mclk_mult_sel) {
+ case 2:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN, NAU8325_MCLK4XEN_EN);
+ break;
+ case 3:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN);
+ break;
+ default:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static int nau8325_clksrc_n2(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr *srate_table,
+ int mclk, int *n2_sel)
+{
+ int i, mclk_src, ratio;
+
+ ratio = NAU8325_MCLK_FS_RATIO_NUM;
+ for (i = 0; i < ARRAY_SIZE(mclk_n2_div); i++) {
+ mclk_src = mclk >> mclk_n2_div[i].param;
+ if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_256] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_256;
+ break;
+ } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_400] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_400;
+ break;
+ } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_500] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_500;
+ break;
+ }
+ }
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM)
+ *n2_sel = i;
+
+ return ratio;
+}
+
+static const struct nau8325_srate_attr *target_srate_attribute(int srate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(target_srate_table); i++)
+ if (target_srate_table[i].fs == srate)
+ break;
+
+ if (i == ARRAY_SIZE(target_srate_table))
+ goto proc_err;
+
+ return &target_srate_table[i];
+
+proc_err:
+ return NULL;
+}
+
+static int nau8325_clksrc_choose(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr **srate_table,
+ int *n1_sel, int *mult_sel, int *n2_sel)
+{
+ int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max;
+
+ if (!nau8325->mclk || !nau8325->fs)
+ goto proc_err;
+
+ /* select sampling rate and MCLK_SRC */
+ *srate_table = target_srate_attribute(nau8325->fs);
+ if (!*srate_table)
+ goto proc_err;
+
+ /* First check clock from MCLK directly, decide N2 for MCLK_SRC.
+ * If not good, consider 1/N1 and Multiplier.
+ */
+ ratio = nau8325_clksrc_n2(nau8325, *srate_table, nau8325->mclk, n2_sel);
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM) {
+ *n1_sel = 0;
+ *mult_sel = CLK_PROC_BYPASS;
+ *n2_sel = MCLK_SRC;
+ goto proc_done;
+ }
+
+ /* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */
+ mclk_max = 0;
+ for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) {
+ for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) {
+ mclk = nau8325->mclk << mclk_n3_mult[j].param;
+ mclk = mclk / mclk_n1_div[i].param;
+ ratio = nau8325_clksrc_n2(nau8325,
+ *srate_table, mclk, n2_sel);
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM &&
+ (mclk_max < mclk || i > *n1_sel)) {
+ mclk_max = mclk;
+ n2_max = *n2_sel;
+ *n1_sel = i;
+ *mult_sel = j;
+ ratio_sel = ratio;
+ goto proc_done;
+ }
+ }
+ }
+ if (mclk_max) {
+ *n2_sel = n2_max;
+ ratio = ratio_sel;
+ goto proc_done;
+ }
+
+proc_err:
+ dev_dbg(nau8325->dev, "The MCLK %d is invalid. It can't get MCLK_SRC of 256/400/500 FS (%d)",
+ nau8325->mclk, nau8325->fs);
+ return -EINVAL;
+proc_done:
+ dev_dbg(nau8325->dev, "nau8325->fs=%d,range=0x%x, %s, (n1,mu,n2,dmu):(%d,%d,%d), MCLK_SRC=%uHz (%d)",
+ nau8325->fs, (*srate_table)->range,
+ (*srate_table)->max ? "MAX" : "MIN",
+ *n1_sel == CLK_PROC_BYPASS ?
+ CLK_PROC_BYPASS : mclk_n1_div[*n1_sel].param,
+ *mult_sel == CLK_PROC_BYPASS ?
+ CLK_PROC_BYPASS : 1 << mclk_n3_mult[*mult_sel].param,
+ 1 << mclk_n2_div[*n2_sel].param,
+ (*srate_table)->mclk_src[ratio],
+ (*srate_table)->mclk_src[ratio] / nau8325->fs);
+
+ return 0;
+}
+
+static int nau8325_clock_config(struct nau8325 *nau8325)
+{
+ const struct nau8325_srate_attr *srate_table;
+ int ret, n1_sel, mult_sel, n2_sel;
+
+ ret = nau8325_clksrc_choose(nau8325, &srate_table,
+ &n1_sel, &mult_sel, &n2_sel);
+ if (ret)
+ goto err;
+
+ ret = nau8325_srate_clk_apply(nau8325, srate_table,
+ n1_sel, mult_sel, n2_sel);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct nau8325_osr_attr *nau8325_get_osr(struct nau8325 *nau8325)
+{
+ unsigned int osr;
+
+ regmap_read(nau8325->regmap, NAU8325_R29_DAC_CTRL1, &osr);
+ osr &= NAU8325_DAC_OVERSAMPLE_MASK;
+ if (osr >= ARRAY_SIZE(osr_dac_sel))
+ return NULL;
+
+ return &osr_dac_sel[osr];
+}
+
+static int nau8325_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ const struct nau8325_osr_attr *osr;
+
+ osr = nau8325_get_osr(nau8325);
+ if (!osr || !osr->osr)
+ return -EINVAL;
+
+ return snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 0, CLK_DA_AD_MAX / osr->osr);
+}
+
+static int nau8325_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 nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ unsigned int val_len = 0;
+ const struct nau8325_osr_attr *osr;
+ int ret;
+
+ nau8325->fs = params_rate(params);
+ osr = nau8325_get_osr(nau8325);
+ if (!osr || !osr->osr || nau8325->fs * osr->osr > CLK_DA_AD_MAX) {
+ ret = -EINVAL;
+ goto err;
+ }
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_CLK_DAC_SRC_MASK,
+ osr->clk_src << NAU8325_CLK_DAC_SRC_SFT);
+
+ ret = nau8325_clock_config(nau8325);
+ if (ret)
+ goto err;
+
+ switch (params_width(params)) {
+ case 16:
+ val_len |= NAU8325_I2S_DL_16;
+ break;
+ case 20:
+ val_len |= NAU8325_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= NAU8325_I2S_DL_24;
+ break;
+ case 32:
+ val_len |= NAU8325_I2S_DL_32;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1,
+ NAU8325_I2S_DL_MASK, val_len);
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static int nau8325_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ unsigned int ctrl1_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl1_val |= NAU8325_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl1_val |= NAU8325_I2S_DF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl1_val |= NAU8325_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl1_val |= NAU8325_I2S_DF_RIGTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1_val |= NAU8325_I2S_DF_PCM_AB;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1_val |= NAU8325_I2S_DF_PCM_AB;
+ ctrl1_val |= NAU8325_I2S_PCMB_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1,
+ NAU8325_I2S_DF_MASK | NAU8325_I2S_BP_MASK |
+ NAU8325_I2S_PCMB_EN, ctrl1_val);
+
+ return 0;
+}
+
+static int nau8325_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ if (freq < MASTER_CLK_MIN || freq > MASTER_CLK_MAX) {
+ dev_dbg(nau8325->dev, "MCLK exceeds the range, MCLK:%d", freq);
+ return -EINVAL;
+ }
+
+ nau8325->mclk = freq;
+ dev_dbg(nau8325->dev, "MCLK %dHz", nau8325->mclk);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver nau8325_component_driver = {
+ .set_sysclk = nau8325_set_sysclk,
+ .suspend_bias_off = true,
+ .controls = nau8325_snd_controls,
+ .num_controls = ARRAY_SIZE(nau8325_snd_controls),
+ .dapm_widgets = nau8325_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(nau8325_dapm_widgets),
+ .dapm_routes = nau8325_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(nau8325_dapm_routes),
+};
+
+static const struct snd_soc_dai_ops nau8325_dai_ops = {
+ .startup = nau8325_dai_startup,
+ .hw_params = nau8325_hw_params,
+ .set_fmt = nau8325_set_fmt,
+};
+
+#define NAU8325_RATES SNDRV_PCM_RATE_8000_96000
+#define NAU8325_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver nau8325_dai = {
+ .name = NAU8325_CODEC_DAI,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NAU8325_RATES,
+ .formats = NAU8325_FORMATS,
+ },
+ .ops = &nau8325_dai_ops,
+};
+
+static const struct regmap_config nau8325_regmap_config = {
+ .reg_bits = NAU8325_REG_ADDR_LEN,
+ .val_bits = NAU8325_REG_DATA_LEN,
+
+ .max_register = NAU8325_REG_MAX,
+ .readable_reg = nau8325_readable_reg,
+ .writeable_reg = nau8325_writeable_reg,
+ .volatile_reg = nau8325_volatile_reg,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = nau8325_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(nau8325_reg_defaults),
+};
+
+static void nau8325_reset_chip(struct regmap *regmap)
+{
+ regmap_write(regmap, NAU8325_R00_HARDWARE_RST, 0x0001);
+ regmap_write(regmap, NAU8325_R00_HARDWARE_RST, 0x0000);
+}
+
+static void nau8325_init_regs(struct nau8325 *nau8325)
+{
+ struct regmap *regmap = nau8325->regmap;
+ struct device *dev = nau8325->dev;
+
+ /* set ALC parameters */
+ regmap_update_bits(regmap, NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MAXGAIN_MASK,
+ 0x7 << NAU8325_ALC_MAXGAIN_SFT);
+ regmap_update_bits(regmap, NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_DCY_MASK | NAU8325_ALC_ATK_MASK |
+ NAU8325_ALC_HLD_MASK, (0x5 << NAU8325_ALC_DCY_SFT) |
+ (0x3 << NAU8325_ALC_ATK_SFT) |
+ (0x5 << NAU8325_ALC_HLD_SFT));
+ /* Enable ALC to avoid signal distortion when battery low. */
+ if (nau8325->alc_enable)
+ regmap_update_bits(regmap, NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN, NAU8325_ALC_EN);
+ if (nau8325->clock_detection)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS |
+ NAU8325_PWRUP_DFT, 0);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT,
+ NAU8325_CLKPWRUP_DIS);
+ if (nau8325->clock_det_data)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, NAU8325_APWRUP_EN);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, 0);
+
+ /* DAC Reference Voltage Setting */
+ switch (nau8325->dac_vref_microvolt) {
+ case 1800000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 0 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 2700000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 1 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 2880000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 2 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 3060000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 3 << NAU8325_DACVREFSEL_SFT);
+ break;
+ default:
+ dev_dbg(dev, "Invalid dac-vref-microvolt %d", nau8325->dac_vref_microvolt);
+
+ }
+
+ /* DAC Reference Voltage Decoupling Capacitors. */
+ regmap_update_bits(regmap, NAU8325_R63_ANALOG_CONTROL_3,
+ NAU8325_CLASSD_COARSE_GAIN_MASK, 0x4);
+ /* Auto-Att Min Gain 0dB, Class-D N Driver Slew Rate -25%. */
+ regmap_update_bits(regmap, NAU8325_R64_ANALOG_CONTROL_4,
+ NAU8325_CLASSD_SLEWN_MASK, 0x7);
+
+ /* VMID Tieoff (VMID Resistor Selection) */
+ switch (nau8325->vref_impedance_ohms) {
+ case 0:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 0 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 25000:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 1 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 125000:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 2 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 2500:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 3 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ default:
+ dev_dbg(dev, "Invalid vref-impedance-ohms %d", nau8325->vref_impedance_ohms);
+ }
+
+
+ /* enable VMID, BIAS, DAC, DCA CLOCK, Voltage/Current Amps
+ */
+ regmap_update_bits(regmap, NAU8325_R61_ANALOG_CONTROL_1,
+ NAU8325_DACEN_MASK | NAU8325_DACCLKEN_MASK |
+ NAU8325_DACEN_R_MASK | NAU8325_DACCLKEN_R_MASK |
+ NAU8325_CLASSDEN_MASK | NAU8325_VMDFSTENB_MASK |
+ NAU8325_BIASEN_MASK | NAU8325_VMIDEN_MASK,
+ (0x1 << NAU8325_DACEN_SFT) |
+ (0x1 << NAU8325_DACCLKEN_SFT) |
+ (0x1 << NAU8325_DACEN_R_SFT) |
+ (0x1 << NAU8325_DACCLKEN_R_SFT) |
+ (0x1 << NAU8325_CLASSDEN_SFT) |
+ (0x1 << NAU8325_VMDFSTENB_SFT) |
+ (0x1 << NAU8325_BIASEN_SFT) | 0x3);
+
+ /* Enable ALC to avoid signal distortion when battery low. */
+ if (nau8325->alc_enable)
+ regmap_update_bits(regmap, NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN, NAU8325_ALC_EN);
+ if (nau8325->clock_det_data)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, NAU8325_APWRUP_EN);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, 0);
+ if (nau8325->clock_detection)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS |
+ NAU8325_PWRUP_DFT, 0);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT,
+ NAU8325_CLKPWRUP_DIS);
+ regmap_update_bits(regmap, NAU8325_R29_DAC_CTRL1,
+ NAU8325_DAC_OVERSAMPLE_MASK,
+ NAU8325_DAC_OVERSAMPLE_128);
+}
+
+static void nau8325_print_device_properties(struct nau8325 *nau8325)
+{
+ struct device *dev = nau8325->dev;
+
+ dev_dbg(dev, "vref-impedance-ohms: %d", nau8325->vref_impedance_ohms);
+ dev_dbg(dev, "dac-vref-microvolt: %d", nau8325->dac_vref_microvolt);
+ dev_dbg(dev, "alc-enable: %d", nau8325->alc_enable);
+ dev_dbg(dev, "clock-det-data: %d", nau8325->clock_det_data);
+ dev_dbg(dev, "clock-detection-disable: %d", nau8325->clock_detection);
+}
+
+static int nau8325_read_device_properties(struct device *dev,
+ struct nau8325 *nau8325)
+{
+ int ret;
+
+ nau8325->alc_enable =
+ device_property_read_bool(dev, "nuvoton,alc-enable");
+ nau8325->clock_det_data =
+ device_property_read_bool(dev, "nuvoton,clock-det-data");
+ nau8325->clock_detection =
+ !device_property_read_bool(dev, "nuvoton,clock-detection-disable");
+
+ ret = device_property_read_u32(dev, "nuvoton,vref-impedance-ohms",
+ &nau8325->vref_impedance_ohms);
+ if (ret)
+ nau8325->vref_impedance_ohms = 125000;
+ ret = device_property_read_u32(dev, "nuvoton,dac-vref-microvolt",
+ &nau8325->dac_vref_microvolt);
+ if (ret)
+ nau8325->dac_vref_microvolt = 2880000;
+
+ return 0;
+}
+
+static int nau8325_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c->dev;
+ struct nau8325 *nau8325 = dev_get_platdata(dev);
+ int ret, value;
+
+ if (!nau8325) {
+ nau8325 = devm_kzalloc(dev, sizeof(*nau8325), GFP_KERNEL);
+ if (!nau8325) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = nau8325_read_device_properties(dev, nau8325);
+ if (ret)
+ goto err;
+ }
+ i2c_set_clientdata(i2c, nau8325);
+
+ nau8325->regmap = devm_regmap_init_i2c(i2c, &nau8325_regmap_config);
+ if (IS_ERR(nau8325->regmap)) {
+ ret = PTR_ERR(nau8325->regmap);
+ goto err;
+ }
+ nau8325->dev = dev;
+ nau8325_print_device_properties(nau8325);
+
+ nau8325_reset_chip(nau8325->regmap);
+ ret = regmap_read(nau8325->regmap, NAU8325_R02_DEVICE_ID, &value);
+ if (ret) {
+ dev_dbg(dev, "Failed to read device id (%d)", ret);
+ goto err;
+ }
+ nau8325_init_regs(nau8325);
+
+ ret = devm_snd_soc_register_component(dev, &nau8325_component_driver,
+ &nau8325_dai, 1);
+err:
+ return ret;
+}
+
+static const struct i2c_device_id nau8325_i2c_ids[] = {
+ { "nau8325", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nau8325_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8325_of_ids[] = {
+ { .compatible = "nuvoton,nau8325", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nau8325_of_ids);
+#endif
+
+static struct i2c_driver nau8325_i2c_driver = {
+ .driver = {
+ .name = "nau8325",
+ .of_match_table = of_match_ptr(nau8325_of_ids),
+ },
+ .probe = nau8325_i2c_probe,
+ .id_table = nau8325_i2c_ids,
+};
+module_i2c_driver(nau8325_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8325 driver");
+MODULE_AUTHOR("Seven Lee <WTLI@nuvoton.com>");
+MODULE_AUTHOR("David Lin <CTLIN0@nuvoton.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/nau8325.h b/sound/soc/codecs/nau8325.h
new file mode 100644
index 000000000000..0d173b66a4d4
--- /dev/null
+++ b/sound/soc/codecs/nau8325.h
@@ -0,0 +1,391 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * nau8325.h -- Nuvoton NAU8325 audio codec driver
+ *
+ * Copyright 2023 Nuvoton Technology Crop.
+ * Author: Seven Lee <WTLI@nuvoton.com>
+ * David Lin <CTLIN0@nuvoton.com>
+ */
+
+#ifndef __NAU8325_H__
+#define __NAU8325_H__
+
+#define NAU8325_R00_HARDWARE_RST 0x00
+#define NAU8325_R01_SOFTWARE_RST 0x01
+#define NAU8325_R02_DEVICE_ID 0x02
+#define NAU8325_R03_CLK_CTRL 0x03
+#define NAU8325_R04_ENA_CTRL 0x04
+#define NAU8325_R05_INTERRUPT_CTRL 0x05
+#define NAU8325_R06_INT_CLR_STATUS 0x06
+#define NAU8325_R09_IRQOUT 0x09
+#define NAU8325_R0A_IO_CTRL 0x0a
+#define NAU8325_R0B_PDM_CTRL 0x0b
+#define NAU8325_R0C_TDM_CTRL 0x0c
+#define NAU8325_R0D_I2S_PCM_CTRL1 0x0d
+#define NAU8325_R0E_I2S_PCM_CTRL2 0x0e
+#define NAU8325_R0F_L_TIME_SLOT 0x0f
+#define NAU8325_R10_R_TIME_SLOT 0x10
+#define NAU8325_R11_HPF_CTRL 0x11
+#define NAU8325_R12_MUTE_CTRL 0x12
+#define NAU8325_R13_DAC_VOLUME 0x13
+#define NAU8325_R1D_DEBUG_READ1 0x1d
+#define NAU8325_R1F_DEBUG_READ2 0x1f
+#define NAU8325_R22_DEBUG_READ3 0x22
+#define NAU8325_R29_DAC_CTRL1 0x29
+#define NAU8325_R2A_DAC_CTRL2 0x2a
+#define NAU8325_R2C_ALC_CTRL1 0x2c
+#define NAU8325_R2D_ALC_CTRL2 0x2d
+#define NAU8325_R2E_ALC_CTRL3 0x2e
+#define NAU8325_R2F_ALC_CTRL4 0x2f
+#define NAU8325_R40_CLK_DET_CTRL 0x40
+#define NAU8325_R49_TEST_STATUS 0x49
+#define NAU8325_R4A_ANALOG_READ 0x4a
+#define NAU8325_R50_MIXER_CTRL 0x50
+#define NAU8325_R55_MISC_CTRL 0x55
+#define NAU8325_R60_BIAS_ADJ 0x60
+#define NAU8325_R61_ANALOG_CONTROL_1 0x61
+#define NAU8325_R62_ANALOG_CONTROL_2 0x62
+#define NAU8325_R63_ANALOG_CONTROL_3 0x63
+#define NAU8325_R64_ANALOG_CONTROL_4 0x64
+#define NAU8325_R65_ANALOG_CONTROL_5 0x65
+#define NAU8325_R66_ANALOG_CONTROL_6 0x66
+#define NAU8325_R69_CLIP_CTRL 0x69
+#define NAU8325_R73_RDAC 0x73
+#define NAU8325_REG_MAX NAU8325_R73_RDAC
+
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8325_REG_ADDR_LEN 16
+#define NAU8325_REG_DATA_LEN 16
+
+/* CLK_CTRL (0x03) */
+#define NAU8325_CLK_DAC_SRC_SFT 12
+#define NAU8325_CLK_DAC_SRC_MASK (0x3 << NAU8325_CLK_DAC_SRC_SFT)
+#define NAU8325_CLK_MUL_SRC_SFT 6
+#define NAU8325_CLK_MUL_SRC_MASK (0x3 << NAU8325_CLK_MUL_SRC_SFT)
+#define NAU8325_MCLK_SEL_SFT 3
+#define NAU8325_MCLK_SEL_MASK (0x7 << NAU8325_MCLK_SEL_SFT)
+#define NAU8325_MCLK_SRC_MASK 0x7
+
+/* ENA_CTRL (0x04) */
+#define NAU8325_DAC_LEFT_CH_EN_SFT 3
+#define NAU8325_DAC_LEFT_CH_EN (0x1 << NAU8325_DAC_LEFT_CH_EN_SFT)
+#define NAU8325_DAC_RIGHT_CH_EN_SFT 2
+#define NAU8325_DAC_RIGHT_CH_EN (0x1 << NAU8325_DAC_RIGHT_CH_EN_SFT)
+
+/* INTERRUPT_CTRL (0x05) */
+#define NAU8325_ARP_DWN_INT_SFT 12
+#define NAU8325_ARP_DWN_INT_MASK (0x1 << NAU8325_ARP_DWN_INT_SFT)
+#define NAU8325_CLIP_INT_SFT 11
+#define NAU8325_CLIP_INT_MASK (0x1 << NAU8325_CLIP_INT_SFT)
+#define NAU8325_LVD_INT_SFT 10
+#define NAU8325_LVD_INT_MASK (0x1 << NAU8325_LVD_INT_SFT)
+#define NAU8325_PWR_INT_DIS_SFT 8
+#define NAU8325_PWR_INT_DIS (0x1 << NAU8325_PWR_INT_DIS_SFT)
+#define NAU8325_OCP_OTP_SHTDWN_INT_SFT 4
+#define NAU8325_OCP_OTP_SHTDWN_INT_MASK (0x1 << NAU8325_OCP_OTP_SHTDWN_INT_SFT)
+#define NAU8325_CLIP_INT_DIS_SFT 3
+#define NAU8325_CLIP_INT_DIS (0x1 << NAU8325_CLIP_INT_DIS_SFT)
+#define NAU8325_LVD_INT_DIS_SFT 2
+#define NAU8325_LVD_INT_DIS (0x1 << NAU8325_LVD_INT_DIS_SFT)
+#define NAU8325_PWR_INT_MASK 0x1
+
+/* INT_CLR_STATUS (0x06) */
+#define NAU8325_INT_STATUS_MASK 0x7f
+
+/* IRQOUT (0x9) */
+#define NAU8325_IRQOUT_SEL_SEF 12
+#define NAU8325_IRQOUT_SEL_MASK (0xf << NAU8325_IRQOUT_SEL_SEF)
+#define NAU8325_DEM_DITH_SFT 7
+#define NAU8325_DEM_DITH_EN (0x1 << NAU8325_DEM_DITH_SFT)
+#define NAU8325_GAINZI3_SFT 5
+#define NAU8325_GAINZI3_MASK (0x1 << NAU8325_GAINZI3_SFT)
+#define NAU8325_GAINZI2_MASK 0x1f
+
+/* IO_CTRL (0x0a) */
+#define NAU8325_IRQ_PL_SFT 15
+#define NAU8325_IRQ_PL_ACT_HIGH (0x1 << NAU8325_IRQ_PL_SFT)
+#define NAU8325_IRQ_PS_SFT 14
+#define NAU8325_IRQ_PS_UP (0x1 << NAU8325_IRQ_PS_SFT)
+#define NAU8325_IRQ_PE_SFT 13
+#define NAU8325_IRQ_PE_EN (0x1 << NAU8325_IRQ_PE_SFT)
+#define NAU8325_IRQ_DS_SFT 12
+#define NAU8325_IRQ_DS_HIGH (0x1 << NAU8325_IRQ_DS_SFT)
+#define NAU8325_IRQ_OUTPUT_SFT 11
+#define NAU8325_IRQ_OUTPUT_EN (0x1 << NAU8325_IRQ_OUTPUT_SFT)
+#define NAU8325_IRQ_PIN_DEBUG_SFT 10
+#define NAU8325_IRQ_PIN_DEBUG_EN (0x1 << NAU8325_IRQ_PIN_DEBUG_SFT)
+
+/* PDM_CTRL (0x0b) */
+#define NAU8325_PDM_LCH_EDGE_SFT 1
+#define NAU8325_PDM_LCH_EDGE__MASK (0x1 << NAU8325_PDM_LCH_EDGE_SFT)
+#define NAU8325_PDM_MODE_EN 0x1
+
+/* TDM_CTRL (0x0c) */
+#define NAU8325_TDM_SFT 15
+#define NAU8325_TDM_EN (0x1 << NAU8325_TDM_SFT)
+#define NAU8325_PCM_OFFSET_CTRL_SFT 14
+#define NAU8325_PCM_OFFSET_CTRL_EN (0x1 << NAU8325_PCM_OFFSET_CTRL_SFT)
+#define NAU8325_DAC_LEFT_SFT 6
+#define NAU8325_NAU8325_DAC_LEFT_MASK (0x7 << NAU8325_DAC_LEFT_SFT)
+#define NAU8325_DAC_RIGHT_SFT 3
+#define NAU8325_DAC_RIGHT_MASK (0x7 << NAU8325_DAC_RIGHT_SFT)
+
+/* I2S_PCM_CTRL1 (0x0d) */
+#define NAU8325_DACCM_CTL_SFT 14
+#define NAU8325_DACCM_CTL_MASK (0x3 << NAU8325_DACCM_CTL_SFT)
+#define NAU8325_CMB8_0_SFT 10
+#define NAU8325_CMB8_0_MASK (0x1 << NAU8325_CMB8_0_SFT)
+#define NAU8325_UA_OFFSET_SFT 9
+#define NAU8325_UA_OFFSET_MASK (0x1 << NAU8325_UA_OFFSET_SFT)
+#define NAU8325_I2S_BP_SFT 7
+#define NAU8325_I2S_BP_MASK (0x1 << NAU8325_I2S_BP_SFT)
+#define NAU8325_I2S_BP_INV (0x1 << NAU8325_I2S_BP_SFT)
+#define NAU8325_I2S_PCMB_SFT 6
+#define NAU8325_I2S_PCMB_EN (0x1 << NAU8325_I2S_PCMB_SFT)
+#define NAU8325_I2S_DACPSHS0_SFT 5
+#define NAU8325_I2S_DACPSHS0_MASK (0x1 << NAU8325_I2S_DACPSHS0_SFT)
+#define NAU8325_I2S_DL_SFT 2
+#define NAU8325_I2S_DL_MASK (0x3 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_32 (0x3 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_24 (0x2 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_20 (0x1 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_16 (0x0 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DF_MASK 0x3
+#define NAU8325_I2S_DF_RIGTH 0x0
+#define NAU8325_I2S_DF_LEFT 0x1
+#define NAU8325_I2S_DF_I2S 0x2
+#define NAU8325_I2S_DF_PCM_AB 0x3
+
+/* I2S_PCM_CTRL2 (0x0e) */
+#define NAU8325_PCM_TS_SFT 10
+#define NAU8325_PCM_TS_EN (0x1 << NAU8325_PCM_TS_SFT)
+#define NAU8325_PCM8BIT0_SFT 8
+#define NAU8325_PCM8BIT0_MASK (0x1 << NAU8325_PCM8BIT0_SFT)
+
+/* L_TIME_SLOT (0x0f)*/
+#define NAU8325_SHORT_FS_DET_SFT 13
+#define NAU8325_SHORT_FS_DET_DIS (0x1 << NAU8325_SHORT_FS_DET_SFT)
+#define NAU8325_TSLOT_L0_MASK 0x3ff
+
+/* R_TIME_SLOT (0x10)*/
+#define NAU8325_TSLOT_R0_MASK 0x3ff
+
+/* HPF_CTRL (0x11)*/
+#define NAU8325_DAC_HPF_SFT 15
+#define NAU8325_DAC_HPF_EN (0x1 << NAU8325_DAC_HPF_SFT)
+#define NAU8325_DAC_HPF_APP_SFT 14
+#define NAU8325_DAC_HPF_APP_MASK (0x1 << NAU8325_DAC_HPF_APP_SFT)
+#define NAU8325_DAC_HPF_FCUT_SFT 11
+#define NAU8325_DAC_HPF_FCUT_MASK (0x7 << NAU8325_DAC_HPF_FCUT_SFT)
+
+/* MUTE_CTRL (0x12)*/
+#define NAU8325_SOFT_MUTE_SFT 15
+#define NAU8325_SOFT_MUTE (0x1 << NAU8325_SOFT_MUTE_SFT)
+#define NAU8325_DAC_ZC_SFT 8
+#define NAU8325_DAC_ZC_EN (0x1 << NAU8325_DAC_ZC_SFT)
+#define NAU8325_UNMUTE_CTL_SFT 6
+#define NAU8325_UNMUTE_CTL_MASK (0x3 << NAU8325_UNMUTE_CTL_SFT)
+#define NAU8325_ANA_MUTE_SFT 4
+#define NAU8325_ANA_MUTE_MASK (0x3 << NAU8325_ANA_MUTE_SFT)
+#define NAU8325_AUTO_MUTE_SFT 3
+#define NAU8325_AUTO_MUTE_DIS (0x1 << NAU8325_AUTO_MUTE_SFT)
+
+/* DAC_VOLUME (0x13) */
+#define NAU8325_DAC_VOLUME_L_SFT 8
+#define NAU8325_DAC_VOLUME_L_EN (0xff << NAU8325_DAC_VOLUME_L_SFT)
+#define NAU8325_DAC_VOLUME_R_SFT 0
+#define NAU8325_DAC_VOLUME_R_EN (0xff << NAU8325_DAC_VOLUME_R_SFT)
+#define NAU8325_DAC_VOL_MAX 0xff
+
+/* DEBUG_READ1 (0x1d)*/
+#define NAU8325_OSR100_MASK (0x1 << 6)
+#define NAU8325_MIPS500_MASK (0x1 << 5)
+#define NAU8325_SHUTDWNDRVR_R_MASK (0x1 << 4)
+#define NAU8325_SHUTDWNDRVR_L_MASK (0x1 << 3)
+#define NAU8325_MUTEB_MASK (0x1 << 2)
+#define NAU8325_PDOSCB_MASK (0x1 << 1)
+#define NAU8325_POWERDOWN1B_D_MASK 0x1
+
+/* DEBUG_READ2 (0x1f)*/
+#define NAU8325_R_CHANNEL_Vol_SFT 8
+#define NAU8325_R_CHANNEL_Vol_MASK (0xff << NAU8325_R_CHANNEL_Vol_SFT)
+#define NAU8325_L_CHANNEL_Vol_MASK 0xff
+
+/* DEBUG_READ3(0x22)*/
+#define NAU8325_PGAL_GAIN_MASK (0x3f << 7)
+#define NAU8325_CLIP_MASK (0x1 << 6)
+#define NAU8325_SCAN_MODE_MASK (0x1 << 5)
+#define NAU8325_SDB_MASK (0x1 << 4)
+#define NAU8325_TALARM_MASK (0x1 << 3)
+#define NAU8325_SHORTR_MASK (0x1 << 2)
+#define NAU8325_SHORTL_MASK (0x1 << 1)
+#define NAU8325_TMDET_MASK 0x1
+
+/* DAC_CTRL1 (0x29) */
+#define NAU8325_DAC_OVERSAMPLE_SFT 0
+#define NAU8325_DAC_OVERSAMPLE_MASK 0x7
+#define NAU8325_DAC_OVERSAMPLE_256 1
+#define NAU8325_DAC_OVERSAMPLE_128 2
+#define NAU8325_DAC_OVERSAMPLE_64 0
+#define NAU8325_DAC_OVERSAMPLE_32 4
+
+/* ALC_CTRL1 (0x2c) */
+#define NAU8325_ALC_MAXGAIN_SFT 5
+#define NAU8325_ALC_MAXGAIN_MAX 0x7
+#define NAU8325_ALC_MAXGAIN_MASK (0x7 << NAU8325_ALC_MAXGAIN_SFT)
+#define NAU8325_ALC_MINGAIN_MAX 4
+#define NAU8325_ALC_MINGAIN_SFT 1
+#define NAU8325_ALC_MINGAIN_MASK (0x7 << NAU8325_ALC_MINGAIN_SFT)
+
+/* ALC_CTRL2 (0x2d) */
+#define NAU8325_ALC_DCY_SFT 12
+#define NAU8325_ALC_DCY_MAX 0xb
+#define NAU8325_ALC_DCY_MASK (0xf << NAU8325_ALC_DCY_SFT)
+#define NAU8325_ALC_ATK_SFT 8
+#define NAU8325_ALC_ATK_MAX 0xb
+#define NAU8325_ALC_ATK_MASK (0xf << NAU8325_ALC_ATK_SFT)
+#define NAU8325_ALC_HLD_SFT 4
+#define NAU8325_ALC_HLD_MAX 0xa
+#define NAU8325_ALC_HLD_MASK (0xf << NAU8325_ALC_HLD_SFT)
+#define NAU8325_ALC_LVL_SFT 0
+#define NAU8325_ALC_LVL_MAX 0xf
+#define NAU8325_ALC_LVL_MASK 0xf
+
+/* ALC_CTRL3 (0x2e) */
+#define NAU8325_ALC_EN_SFT 15
+#define NAU8325_ALC_EN (0x1 << NAU8325_ALC_EN_SFT)
+
+/* TEMP_COMP_CTRL (0x30) */
+#define NAU8325_TEMP_COMP_ACT2_MASK 0xff
+
+/* LPF_CTRL (0x33) */
+#define NAU8325_LPF_IN1_EN_SFT 15
+#define NAU8325_LPF_IN1_EN (0x1 << NAU8325_LPF_IN1_EN_SFT)
+#define NAU8325_LPF_IN1_TC_SFT 11
+#define NAU8325_LPF_IN1_TC_MASK (0xf << NAU8325_LPF_IN1_TC_SFT)
+#define NAU8325_LPF_IN2_EN_SFT 10
+#define NAU8325_LPF_IN2_EN (0x1 << NAU8325_LPF_IN2_EN_SFT)
+#define NAU8325_LPF_IN2_TC_SFT 6
+#define NAU8325_LPF_IN2_TC_MASK (0xf << NAU8325_LPF_IN2_TC_SFT)
+
+/* CLK_DET_CTRL (0x40) */
+#define NAU8325_APWRUP_SFT 15
+#define NAU8325_APWRUP_EN (0x1 << NAU8325_APWRUP_SFT)
+#define NAU8325_CLKPWRUP_SFT 14
+#define NAU8325_CLKPWRUP_DIS (0x1 << NAU8325_CLKPWRUP_SFT)
+#define NAU8325_PWRUP_DFT_SFT 13
+#define NAU8325_PWRUP_DFT (0x1 << NAU8325_PWRUP_DFT_SFT)
+#define NAU8325_REG_SRATE_SFT 10
+#define NAU8325_REG_SRATE_MASK (0x7 << NAU8325_REG_SRATE_SFT)
+#define NAU8325_REG_ALT_SRATE_SFT 9
+#define NAU8325_REG_ALT_SRATE_EN (0x1 << NAU8325_REG_ALT_SRATE_SFT)
+#define NAU8325_REG_DIV_MAX 0x1
+
+/* BIAS_ADJ (0x60) */
+#define NAU8325_BIAS_VMID_SEL_SFT 4
+#define NAU8325_BIAS_VMID_SEL_MASK (0x3 << NAU8325_BIAS_VMID_SEL_SFT)
+
+/* ANALOG_CONTROL_1 (0x61) */
+#define NAU8325_VMDFSTENB_SFT 14
+#define NAU8325_VMDFSTENB_MASK (0x3 << NAU8325_VMDFSTENB_SFT)
+#define NAU8325_CLASSDEN_SFT 12
+#define NAU8325_CLASSDEN_MASK (0x3 << NAU8325_CLASSDEN_SFT)
+#define NAU8325_DACCLKEN_R_SFT 10
+#define NAU8325_DACCLKEN_R_MASK (0x3 << NAU8325_DACCLKEN_R_SFT)
+#define NAU8325_DACEN_R_SFT 8
+#define NAU8325_DACEN_R_MASK (0x3 << NAU8325_DACEN_R_SFT)
+#define NAU8325_DACCLKEN_SFT 6
+#define NAU8325_DACCLKEN_MASK (0x3 << NAU8325_DACCLKEN_SFT)
+#define NAU8325_DACEN_SFT 4
+#define NAU8325_DACEN_MASK (0x3 << NAU8325_DACEN_SFT)
+#define NAU8325_BIASEN_SFT 2
+#define NAU8325_BIASEN_MASK (0x3 << NAU8325_BIASEN_SFT)
+#define NAU8325_VMIDEN_MASK 0x3
+
+/* ANALOG_CONTROL_2 (0x62) */
+#define NAU8325_PWMMOD_SFT 14
+#define NAU8325_PWMMOD_MASK (0x1 << NAU8325_PWMMOD_SFT)
+#define NAU8325_DACTEST_SFT 6
+#define NAU8325_DACTEST_MASK (0x3 << NAU8325_DACTEST_SFT)
+#define NAU8325_DACREFCAP_SFT 4
+#define NAU8325_DACREFCAP_MASK (0x3 << NAU8325_DACREFCAP_SFT)
+
+/* ANALOG_CONTROL_3 (0x63) */
+#define NAU8325_POWER_DOWN_L_SFT 12
+#define NAU8325_POWER_DOWN_L_MASK (0x3 << NAU8325_POWER_DOWN_L_SFT)
+#define NAU8325_POWER_DOWN_R_SFT 11
+#define NAU8325_POWER_DOWN_R_MASK (0x3 << NAU8325_DACREFCAP_SFT)
+#define NAU8325_CLASSD_FINE_SFT 5
+#define NAU8325_CLASSD_FINE_MASK (0x3 << NAU8325_CLASSD_FINE_SFT)
+#define NAU8325_CLASSD_COARSE_GAIN_MASK 0xf
+
+/* ANALOG_CONTROL_4 (0x64) */
+#define NAU8325_CLASSD_OCPN_SFT 12
+#define NAU8325_CLASSD_OCPN_MASK (0xf << NAU8325_CLASSD_OCPN_SFT)
+#define NAU8325_CLASSD_OCPP_SFT 8
+#define NAU8325_CLASSD_OCPP_MASK (0xf << NAU8325_CLASSD_OCPP_SFT)
+#define NAU8325_CLASSD_SLEWN_MASK 0xff
+
+/* ANALOG_CONTROL_5 (0x65) */
+#define NAU8325_MCLK_RANGE_SFT 2
+#define NAU8325_MCLK_RANGE_EN (0x1 << NAU8325_MCLK_RANGE_SFT)
+#define NAU8325_MCLK8XEN_SFT 1
+#define NAU8325_MCLK8XEN_EN (0x1 << NAU8325_MCLK8XEN_SFT)
+#define NAU8325_MCLK4XEN_EN 0x1
+
+/* ANALOG_CONTROL_6 (0x66) */
+#define NAU8325_VBATLOW_SFT 4
+#define NAU8325_VBATLOW_MASK (0x1 << NAU8325_VBATLOW_SFT)
+#define NAU8325_VDDSPK_LIM_SFT 3
+#define NAU8325_VDDSPK_LIM_EN (0x1 << NAU8325_VDDSPK_LIM_SFT)
+#define NAU8325_VDDSPK_LIM_MASK 0x7
+
+/* CLIP_CTRL (0x69)*/
+#define NAU8325_ANTI_CLIP_SFT 4
+#define NAU8325_ANTI_CLIP_EN (0x1 << NAU8325_ANTI_CLIP_SFT)
+
+/* RDAC (0x73) */
+#define NAU8325_CLK_DAC_DELAY_SFT 4
+#define NAU8325_CLK_DAC_DELAY_EN (0x7 << NAU8325_CLK_DAC_DELAY_SFT)
+#define NAU8325_DACVREFSEL_SFT 2
+#define NAU8325_DACVREFSEL_MASK (0x3 << NAU8325_DACVREFSEL_SFT)
+
+#define NAU8325_CODEC_DAI "nau8325-hifi"
+
+struct nau8325 {
+ struct device *dev;
+ struct regmap *regmap;
+ int mclk;
+ int fs;
+ int vref_impedance_ohms;
+ int dac_vref_microvolt;
+ int clock_detection;
+ int clock_det_data;
+ int alc_enable;
+};
+
+struct nau8325_src_attr {
+ int param;
+ unsigned int val;
+};
+
+enum {
+ NAU8325_MCLK_FS_RATIO_256,
+ NAU8325_MCLK_FS_RATIO_400,
+ NAU8325_MCLK_FS_RATIO_500,
+ NAU8325_MCLK_FS_RATIO_NUM,
+};
+
+struct nau8325_srate_attr {
+ int fs;
+ int range;
+ bool max;
+ unsigned int mclk_src[NAU8325_MCLK_FS_RATIO_NUM];
+};
+
+struct nau8325_osr_attr {
+ unsigned int osr;
+ unsigned int clk_src;
+};
+
+#endif /* __NAU8325_H__ */
diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c
new file mode 100644
index 000000000000..9d3e4691a7b5
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.c
@@ -0,0 +1,974 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip RK3308 internal audio codec driver
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2024, Vivax-Metrotech Ltd
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/util_macros.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "rk3308_codec.h"
+
+#define ADC_LR_GROUP_MAX 4
+
+#define GRF_CHIP_ID 0x800
+
+enum {
+ ACODEC_VERSION_A = 'A',
+ ACODEC_VERSION_B,
+ ACODEC_VERSION_C,
+};
+
+struct rk3308_codec_priv {
+ const struct device *dev;
+ struct regmap *regmap;
+ struct regmap *grf;
+ struct reset_control *reset;
+ struct clk *hclk;
+ struct clk *mclk_rx;
+ struct clk *mclk_tx;
+ struct snd_soc_component *component;
+ unsigned char codec_ver;
+};
+
+static struct clk_bulk_data rk3308_codec_clocks[] = {
+ { .id = "hclk" },
+ { .id = "mclk_rx" },
+ { .id = "mclk_tx" },
+};
+
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, -1800, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, -3900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, -600, 600, 0);
+
+static const DECLARE_TLV_DB_RANGE(rk3308_codec_dac_lineout_gain_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(-300, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(-150, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0),
+);
+
+static const char * const rk3308_codec_hpf_cutoff_text[] = {
+ "20 Hz", "245 Hz", "612 Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum12, RK3308_ADC_DIG_CON04(0), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum34, RK3308_ADC_DIG_CON04(1), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum56, RK3308_ADC_DIG_CON04(2), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum78, RK3308_ADC_DIG_CON04(3), 0,
+ rk3308_codec_hpf_cutoff_text);
+
+static const struct snd_kcontrol_new rk3308_codec_controls[] = {
+ /* Despite the register names, these set the gain when AGC is OFF */
+ SOC_SINGLE_RANGE_TLV("MIC1 Capture Volume",
+ RK3308_ADC_ANA_CON03(0),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC2 Capture Volume",
+ RK3308_ADC_ANA_CON04(0),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC3 Capture Volume",
+ RK3308_ADC_ANA_CON03(1),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC4 Capture Volume",
+ RK3308_ADC_ANA_CON04(1),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC5 Capture Volume",
+ RK3308_ADC_ANA_CON03(2),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC6 Capture Volume",
+ RK3308_ADC_ANA_CON04(2),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC7 Capture Volume",
+ RK3308_ADC_ANA_CON03(3),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC8 Capture Volume",
+ RK3308_ADC_ANA_CON04(3),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+
+ SOC_SINGLE("MIC1 Capture Switch", RK3308_ADC_ANA_CON00(0), 3, 1, 0),
+ SOC_SINGLE("MIC2 Capture Switch", RK3308_ADC_ANA_CON00(0), 7, 1, 0),
+ SOC_SINGLE("MIC3 Capture Switch", RK3308_ADC_ANA_CON00(1), 3, 1, 0),
+ SOC_SINGLE("MIC4 Capture Switch", RK3308_ADC_ANA_CON00(1), 7, 1, 0),
+ SOC_SINGLE("MIC5 Capture Switch", RK3308_ADC_ANA_CON00(2), 3, 1, 0),
+ SOC_SINGLE("MIC6 Capture Switch", RK3308_ADC_ANA_CON00(2), 7, 1, 0),
+ SOC_SINGLE("MIC7 Capture Switch", RK3308_ADC_ANA_CON00(3), 3, 1, 0),
+ SOC_SINGLE("MIC8 Capture Switch", RK3308_ADC_ANA_CON00(3), 7, 1, 0),
+
+ SOC_SINGLE("MIC12 HPF Capture Switch", RK3308_ADC_DIG_CON04(0), 2, 1, 1),
+ SOC_SINGLE("MIC34 HPF Capture Switch", RK3308_ADC_DIG_CON04(1), 2, 1, 1),
+ SOC_SINGLE("MIC56 HPF Capture Switch", RK3308_ADC_DIG_CON04(2), 2, 1, 1),
+ SOC_SINGLE("MIC78 HPF Capture Switch", RK3308_ADC_DIG_CON04(3), 2, 1, 1),
+
+ SOC_ENUM("MIC12 HPF Cutoff", rk3308_codec_hpf_cutoff_enum12),
+ SOC_ENUM("MIC34 HPF Cutoff", rk3308_codec_hpf_cutoff_enum34),
+ SOC_ENUM("MIC56 HPF Cutoff", rk3308_codec_hpf_cutoff_enum56),
+ SOC_ENUM("MIC78 HPF Cutoff", rk3308_codec_hpf_cutoff_enum78),
+
+ SOC_DOUBLE_TLV("Line Out Playback Volume",
+ RK3308_DAC_ANA_CON04,
+ RK3308_DAC_L_LINEOUT_GAIN_SFT,
+ RK3308_DAC_R_LINEOUT_GAIN_SFT,
+ RK3308_DAC_x_LINEOUT_GAIN_MAX,
+ 0, rk3308_codec_dac_lineout_gain_tlv),
+ SOC_DOUBLE("Line Out Playback Switch",
+ RK3308_DAC_ANA_CON04,
+ RK3308_DAC_L_LINEOUT_MUTE_SFT,
+ RK3308_DAC_R_LINEOUT_MUTE_SFT, 1, 0),
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume",
+ RK3308_DAC_ANA_CON05,
+ RK3308_DAC_ANA_CON06,
+ RK3308_DAC_x_HPOUT_GAIN_SFT,
+ RK3308_DAC_x_HPOUT_GAIN_MAX,
+ 0, rk3308_codec_dac_hpout_gain_tlv),
+ SOC_DOUBLE("Headphone Playback Switch",
+ RK3308_DAC_ANA_CON03,
+ RK3308_DAC_L_HPOUT_MUTE_SFT,
+ RK3308_DAC_R_HPOUT_MUTE_SFT, 1, 0),
+ SOC_DOUBLE_RANGE_TLV("DAC HPMIX Playback Volume",
+ RK3308_DAC_ANA_CON12,
+ RK3308_DAC_L_HPMIX_GAIN_SFT,
+ RK3308_DAC_R_HPMIX_GAIN_SFT,
+ 1, 2, 0, rk3308_codec_dac_hpmix_gain_tlv),
+};
+
+static int rk3308_codec_pop_sound_set(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+ unsigned int val = (event == SND_SOC_DAPM_POST_PMU) ?
+ RK3308_DAC_HPOUT_POP_SOUND_x_WORK :
+ RK3308_DAC_HPOUT_POP_SOUND_x_INIT;
+ unsigned int mask = RK3308_DAC_HPOUT_POP_SOUND_x_MSK;
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+ mask << w->shift, val << w->shift);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rk3308_codec_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+ SND_SOC_DAPM_INPUT("MIC4"),
+ SND_SOC_DAPM_INPUT("MIC5"),
+ SND_SOC_DAPM_INPUT("MIC6"),
+ SND_SOC_DAPM_INPUT("MIC7"),
+ SND_SOC_DAPM_INPUT("MIC8"),
+
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN12", RK3308_ADC_ANA_CON06(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN34", RK3308_ADC_ANA_CON06(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN56", RK3308_ADC_ANA_CON06(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN78", RK3308_ADC_ANA_CON06(3), 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_EN", RK3308_ADC_ANA_CON00(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_EN", RK3308_ADC_ANA_CON00(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_EN", RK3308_ADC_ANA_CON00(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_EN", RK3308_ADC_ANA_CON00(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_EN", RK3308_ADC_ANA_CON00(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_EN", RK3308_ADC_ANA_CON00(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_EN", RK3308_ADC_ANA_CON00(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_EN", RK3308_ADC_ANA_CON00(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_WORK", RK3308_ADC_ANA_CON00(0), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_WORK", RK3308_ADC_ANA_CON00(0), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_WORK", RK3308_ADC_ANA_CON00(1), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_WORK", RK3308_ADC_ANA_CON00(1), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_WORK", RK3308_ADC_ANA_CON00(2), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_WORK", RK3308_ADC_ANA_CON00(2), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_WORK", RK3308_ADC_ANA_CON00(3), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_WORK", RK3308_ADC_ANA_CON00(3), 6, 1, 1, 0),
+
+ /*
+ * In theory MIC1 and MIC2 can switch to LINE IN, but this is not
+ * supported so all we can do is enabling the MIC input.
+ */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH1_IN_SEL", RK3308_ADC_ANA_CON07(0), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH2_IN_SEL", RK3308_ADC_ANA_CON07(0), 6, 1, 1, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC3_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC4_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC5_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC6_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC7_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC8_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC_MCLK_GATE", RK3308_GLB_CON, 5, 1, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1_CLK_EN", RK3308_ADC_ANA_CON05(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2_CLK_EN", RK3308_ADC_ANA_CON05(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC3_CLK_EN", RK3308_ADC_ANA_CON05(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC4_CLK_EN", RK3308_ADC_ANA_CON05(1), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC5_CLK_EN", RK3308_ADC_ANA_CON05(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC6_CLK_EN", RK3308_ADC_ANA_CON05(2), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC7_CLK_EN", RK3308_ADC_ANA_CON05(3), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC8_CLK_EN", RK3308_ADC_ANA_CON05(3), 4, 0, NULL, 0),
+
+ /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_EN", RK3308_ADC_ANA_CON02(0), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_EN", RK3308_ADC_ANA_CON02(0), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_EN", RK3308_ADC_ANA_CON02(1), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_EN", RK3308_ADC_ANA_CON02(1), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_EN", RK3308_ADC_ANA_CON02(2), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_EN", RK3308_ADC_ANA_CON02(2), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_EN", RK3308_ADC_ANA_CON02(3), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_EN", RK3308_ADC_ANA_CON02(3), 4, 1, 1, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC1_EN", RK3308_ADC_ANA_CON05(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC2_EN", RK3308_ADC_ANA_CON05(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC3_EN", RK3308_ADC_ANA_CON05(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC4_EN", RK3308_ADC_ANA_CON05(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC5_EN", RK3308_ADC_ANA_CON05(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC6_EN", RK3308_ADC_ANA_CON05(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC7_EN", RK3308_ADC_ANA_CON05(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC8_EN", RK3308_ADC_ANA_CON05(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_ADC("ADC1_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 2, 0),
+ SND_SOC_DAPM_ADC("ADC2_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 6, 0),
+ SND_SOC_DAPM_ADC("ADC3_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 2, 0),
+ SND_SOC_DAPM_ADC("ADC4_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 6, 0),
+ SND_SOC_DAPM_ADC("ADC5_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 2, 0),
+ SND_SOC_DAPM_ADC("ADC6_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 6, 0),
+ SND_SOC_DAPM_ADC("ADC7_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 2, 0),
+ SND_SOC_DAPM_ADC("ADC8_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 6, 0),
+
+ /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_WORK", RK3308_ADC_ANA_CON02(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_WORK", RK3308_ADC_ANA_CON02(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_WORK", RK3308_ADC_ANA_CON02(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_WORK", RK3308_ADC_ANA_CON02(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_WORK", RK3308_ADC_ANA_CON02(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_WORK", RK3308_ADC_ANA_CON02(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_WORK", RK3308_ADC_ANA_CON02(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_WORK", RK3308_ADC_ANA_CON02(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_SUPPLY("MICBIAS Current", RK3308_ADC_ANA_CON08(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", RK3308_ADC_ANA_CON07(1), 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", RK3308_ADC_ANA_CON07(2), 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_EN", RK3308_DAC_ANA_CON13, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_EN", RK3308_DAC_ANA_CON13, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_WORK", RK3308_DAC_ANA_CON13, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_WORK", RK3308_DAC_ANA_CON13, 5, 0, NULL, 0),
+ /* HPMIX is not actually acting as a mixer as the only supported input is I2S */
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_SEL", RK3308_DAC_ANA_CON12, 2, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_SEL", RK3308_DAC_ANA_CON12, 6, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC HPMIX Left", RK3308_DAC_ANA_CON13, 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC HPMIX Right", RK3308_DAC_ANA_CON13, 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_MCLK_GATE", RK3308_GLB_CON, 4, 1, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_CURRENT_EN", RK3308_DAC_ANA_CON00, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_L_REF_EN", RK3308_DAC_ANA_CON02, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_R_REF_EN", RK3308_DAC_ANA_CON02, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_L_CLK_EN", RK3308_DAC_ANA_CON02, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_R_CLK_EN", RK3308_DAC_ANA_CON02, 5, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC_L_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 3, 0),
+ SND_SOC_DAPM_DAC("DAC_R_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 7, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_L", RK3308_DAC_ANA_CON01, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_R", RK3308_DAC_ANA_CON01, 6, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_L", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rk3308_codec_pop_sound_set,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_R", SND_SOC_NOPM, 4, 0, NULL, 0,
+ rk3308_codec_pop_sound_set,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUT_DRV("L_HPOUT_EN", RK3308_DAC_ANA_CON03, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_HPOUT_EN", RK3308_DAC_ANA_CON03, 5, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("L_HPOUT_WORK", RK3308_DAC_ANA_CON03, 2, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_HPOUT_WORK", RK3308_DAC_ANA_CON03, 6, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HPOUT_L"),
+ SND_SOC_DAPM_OUTPUT("HPOUT_R"),
+
+ SND_SOC_DAPM_OUT_DRV("L_LINEOUT_EN", RK3308_DAC_ANA_CON04, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_LINEOUT_EN", RK3308_DAC_ANA_CON04, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT_L"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT_R"),
+};
+
+static const struct snd_soc_dapm_route rk3308_codec_dapm_routes[] = {
+ { "MICBIAS1", NULL, "MICBIAS Current" },
+ { "MICBIAS2", NULL, "MICBIAS Current" },
+
+ { "MIC1_EN", NULL, "MIC1" },
+ { "MIC2_EN", NULL, "MIC2" },
+ { "MIC3_EN", NULL, "MIC3" },
+ { "MIC4_EN", NULL, "MIC4" },
+ { "MIC5_EN", NULL, "MIC5" },
+ { "MIC6_EN", NULL, "MIC6" },
+ { "MIC7_EN", NULL, "MIC7" },
+ { "MIC8_EN", NULL, "MIC8" },
+
+ { "MIC1_WORK", NULL, "MIC1_EN" },
+ { "MIC2_WORK", NULL, "MIC2_EN" },
+ { "MIC3_WORK", NULL, "MIC3_EN" },
+ { "MIC4_WORK", NULL, "MIC4_EN" },
+ { "MIC5_WORK", NULL, "MIC5_EN" },
+ { "MIC6_WORK", NULL, "MIC6_EN" },
+ { "MIC7_WORK", NULL, "MIC7_EN" },
+ { "MIC8_WORK", NULL, "MIC8_EN" },
+
+ { "CH1_IN_SEL", NULL, "MIC1_WORK" },
+ { "CH2_IN_SEL", NULL, "MIC2_WORK" },
+
+ { "ALC1_EN", NULL, "CH1_IN_SEL" },
+ { "ALC2_EN", NULL, "CH2_IN_SEL" },
+ { "ALC3_EN", NULL, "MIC3_WORK" },
+ { "ALC4_EN", NULL, "MIC4_WORK" },
+ { "ALC5_EN", NULL, "MIC5_WORK" },
+ { "ALC6_EN", NULL, "MIC6_WORK" },
+ { "ALC7_EN", NULL, "MIC7_WORK" },
+ { "ALC8_EN", NULL, "MIC8_WORK" },
+
+ { "ADC1_EN", NULL, "ALC1_EN" },
+ { "ADC2_EN", NULL, "ALC2_EN" },
+ { "ADC3_EN", NULL, "ALC3_EN" },
+ { "ADC4_EN", NULL, "ALC4_EN" },
+ { "ADC5_EN", NULL, "ALC5_EN" },
+ { "ADC6_EN", NULL, "ALC6_EN" },
+ { "ADC7_EN", NULL, "ALC7_EN" },
+ { "ADC8_EN", NULL, "ALC8_EN" },
+
+ { "ADC1_WORK", NULL, "ADC1_EN" },
+ { "ADC2_WORK", NULL, "ADC2_EN" },
+ { "ADC3_WORK", NULL, "ADC3_EN" },
+ { "ADC4_WORK", NULL, "ADC4_EN" },
+ { "ADC5_WORK", NULL, "ADC5_EN" },
+ { "ADC6_WORK", NULL, "ADC6_EN" },
+ { "ADC7_WORK", NULL, "ADC7_EN" },
+ { "ADC8_WORK", NULL, "ADC8_EN" },
+
+ { "ADC1_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" },
+ { "ADC2_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" },
+ { "ADC3_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" },
+ { "ADC4_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" },
+ { "ADC5_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" },
+ { "ADC6_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" },
+ { "ADC7_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" },
+ { "ADC8_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" },
+
+ { "ADC1_WORK", NULL, "ADC1_BUF_REF_EN" },
+ { "ADC2_WORK", NULL, "ADC2_BUF_REF_EN" },
+ { "ADC3_WORK", NULL, "ADC3_BUF_REF_EN" },
+ { "ADC4_WORK", NULL, "ADC4_BUF_REF_EN" },
+ { "ADC5_WORK", NULL, "ADC5_BUF_REF_EN" },
+ { "ADC6_WORK", NULL, "ADC6_BUF_REF_EN" },
+ { "ADC7_WORK", NULL, "ADC7_BUF_REF_EN" },
+ { "ADC8_WORK", NULL, "ADC8_BUF_REF_EN" },
+
+ { "ADC1_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC2_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC3_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC4_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC5_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC6_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC7_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC8_CLK_EN", NULL, "ADC_MCLK_GATE" },
+
+ { "ADC1_WORK", NULL, "ADC1_CLK_EN" },
+ { "ADC2_WORK", NULL, "ADC2_CLK_EN" },
+ { "ADC3_WORK", NULL, "ADC3_CLK_EN" },
+ { "ADC4_WORK", NULL, "ADC4_CLK_EN" },
+ { "ADC5_WORK", NULL, "ADC5_CLK_EN" },
+ { "ADC6_WORK", NULL, "ADC6_CLK_EN" },
+ { "ADC7_WORK", NULL, "ADC7_CLK_EN" },
+ { "ADC8_WORK", NULL, "ADC8_CLK_EN" },
+
+ { "ALC1_WORK", NULL, "ADC1_WORK" },
+ { "ALC2_WORK", NULL, "ADC2_WORK" },
+ { "ALC3_WORK", NULL, "ADC3_WORK" },
+ { "ALC4_WORK", NULL, "ADC4_WORK" },
+ { "ALC5_WORK", NULL, "ADC5_WORK" },
+ { "ALC6_WORK", NULL, "ADC6_WORK" },
+ { "ALC7_WORK", NULL, "ADC7_WORK" },
+ { "ALC8_WORK", NULL, "ADC8_WORK" },
+
+ { "HiFi Capture", NULL, "ALC1_WORK" },
+ { "HiFi Capture", NULL, "ALC2_WORK" },
+ { "HiFi Capture", NULL, "ALC3_WORK" },
+ { "HiFi Capture", NULL, "ALC4_WORK" },
+ { "HiFi Capture", NULL, "ALC5_WORK" },
+ { "HiFi Capture", NULL, "ALC6_WORK" },
+ { "HiFi Capture", NULL, "ALC7_WORK" },
+ { "HiFi Capture", NULL, "ALC8_WORK" },
+
+ { "DAC_L_HPMIX_EN", NULL, "HiFi Playback" },
+ { "DAC_R_HPMIX_EN", NULL, "HiFi Playback" },
+ { "DAC_L_HPMIX_WORK", NULL, "DAC_L_HPMIX_EN" },
+ { "DAC_R_HPMIX_WORK", NULL, "DAC_R_HPMIX_EN" },
+ { "DAC HPMIX Left", NULL, "DAC_L_HPMIX_WORK" },
+ { "DAC HPMIX Right", NULL, "DAC_R_HPMIX_WORK" },
+
+ { "DAC_L_DAC_WORK", NULL, "DAC HPMIX Left" },
+ { "DAC_R_DAC_WORK", NULL, "DAC HPMIX Right" },
+
+ { "DAC_L_REF_EN", NULL, "DAC_CURRENT_EN" },
+ { "DAC_R_REF_EN", NULL, "DAC_CURRENT_EN" },
+ { "DAC_L_CLK_EN", NULL, "DAC_L_REF_EN" },
+ { "DAC_R_CLK_EN", NULL, "DAC_R_REF_EN" },
+ { "DAC_L_CLK_EN", NULL, "DAC_MCLK_GATE" },
+ { "DAC_R_CLK_EN", NULL, "DAC_MCLK_GATE" },
+ { "DAC_L_DAC_WORK", NULL, "DAC_L_CLK_EN" },
+ { "DAC_R_DAC_WORK", NULL, "DAC_R_CLK_EN" },
+ { "DAC_L_HPMIX_SEL", NULL, "DAC_L_DAC_WORK" },
+ { "DAC_R_HPMIX_SEL", NULL, "DAC_R_DAC_WORK" },
+
+ { "HPOUT_L", NULL, "DAC_BUF_REF_L" },
+ { "HPOUT_R", NULL, "DAC_BUF_REF_R" },
+ { "L_HPOUT_EN", NULL, "DAC_L_HPMIX_SEL" },
+ { "R_HPOUT_EN", NULL, "DAC_R_HPMIX_SEL" },
+ { "L_HPOUT_WORK", NULL, "L_HPOUT_EN" },
+ { "R_HPOUT_WORK", NULL, "R_HPOUT_EN" },
+ { "HPOUT_POP_SOUND_L", NULL, "L_HPOUT_WORK" },
+ { "HPOUT_POP_SOUND_R", NULL, "R_HPOUT_WORK" },
+ { "HPOUT_L", NULL, "HPOUT_POP_SOUND_L" },
+ { "HPOUT_R", NULL, "HPOUT_POP_SOUND_R" },
+
+ { "L_LINEOUT_EN", NULL, "DAC_L_HPMIX_SEL" },
+ { "R_LINEOUT_EN", NULL, "DAC_R_HPMIX_SEL" },
+ { "LINEOUT_L", NULL, "L_LINEOUT_EN" },
+ { "LINEOUT_R", NULL, "R_LINEOUT_EN" },
+};
+
+static int rk3308_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+ const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK;
+ const bool inv_bitclk =
+ (inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+ (inv_bits & SND_SOC_DAIFMT_IB_NF);
+ const bool inv_frmclk =
+ (inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+ (inv_bits & SND_SOC_DAIFMT_NB_IF);
+ const unsigned int dac_master_bits = rk3308->codec_ver < ACODEC_VERSION_C ?
+ RK3308_DAC_IO_MODE_MASTER | RK3308_DAC_MODE_MASTER :
+ RK3308BS_DAC_IO_MODE_MASTER | RK3308BS_DAC_MODE_MASTER;
+ unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
+ bool is_master = false;
+ int grp;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ adc_aif2 |= RK3308_ADC_IO_MODE_MASTER;
+ adc_aif2 |= RK3308_ADC_MODE_MASTER;
+ dac_aif2 |= dac_master_bits;
+ is_master = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_PCM;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_PCM;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_I2S;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_RJ;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_RJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_LJ;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_LJ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (inv_bitclk) {
+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL;
+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL;
+ }
+
+ if (inv_frmclk) {
+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL;
+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL;
+ }
+
+ /*
+ * Hold ADC Digital registers start at master mode
+ *
+ * There are 8 ADCs which use the same internal SCLK and LRCK for
+ * master mode. We need to make sure that they are in effect at the
+ * same time, otherwise they will cause abnormal clocks.
+ */
+ if (is_master)
+ regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+ RK3308_ADC_I2S_LRC_POL_REVERSAL |
+ RK3308_ADC_I2S_MODE_MSK,
+ adc_aif1);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp),
+ RK3308_ADC_IO_MODE_MASTER |
+ RK3308_ADC_MODE_MASTER |
+ RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL,
+ adc_aif2);
+ }
+
+ /* Hold ADC Digital registers end at master mode */
+ if (is_master)
+ regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+ RK3308_DAC_I2S_LRC_POL_REVERSAL |
+ RK3308_DAC_I2S_MODE_MSK,
+ dac_aif1);
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02,
+ dac_master_bits | RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL,
+ dac_aif2);
+
+ return 0;
+}
+
+static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int dac_aif1 = 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+ RK3308_DAC_I2S_VALID_LEN_MSK, dac_aif1);
+ regmap_set_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, RK3308_DAC_I2S_WORK);
+
+ return 0;
+}
+
+static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int adc_aif1 = 0;
+ /*
+ * grp 0 = ADC1 and ADC2
+ * grp 1 = ADC3 and ADC4
+ * grp 2 = ADC5 and ADC6
+ * grp 3 = ADC7 and ADC8
+ */
+ u32 used_adc_grps;
+ int grp;
+
+ switch (params_channels(params)) {
+ case 1:
+ adc_aif1 |= RK3308_ADC_I2S_MONO;
+ used_adc_grps = 1;
+ break;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ used_adc_grps = params_channels(params) / 2;
+ break;
+ default:
+ dev_err(rk3308->dev, "Invalid channel number %d\n", params_channels(params));
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (grp = 0; grp < used_adc_grps; grp++) {
+ regmap_update_bits(rk3308->regmap,
+ RK3308_ADC_DIG_CON03(grp),
+ RK3308_ADC_L_CH_BIST_MSK | RK3308_ADC_R_CH_BIST_MSK,
+ RK3308_ADC_L_CH_NORMAL_LEFT | RK3308_ADC_R_CH_NORMAL_RIGHT);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+ RK3308_ADC_I2S_VALID_LEN_MSK | RK3308_ADC_I2S_MONO, adc_aif1);
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), RK3308_ADC_I2S_WORK);
+ }
+
+ return 0;
+}
+
+static int rk3308_codec_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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ return (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ rk3308_codec_dac_dig_config(rk3308, params) :
+ rk3308_codec_adc_dig_config(rk3308, params);
+}
+
+static const struct snd_soc_dai_ops rk3308_codec_dai_ops = {
+ .hw_params = rk3308_codec_hw_params,
+ .set_fmt = rk3308_codec_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver rk3308_codec_dai_driver = {
+ .name = "rk3308-hifi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ },
+ .ops = &rk3308_codec_dai_ops,
+};
+
+static void rk3308_codec_reset(struct snd_soc_component *component)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ reset_control_assert(rk3308->reset);
+ usleep_range(10000, 11000); /* estimated value */
+ reset_control_deassert(rk3308->reset);
+
+ regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00);
+ usleep_range(10000, 11000); /* estimated value */
+ regmap_write(rk3308->regmap, RK3308_GLB_CON,
+ RK3308_SYS_WORK |
+ RK3308_DAC_DIG_WORK |
+ RK3308_ADC_DIG_WORK);
+}
+
+/*
+ * Initialize register whose default after HW reset is problematic or which
+ * are never modified.
+ */
+static int rk3308_codec_initialize(struct rk3308_codec_priv *rk3308)
+{
+ int grp;
+
+ /*
+ * Init ADC digital vol to 0 dB (reset value is 0xff, undocumented).
+ * Range: -97dB ~ +32dB.
+ */
+ if (rk3308->codec_ver == ACODEC_VERSION_C) {
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+ regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON05(grp),
+ RK3308_ADC_DIG_VOL_CON_x_0DB);
+ regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON06(grp),
+ RK3308_ADC_DIG_VOL_CON_x_0DB);
+ }
+ }
+
+ /* set HPMIX default gains (reset value is 0, which is illegal) */
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
+ RK3308_DAC_L_HPMIX_GAIN_MSK |
+ RK3308_DAC_R_HPMIX_GAIN_MSK,
+ RK3308_DAC_L_HPMIX_GAIN_NDB_6 |
+ RK3308_DAC_R_HPMIX_GAIN_NDB_6);
+
+ /* recover DAC digital gain to 0 dB (reset value is 0xff, undocumented) */
+ if (rk3308->codec_ver == ACODEC_VERSION_C)
+ regmap_write(rk3308->regmap, RK3308_DAC_DIG_CON04,
+ RK3308BS_DAC_DIG_GAIN_0DB);
+
+ /*
+ * Unconditionally enable zero-cross detection (needed for AGC,
+ * harmless without AGC)
+ */
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++)
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+ RK3308_ADC_CH1_ZEROCROSS_DET_EN |
+ RK3308_ADC_CH2_ZEROCROSS_DET_EN);
+
+ return 0;
+}
+
+static int rk3308_codec_probe(struct snd_soc_component *component)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ rk3308->component = component;
+
+ rk3308_codec_reset(component);
+ rk3308_codec_initialize(rk3308);
+
+ return 0;
+}
+
+static int rk3308_codec_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_OFF)
+ break;
+
+ /* Sequence from TRM Section 8.6.3 "Power Up" */
+ regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+ RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 1);
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_REF_EN);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 0x7f);
+ msleep(20); /* estimated value */
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* Sequence from TRM Section 8.6.4 "Power Down" */
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 1);
+ regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_REF_EN);
+ regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+ RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
+ msleep(20); /* estimated value */
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_component_driver rk3308_codec_component_driver = {
+ .probe = rk3308_codec_probe,
+ .set_bias_level = rk3308_codec_set_bias_level,
+ .controls = rk3308_codec_controls,
+ .num_controls = ARRAY_SIZE(rk3308_codec_controls),
+ .dapm_widgets = rk3308_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rk3308_codec_dapm_widgets),
+ .dapm_routes = rk3308_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rk3308_codec_dapm_routes),
+};
+
+static const struct regmap_config rk3308_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = RK3308_DAC_ANA_CON15,
+};
+
+static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308)
+{
+ unsigned int chip_id;
+ int err;
+
+ err = regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id);
+ if (err)
+ return err;
+
+ switch (chip_id) {
+ case 3306:
+ rk3308->codec_ver = ACODEC_VERSION_A;
+ break;
+ case 0x3308:
+ rk3308->codec_ver = ACODEC_VERSION_B;
+ return dev_err_probe(rk3308->dev, -EINVAL, "Chip version B not supported\n");
+ case 0x3308c:
+ rk3308->codec_ver = ACODEC_VERSION_C;
+ break;
+ default:
+ return dev_err_probe(rk3308->dev, -EINVAL, "Unknown chip_id: 0x%x\n", chip_id);
+ }
+
+ dev_info(rk3308->dev, "Found codec version %c\n", rk3308->codec_ver);
+ return 0;
+}
+
+static int rk3308_codec_set_micbias_level(struct rk3308_codec_priv *rk3308)
+{
+ struct device_node *np = rk3308->dev->of_node;
+ u32 percent;
+ u32 mult;
+ int err;
+
+ err = of_property_read_u32(np, "rockchip,micbias-avdd-percent", &percent);
+ if (err == -EINVAL)
+ return 0;
+ if (err)
+ return dev_err_probe(rk3308->dev, err,
+ "Error reading 'rockchip,micbias-avdd-percent'\n");
+
+ /* Convert percent to register value, linerarly (50% -> 0, 5% step = +1) */
+ mult = (percent - 50) / 5;
+
+ /* Check range and that the percent was an exact value allowed */
+ if (mult > RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX || mult * 5 + 50 != percent)
+ return dev_err_probe(rk3308->dev, -EINVAL,
+ "Invalid value %u for 'rockchip,micbias-avdd-percent'\n",
+ percent);
+
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0),
+ RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK,
+ mult << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT);
+
+ return 0;
+}
+
+static int rk3308_codec_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct rk3308_codec_priv *rk3308;
+ void __iomem *base;
+ int err;
+
+ rk3308 = devm_kzalloc(&pdev->dev, sizeof(*rk3308), GFP_KERNEL);
+ if (!rk3308)
+ return -ENOMEM;
+
+ rk3308->dev = dev;
+
+ rk3308->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(rk3308->grf))
+ return dev_err_probe(dev, PTR_ERR(rk3308->grf), "Error getting GRF\n");
+
+ rk3308->reset = devm_reset_control_get_optional_exclusive(dev, "codec");
+ if (IS_ERR(rk3308->reset))
+ return dev_err_probe(dev, PTR_ERR(rk3308->reset), "Failed to get reset control\n");
+
+ err = devm_clk_bulk_get(dev, ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to get clocks\n");
+
+ err = clk_bulk_prepare_enable(ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable clocks\n");
+
+ err = rk3308_codec_get_version(rk3308);
+ if (err)
+ return err;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rk3308->regmap = devm_regmap_init_mmio(dev, base, &rk3308_codec_regmap_config);
+ if (IS_ERR(rk3308->regmap))
+ return dev_err_probe(dev, PTR_ERR(rk3308->regmap),
+ "Failed to init regmap\n");
+
+ platform_set_drvdata(pdev, rk3308);
+
+ err = rk3308_codec_set_micbias_level(rk3308);
+ if (err)
+ return err;
+
+ err = devm_snd_soc_register_component(dev, &rk3308_codec_component_driver,
+ &rk3308_codec_dai_driver, 1);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to register codec\n");
+
+ return 0;
+}
+
+static const struct of_device_id rk3308_codec_of_match[] = {
+ { .compatible = "rockchip,rk3308-codec", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rk3308_codec_of_match);
+
+static struct platform_driver rk3308_codec_driver = {
+ .driver = {
+ .name = "rk3308-acodec",
+ .of_match_table = of_match_ptr(rk3308_codec_of_match),
+ },
+ .probe = rk3308_codec_platform_probe,
+};
+module_platform_driver(rk3308_codec_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
+MODULE_DESCRIPTION("ASoC RK3308 Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h
new file mode 100644
index 000000000000..a4226b235ab7
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.h
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Rockchip RK3308 internal audio codec driver -- register definitions
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2022, Vivax-Metrotech Ltd
+ */
+
+#ifndef __RK3308_CODEC_H__
+#define __RK3308_CODEC_H__
+
+#define RK3308_GLB_CON 0x00
+
+/* ADC DIGITAL REGISTERS */
+
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_DIG_OFFSET(ch) (((ch) & 0x3) * 0xc0 + 0x0)
+
+#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x14) // ver.C only
+#define RK3308_ADC_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x18) // ver.C only
+#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x1c)
+
+#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x40)
+#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x44)
+#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x48)
+#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x4c)
+#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x50)
+#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x54)
+#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x58)
+#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x5c)
+#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x60)
+#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x64)
+#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x70)
+
+#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x80)
+#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x84)
+#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x88)
+#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x8c)
+#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x90)
+#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x94)
+#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x98)
+#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x9c)
+#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa0)
+#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa4)
+#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xb0)
+
+/* DAC DIGITAL REGISTERS */
+#define RK3308_DAC_DIG_OFFSET 0x300
+#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + 0x04)
+#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + 0x08)
+#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + 0x0c)
+#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + 0x10)
+#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + 0x14)
+#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + 0x28)
+#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + 0x2c)
+#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + 0x34)
+#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + 0x38)
+
+/* ADC ANALOG REGISTERS */
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_ANA_OFFSET(ch) (((ch) & 0x3) * 0x40 + 0x340)
+#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x00)
+#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x14)
+#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x18)
+#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x1c)
+#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x20)
+#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x28)
+#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x2c)
+
+/* DAC ANALOG REGISTERS */
+#define RK3308_DAC_ANA_OFFSET 0x440
+#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + 0x00)
+#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + 0x04)
+#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + 0x08)
+#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + 0x0c)
+#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + 0x10)
+#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + 0x14)
+#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + 0x18)
+#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + 0x1c)
+#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + 0x20)
+#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + 0x30)
+#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + 0x34)
+#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + 0x38)
+#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + 0x3c)
+
+/*
+ * These are the bits for registers
+ */
+
+/* RK3308_GLB_CON - REG: 0x0000 */
+#define RK3308_ADC_BIST_WORK BIT(7)
+#define RK3308_DAC_BIST_WORK BIT(6)
+#define RK3308_ADC_MCLK_GATING BIT(5)
+#define RK3308_DAC_MCLK_GATING BIT(4)
+#define RK3308_ADC_DIG_WORK BIT(2)
+#define RK3308_DAC_DIG_WORK BIT(1)
+#define RK3308_SYS_WORK BIT(0)
+
+/* RK3308_ADC_DIG_CON01 - REG: 0x0004 */
+#define RK3308_ADC_I2S_LRC_POL_REVERSAL BIT(7)
+#define RK3308_ADC_I2S_VALID_LEN_SFT 5
+#define RK3308_ADC_I2S_VALID_LEN_MSK (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_32BITS (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_24BITS (0x2 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_20BITS (0x1 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_16BITS (0x0 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_MODE_SFT 3
+#define RK3308_ADC_I2S_MODE_MSK (0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_PCM (0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_I2S (0x2 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_LJ (0x1 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_RJ (0x0 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_LR_SWAP BIT(1)
+#define RK3308_ADC_I2S_MONO BIT(0)
+
+/* RK3308_ADC_DIG_CON02 - REG: 0x0008 */
+#define RK3308_ADC_IO_MODE_MASTER BIT(5)
+#define RK3308_ADC_MODE_MASTER BIT(4)
+#define RK3308_ADC_I2S_FRAME_LEN_SFT 2
+#define RK3308_ADC_I2S_FRAME_LEN_MSK (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_32BITS (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_24BITS (0x2 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_20BITS (0x1 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_16BITS (0x0 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_WORK BIT(1)
+#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL BIT(0)
+
+/* RK3308_ADC_DIG_CON03 - REG: 0x000c */
+#define RK3308_ADC_L_CH_BIST_SFT 2
+#define RK3308_ADC_L_CH_BIST_MSK (0x3 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_RIGHT (0x3 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_L_CH_BIST_CUBE (0x2 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_BIST_SINE (0x1 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_LEFT (0x0 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_SFT 0
+#define RK3308_ADC_R_CH_BIST_MSK (0x3 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_LEFT (0x3 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_CUBE (0x2 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_BIST_SINE (0x1 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_RIGHT (0x0 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_ADC_DIG_CON04 - REG: 0x0010 */
+#define RK3308_ADC_HPF_PATH_DIS BIT(2)
+#define RK3308_ADC_HPF_CUTOFF_SFT 0
+#define RK3308_ADC_HPF_CUTOFF_MSK (0x3 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_612HZ (0x2 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_245HZ (0x1 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_20HZ (0x0 << RK3308_ADC_HPF_CUTOFF_SFT)
+
+/* RK3308_ADC_DIG_CON07 - REG: 0x001c */
+#define RK3308_ADCL_DATA_SFT 4
+#define RK3308_ADCR_DATA_SFT 2
+#define RK3308_ADCL_DATA_SEL_ADCL BIT(1)
+#define RK3308_ADCR_DATA_SEL_ADCR BIT(0)
+
+/*
+ * RK3308_ALC_L_DIG_CON00 - REG: 0x0040 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON00 - REG: 0x0080 + ch * 0xc0
+ */
+#define RK3308_GAIN_ATTACK_JACK BIT(6)
+#define RK3308_CTRL_GEN_SFT 4
+#define RK3308_CTRL_GEN_MSK (0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK3 (0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK2 (0x2 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK1 (0x1 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_NORMAL (0x0 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_AGC_HOLD_TIME_SFT 0
+#define RK3308_AGC_HOLD_TIME_MSK (0xf << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_1S (0xa << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_512MS (0x9 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_256MS (0x8 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_128MS (0x7 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_64MS (0x6 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_32MS (0x5 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_16MS (0x4 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_8MS (0x3 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_4MS (0x2 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_2MS (0x1 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_0MS (0x0 << RK3308_AGC_HOLD_TIME_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON01 - REG: 0x0044 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON01 - REG: 0x0084 + ch * 0xc0
+ */
+#define RK3308_AGC_DECAY_TIME_SFT 4
+#define RK3308_AGC_ATTACK_TIME_SFT 0
+
+/*
+ * RK3308_ALC_L_DIG_CON02 - REG: 0x0048 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON02 - REG: 0x0088 + ch * 0xc0
+ */
+#define RK3308_AGC_MODE_LIMITER BIT(7)
+#define RK3308_AGC_ZERO_CRO_EN BIT(6)
+#define RK3308_AGC_AMP_RECOVER_GAIN BIT(5)
+#define RK3308_AGC_FAST_DEC_EN BIT(4)
+#define RK3308_AGC_NOISE_GATE_EN BIT(3)
+#define RK3308_AGC_NOISE_GATE_THRESH_SFT 0
+#define RK3308_AGC_NOISE_GATE_THRESH_MSK (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON03 - REG: 0x004c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON03 - REG: 0x008c + ch * 0xc0
+ */
+#define RK3308_AGC_PGA_ZERO_CRO_EN BIT(5)
+#define RK3308_AGC_PGA_GAIN_MAX 0x1f
+#define RK3308_AGC_PGA_GAIN_MIN 0
+#define RK3308_AGC_PGA_GAIN_SFT 0
+
+/*
+ * RK3308_ALC_L_DIG_CON04 - REG: 0x0050 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON04 - REG: 0x0090 + ch * 0xc0
+ */
+#define RK3308_AGC_SLOW_CLK_EN BIT(3)
+#define RK3308_AGC_APPROX_RATE_SFT 0
+#define RK3308_AGC_APPROX_RATE_MSK (0x7 << RK3308_AGC_APPROX_RATE_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON05 - REG: 0x0054 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON05 - REG: 0x0094 + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MAX_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON06 - REG: 0x0058 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON06 - REG: 0x0098 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MAX_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON07 - REG: 0x005c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON07 - REG: 0x009c + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MIN_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON08 - REG: 0x0060 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON08 - REG: 0x00a0 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MIN_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON09 - REG: 0x0064 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON09 - REG: 0x00a4 + ch * 0xc0
+ */
+#define RK3308_AGC_FUNC_SEL BIT(6)
+#define RK3308_AGC_MAX_GAIN_PGA_MAX 0x7
+#define RK3308_AGC_MAX_GAIN_PGA_MIN 0
+#define RK3308_AGC_MAX_GAIN_PGA_SFT 3
+#define RK3308_AGC_MAX_GAIN_PGA_MSK (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT)
+#define RK3308_AGC_MIN_GAIN_PGA_MAX 0x7
+#define RK3308_AGC_MIN_GAIN_PGA_MIN 0
+#define RK3308_AGC_MIN_GAIN_PGA_SFT 0
+#define RK3308_AGC_MIN_GAIN_PGA_MSK (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON12 - REG: 0x0068 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON12 - REG: 0x00a8 + ch * 0xc0
+ */
+#define RK3308_AGC_GAIN_MSK 0x1f
+
+/* RK3308_DAC_DIG_CON01 - REG: 0x0304 */
+#define RK3308_DAC_I2S_LRC_POL_REVERSAL BIT(7)
+#define RK3308_DAC_I2S_VALID_LEN_SFT 5
+#define RK3308_DAC_I2S_VALID_LEN_MSK (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_32BITS (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_24BITS (0x2 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_20BITS (0x1 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_16BITS (0x0 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_MODE_SFT 3
+#define RK3308_DAC_I2S_MODE_MSK (0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_PCM (0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_I2S (0x2 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_LJ (0x1 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_RJ (0x0 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_LR_SWAP BIT(2)
+
+/* RK3308_DAC_DIG_CON02 - REG: 0x0308 */
+#define RK3308BS_DAC_IO_MODE_MASTER BIT(7)
+#define RK3308BS_DAC_MODE_MASTER BIT(6)
+#define RK3308_DAC_IO_MODE_MASTER BIT(5)
+#define RK3308_DAC_MODE_MASTER BIT(4)
+#define RK3308_DAC_I2S_FRAME_LEN_SFT 2
+#define RK3308_DAC_I2S_FRAME_LEN_MSK (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_32BITS (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_24BITS (0x2 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_20BITS (0x1 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_16BITS (0x0 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_WORK BIT(1)
+#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL BIT(0)
+
+/* RK3308_DAC_DIG_CON03 - REG: 0x030C */
+#define RK3308_DAC_L_CH_BIST_SFT 2
+#define RK3308_DAC_L_CH_BIST_MSK (0x3 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_LEFT (0x3 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_L_CH_BIST_CUBE (0x2 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_SINE (0x1 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_RIGHT (0x0 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_SFT 0
+#define RK3308_DAC_R_CH_BIST_MSK (0x3 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_LEFT (0x3 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_CUBE (0x2 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_SINE (0x1 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_RIGHT (0x0 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_DAC_DIG_CON04 - REG: 0x0310 */
+/* Versions up to B: */
+#define RK3308_DAC_MODULATOR_GAIN_SFT 4
+#define RK3308_DAC_MODULATOR_GAIN_MSK (0x7 << RK3308_DAC_MODULATOR_GAIN_SFT)
+#define RK3308_DAC_CIC_IF_GAIN_SFT 0
+#define RK3308_DAC_CIC_IF_GAIN_MSK (0x7 << RK3308_DAC_CIC_IF_GAIN_SFT)
+/* Version C: */
+#define RK3308BS_DAC_DIG_GAIN_SFT 0
+#define RK3308BS_DAC_DIG_GAIN_MSK (0xff << RK3308BS_DAC_DIG_GAIN_SFT)
+#define RK3308BS_DAC_DIG_GAIN_0DB (0xed << RK3308BS_DAC_DIG_GAIN_SFT)
+
+/* RK3308BS_ADC_DIG_CON05..06 (Version C only) */
+#define RK3308_ADC_DIG_VOL_CON_x_SFT 0
+#define RK3308_ADC_DIG_VOL_CON_x_MSK (0xff << RK3308_ADC_DIG_VOL_CON_x_SFT)
+#define RK3308_ADC_DIG_VOL_CON_x_0DB (0xc2 << RK3308_ADC_DIG_VOL_CON_x_SFT)
+
+/* RK3308_DAC_DIG_CON05 - REG: 0x0314 */
+#define RK3308_DAC_L_REG_CTL_INDATA BIT(2)
+#define RK3308_DAC_R_REG_CTL_INDATA BIT(1)
+
+/* RK3308_DAC_DIG_CON10 - REG: 0x0328 */
+#define RK3308_DAC_DATA_HI4(x) ((x) & 0xf)
+
+/* RK3308_DAC_DIG_CON11 - REG: 0x032c */
+#define RK3308_DAC_DATA_LO8(x) ((x) & 0xff)
+
+/* RK3308_ADC_ANA_CON00 - REG: 0x0340 */
+#define RK3308_ADC_CH1_CH2_MIC_ALL_MSK (0xff << 0)
+#define RK3308_ADC_CH1_CH2_MIC_ALL 0xff
+#define RK3308_ADC_CH2_MIC_UNMUTE BIT(7)
+#define RK3308_ADC_CH2_MIC_WORK BIT(6)
+#define RK3308_ADC_CH2_MIC_EN BIT(5)
+#define RK3308_ADC_CH2_BUF_REF_EN BIT(4)
+#define RK3308_ADC_CH1_MIC_UNMUTE BIT(3)
+#define RK3308_ADC_CH1_MIC_WORK BIT(2)
+#define RK3308_ADC_CH1_MIC_EN BIT(1)
+#define RK3308_ADC_CH1_BUF_REF_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON01 - REG: 0x0344
+ *
+ * The PGA of MIC-INs:
+ * - HW version A:
+ * 0x0 - MIC1~MIC8 0 dB (recommended when ADC used as loopback)
+ * 0x3 - MIC1~MIC8 20 dB (recommended when ADC used as MIC input)
+ * - HW version B:
+ * 0x0 - MIC1~MIC8 0 dB
+ * 0x1 - MIC1~MIC8 6.6 dB
+ * 0x2 - MIC1~MIC8 13 dB
+ * 0x3 - MIC1~MIC8 20 dB
+ */
+#define RK3308_ADC_CH2_MIC_GAIN_MAX 0x3
+#define RK3308_ADC_CH2_MIC_GAIN_MIN 0
+#define RK3308_ADC_CH2_MIC_GAIN_SFT 4
+#define RK3308_ADC_CH2_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+
+#define RK3308_ADC_CH1_MIC_GAIN_MAX 0x3
+#define RK3308_ADC_CH1_MIC_GAIN_MIN 0
+#define RK3308_ADC_CH1_MIC_GAIN_SFT 0
+#define RK3308_ADC_CH1_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON02 - REG: 0x0348 */
+#define RK3308_ADC_CH2_ZEROCROSS_DET_EN BIT(6)
+#define RK3308_ADC_CH2_ALC_WORK BIT(5)
+#define RK3308_ADC_CH2_ALC_EN BIT(4)
+#define RK3308_ADC_CH1_ZEROCROSS_DET_EN BIT(2)
+#define RK3308_ADC_CH1_ALC_WORK BIT(1)
+#define RK3308_ADC_CH1_ALC_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON03 - REG: 0x034c */
+#define RK3308_ADC_CH1_ALC_GAIN_MAX 0x1f
+#define RK3308_ADC_CH1_ALC_GAIN_MIN 0
+#define RK3308_ADC_CH1_ALC_GAIN_SFT 0
+#define RK3308_ADC_CH1_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT)
+#define RK3308_ADC_CH1_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH1_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON04 - REG: 0x0350 */
+#define RK3308_ADC_CH2_ALC_GAIN_MAX 0x1f
+#define RK3308_ADC_CH2_ALC_GAIN_MIN 0
+#define RK3308_ADC_CH2_ALC_GAIN_SFT 0
+#define RK3308_ADC_CH2_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT)
+#define RK3308_ADC_CH2_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH2_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON05 - REG: 0x0354 */
+#define RK3308_ADC_CH2_ADC_WORK BIT(6)
+#define RK3308_ADC_CH2_ADC_EN BIT(5)
+#define RK3308_ADC_CH2_CLK_EN BIT(4)
+#define RK3308_ADC_CH1_ADC_WORK BIT(2)
+#define RK3308_ADC_CH1_ADC_EN BIT(1)
+#define RK3308_ADC_CH1_CLK_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON06 - REG: 0x0358 */
+#define RK3308_ADC_CURRENT_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON07 - REG: 0x035c */
+/* Note: The register configuration is only valid for ADC2 */
+#define RK3308_ADC_CH2_IN_SEL_SFT 6
+#define RK3308_ADC_CH2_IN_SEL_MSK (0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN_MIC (0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN (0x2 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_MIC (0x1 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_NONE (0x0 << RK3308_ADC_CH2_IN_SEL_SFT)
+/* Note: The register configuration is only valid for ADC1 */
+#define RK3308_ADC_CH1_IN_SEL_SFT 4
+#define RK3308_ADC_CH1_IN_SEL_MSK (0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN_MIC (0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN (0x2 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_MIC (0x1 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_NONE (0x0 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_MIC_BIAS_BUF_EN BIT(3)
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX 7
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT 0
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT)
+
+/* RK3308_ADC_ANA_CON08 - REG: 0x0360 */
+#define RK3308_ADC_MICBIAS_CURRENT_EN BIT(4)
+
+/* RK3308_ADC_ANA_CON10 - REG: 0x0368 */
+#define RK3308_ADC_REF_EN BIT(7)
+#define RK3308_ADC_CURRENT_CHARGE_SFT 0
+#define RK3308_ADC_CURRENT_CHARGE_MSK (0x7f << RK3308_ADC_CURRENT_CHARGE_SFT)
+
+/* RK3308_ADC_ANA_CON11 - REG: 0x036c */
+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN BIT(1)
+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON00 - REG: 0x0440 */
+#define RK3308_DAC_HEADPHONE_DET_EN BIT(1)
+#define RK3308_DAC_CURRENT_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON01 - REG: 0x0444 */
+#define RK3308_DAC_BUF_REF_R_EN BIT(6)
+#define RK3308_DAC_BUF_REF_L_EN BIT(2)
+#define RK3308_DAC_HPOUT_POP_SOUND_R_SFT 4
+#define RK3308_DAC_HPOUT_POP_SOUND_L_SFT 0
+// unshifted values for both L and R:
+#define RK3308_DAC_HPOUT_POP_SOUND_x_MSK 0x3
+#define RK3308_DAC_HPOUT_POP_SOUND_x_WORK 0x2
+#define RK3308_DAC_HPOUT_POP_SOUND_x_INIT 0x1
+
+/* RK3308_DAC_ANA_CON02 - REG: 0x0448 */
+#define RK3308_DAC_R_DAC_WORK BIT(7)
+#define RK3308_DAC_R_DAC_EN BIT(6)
+#define RK3308_DAC_R_CLK_EN BIT(5)
+#define RK3308_DAC_R_REF_EN BIT(4)
+#define RK3308_DAC_L_DAC_WORK BIT(3)
+#define RK3308_DAC_L_DAC_EN BIT(2)
+#define RK3308_DAC_L_CLK_EN BIT(1)
+#define RK3308_DAC_L_REF_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON03 - REG: 0x044c */
+#define RK3308_DAC_R_HPOUT_WORK BIT(6)
+#define RK3308_DAC_R_HPOUT_EN BIT(5)
+#define RK3308_DAC_R_HPOUT_MUTE_SFT 4
+#define RK3308_DAC_L_HPOUT_WORK BIT(2)
+#define RK3308_DAC_L_HPOUT_EN BIT(1)
+#define RK3308_DAC_L_HPOUT_MUTE_SFT 0
+
+/* RK3308_DAC_ANA_CON04 - REG: 0x0450 */
+#define RK3308_DAC_x_LINEOUT_GAIN_MAX 0x3
+#define RK3308_DAC_R_LINEOUT_GAIN_SFT 6
+#define RK3308_DAC_R_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_MUTE_SFT 5
+#define RK3308_DAC_R_LINEOUT_EN BIT(4)
+#define RK3308_DAC_L_LINEOUT_GAIN_SFT 2
+#define RK3308_DAC_L_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_MUTE_SFT 1
+#define RK3308_DAC_L_LINEOUT_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON05 - REG: 0x0454, step is 1.5db */
+/* RK3308_DAC_ANA_CON06 - REG: 0x0458, step is 1.5db */
+#define RK3308_DAC_x_HPOUT_GAIN_MAX 0x1e
+#define RK3308_DAC_x_HPOUT_GAIN_SFT 0
+#define RK3308_DAC_x_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_x_HPOUT_GAIN_SFT)
+#define RK3308_DAC_x_HPOUT_GAIN_MIN (0x00 << RK3308_DAC_x_HPOUT_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON07 - REG: 0x045c */
+#define RK3308_DAC_R_HPOUT_DRV_SFT 4
+#define RK3308_DAC_R_HPOUT_DRV_MSK (0xf << RK3308_DAC_R_HPOUT_DRV_SFT)
+#define RK3308_DAC_L_HPOUT_DRV_SFT 0
+#define RK3308_DAC_L_HPOUT_DRV_MSK (0xf << RK3308_DAC_L_HPOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON08 - REG: 0x0460 */
+#define RK3308_DAC_R_LINEOUT_DRV_SFT 4
+#define RK3308_DAC_R_LINEOUT_DRV_MSK (0xf << RK3308_DAC_R_LINEOUT_DRV_SFT)
+#define RK3308_DAC_L_LINEOUT_DRV_SFT 0
+#define RK3308_DAC_L_LINEOUT_DRV_MSK (0xf << RK3308_DAC_L_LINEOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON12 - REG: 0x0470 */
+#define RK3308_DAC_R_HPMIX_SEL_SFT 6
+#define RK3308_DAC_R_HPMIX_SEL_MSK (0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN (0x2 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_I2S (0x1 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_NONE (0x0 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_SEL_SFT 2
+#define RK3308_DAC_L_HPMIX_SEL_MSK (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN (0x2 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_I2S (0x1 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_NONE (0x0 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_x_HPMIX_GAIN_MIN 0x1 /* 0x0 and 0x3 are reserved */
+#define RK3308_DAC_x_HPMIX_GAIN_MAX 0x2
+#define RK3308_DAC_R_HPMIX_GAIN_SFT 4
+#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_SFT 0
+#define RK3308_DAC_L_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON13 - REG: 0x0474 */
+#define RK3308_DAC_R_HPMIX_UNMUTE BIT(6)
+#define RK3308_DAC_R_HPMIX_WORK BIT(5)
+#define RK3308_DAC_R_HPMIX_EN BIT(4)
+#define RK3308_DAC_L_HPMIX_UNMUTE BIT(2)
+#define RK3308_DAC_L_HPMIX_WORK BIT(1)
+#define RK3308_DAC_L_HPMIX_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON14 - REG: 0x0478 */
+#define RK3308_DAC_VCM_LINEOUT_EN (0x1 << 4)
+#define RK3308_DAC_CURRENT_CHARGE_SFT 0
+#define RK3308_DAC_CURRENT_CHARGE_MSK (0xf << RK3308_DAC_CURRENT_CHARGE_SFT)
+
+/* RK3308_DAC_ANA_CON15 - REG: 0x047C */
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_SFT 4
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_INTERNAL (0x2 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_SFT 0
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_INTERNAL (0x2 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+
+#endif /* __RK3308_CODEC_H__ */
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index 4dbbd8bdaaac..7c8103a0d562 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -809,7 +809,6 @@ static const struct dev_pm_ops rt1017_sdca_pm = {
static struct sdw_driver rt1017_sdca_sdw_driver = {
.driver = {
.name = "rt1017-sdca",
- .owner = THIS_MODULE,
.pm = &rt1017_sdca_pm,
},
.probe = rt1017_sdca_sdw_probe,
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 63d4abf964d4..563df483a466 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -804,7 +804,6 @@ static const struct dev_pm_ops rt1308_pm = {
static struct sdw_driver rt1308_sdw_driver = {
.driver = {
.name = "rt1308",
- .owner = THIS_MODULE,
.pm = &rt1308_pm,
},
.probe = rt1308_sdw_probe,
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 0b3bf920bcab..22f1ed4e03f1 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -781,7 +781,6 @@ static const struct dev_pm_ops rt1316_pm = {
static struct sdw_driver rt1316_sdw_driver = {
.driver = {
.name = "rt1316-sdca",
- .owner = THIS_MODULE,
.pm = &rt1316_pm,
},
.probe = rt1316_sdw_probe,
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index 462c9a4b1be5..319f71f5e60d 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -855,7 +855,6 @@ static const struct dev_pm_ops rt1318_pm = {
static struct sdw_driver rt1318_sdw_driver = {
.driver = {
.name = "rt1318-sdca",
- .owner = THIS_MODULE,
.pm = &rt1318_pm,
},
.probe = rt1318_sdw_probe,
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index f9ee42c13dba..5edf11e136b4 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -798,7 +798,6 @@ static const struct dev_pm_ops rt5682_pm = {
static struct sdw_driver rt5682_sdw_driver = {
.driver = {
.name = "rt5682",
- .owner = THIS_MODULE,
.pm = &rt5682_pm,
},
.probe = rt5682_sdw_probe,
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 52c33d56b143..24cb895b759f 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -558,7 +558,6 @@ static const struct dev_pm_ops rt700_pm = {
static struct sdw_driver rt700_sdw_driver = {
.driver = {
.name = "rt700",
- .owner = THIS_MODULE,
.pm = &rt700_pm,
},
.probe = rt700_sdw_probe,
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index 2636c2eea4bc..f5933d2e085e 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -474,7 +474,6 @@ static const struct dev_pm_ops rt711_sdca_pm = {
static struct sdw_driver rt711_sdca_sdw_driver = {
.driver = {
.name = "rt711-sdca",
- .owner = THIS_MODULE,
.pm = &rt711_sdca_pm,
},
.probe = rt711_sdca_sdw_probe,
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index 0d3b43dd22e6..8ca8bcd177ab 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -569,7 +569,6 @@ static const struct dev_pm_ops rt711_pm = {
static struct sdw_driver rt711_sdw_driver = {
.driver = {
.name = "rt711",
- .owner = THIS_MODULE,
.pm = &rt711_pm,
},
.probe = rt711_sdw_probe,
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 012b79e72cf6..ee5435f3a80a 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -978,7 +978,6 @@ static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
static struct sdw_driver rt712_sdca_dmic_sdw_driver = {
.driver = {
.name = "rt712-sdca-dmic",
- .owner = THIS_MODULE,
.pm = &rt712_sdca_dmic_pm,
},
.probe = rt712_sdca_dmic_sdw_probe,
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 4e9ab3ef135b..ce337db86d1a 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -475,7 +475,6 @@ static const struct dev_pm_ops rt712_sdca_pm = {
static struct sdw_driver rt712_sdca_sdw_driver = {
.driver = {
.name = "rt712-sdca",
- .owner = THIS_MODULE,
.pm = &rt712_sdca_pm,
},
.probe = rt712_sdca_sdw_probe,
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index ee450126106f..d3fb02e8f31a 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -270,7 +270,6 @@ static const struct dev_pm_ops rt715_pm = {
static struct sdw_driver rt715_sdw_driver = {
.driver = {
.name = "rt715-sdca",
- .owner = THIS_MODULE,
.pm = &rt715_pm,
},
.probe = rt715_sdca_sdw_probe,
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
index 3fb7b9adb61d..3a6dfe1f6c48 100644
--- a/sound/soc/codecs/rt715-sdca.c
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -933,7 +933,7 @@ static const struct snd_soc_dai_ops rt715_sdca_ops = {
static struct snd_soc_dai_driver rt715_sdca_dai[] = {
{
- .name = "rt715-aif1",
+ .name = "rt715-sdca-aif1",
.id = RT715_AIF1,
.capture = {
.stream_name = "DP6 Capture",
@@ -945,7 +945,7 @@ static struct snd_soc_dai_driver rt715_sdca_dai[] = {
.ops = &rt715_sdca_ops,
},
{
- .name = "rt715-aif2",
+ .name = "rt715-sdca-aif2",
.id = RT715_AIF2,
.capture = {
.stream_name = "DP4 Capture",
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 7e13868ff99f..24b3443aeb02 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -577,7 +577,6 @@ static const struct dev_pm_ops rt715_pm = {
static struct sdw_driver rt715_sdw_driver = {
.driver = {
.name = "rt715",
- .owner = THIS_MODULE,
.pm = &rt715_pm,
},
.probe = rt715_sdw_probe,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 65d584c1886e..b33da2215ade 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -503,7 +503,6 @@ static const struct dev_pm_ops rt722_sdca_pm = {
static struct sdw_driver rt722_sdca_sdw_driver = {
.driver = {
.name = "rt722-sdca",
- .owner = THIS_MODULE,
.pm = &rt722_sdca_pm,
},
.probe = rt722_sdca_sdw_probe,
diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c
index 5498ff027c58..574c08b14f0c 100644
--- a/sound/soc/codecs/sdw-mockup.c
+++ b/sound/soc/codecs/sdw-mockup.c
@@ -262,7 +262,6 @@ MODULE_DEVICE_TABLE(sdw, sdw_mockup_id);
static struct sdw_driver sdw_mockup_sdw_driver = {
.driver = {
.name = "sdw-mockup",
- .owner = THIS_MODULE,
},
.probe = sdw_mockup_sdw_probe,
.remove = sdw_mockup_sdw_remove,
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index d5976c91766e..92246243ff94 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -56,7 +56,6 @@ MODULE_DEVICE_TABLE(of, aic32x4_of_id);
static struct spi_driver aic32x4_spi_driver = {
.driver = {
.name = "tlv320aic32x4",
- .owner = THIS_MODULE,
.of_match_table = aic32x4_of_id,
},
.probe = aic32x4_spi_probe,
diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c
index deed6ec7e081..f8c1c16eaa0e 100644
--- a/sound/soc/codecs/tlv320aic3x-spi.c
+++ b/sound/soc/codecs/tlv320aic3x-spi.c
@@ -63,7 +63,6 @@ MODULE_DEVICE_TABLE(of, aic3x_of_id);
static struct spi_driver aic3x_spi_driver = {
.driver = {
.name = "tlv320aic3x",
- .owner = THIS_MODULE,
.of_match_table = aic3x_of_id,
},
.probe = aic3x_spi_probe,
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
index 00852f174a69..bc41a0666856 100644
--- a/sound/soc/fsl/fsl_rpmsg.c
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -135,7 +135,6 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-rpmsg",
- .legacy_dai_naming = 1,
};
static const struct fsl_rpmsg_soc_data imx7ulp_data = {
@@ -190,19 +189,40 @@ MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
static int fsl_rpmsg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_dai_driver *dai_drv;
+ const char *dai_name;
struct fsl_rpmsg *rpmsg;
int ret;
+ dai_drv = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+ memcpy(dai_drv, &fsl_rpmsg_dai, sizeof(fsl_rpmsg_dai));
+
rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL);
if (!rpmsg)
return -ENOMEM;
rpmsg->soc_data = of_device_get_match_data(&pdev->dev);
- fsl_rpmsg_dai.playback.rates = rpmsg->soc_data->rates;
- fsl_rpmsg_dai.capture.rates = rpmsg->soc_data->rates;
- fsl_rpmsg_dai.playback.formats = rpmsg->soc_data->formats;
- fsl_rpmsg_dai.capture.formats = rpmsg->soc_data->formats;
+ if (rpmsg->soc_data) {
+ dai_drv->playback.rates = rpmsg->soc_data->rates;
+ dai_drv->capture.rates = rpmsg->soc_data->rates;
+ dai_drv->playback.formats = rpmsg->soc_data->formats;
+ dai_drv->capture.formats = rpmsg->soc_data->formats;
+ }
+
+ /* Use rpmsg channel name as cpu dai name */
+ ret = of_property_read_string(np, "fsl,rpmsg-channel-name", &dai_name);
+ if (ret) {
+ if (ret == -EINVAL) {
+ dai_name = "rpmsg-audio-channel";
+ } else {
+ dev_err(&pdev->dev, "Failed to get rpmsg channel name: %d!\n", ret);
+ return ret;
+ }
+ }
+ dai_drv->name = dai_name;
if (of_property_read_bool(np, "fsl,enable-lpa")) {
rpmsg->enable_lpa = 1;
@@ -236,21 +256,10 @@ static int fsl_rpmsg_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
- &fsl_rpmsg_dai, 1);
+ dai_drv, 1);
if (ret)
goto err_pm_disable;
- rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
- "imx-audio-rpmsg",
- PLATFORM_DEVID_AUTO,
- NULL,
- 0);
- if (IS_ERR(rpmsg->card_pdev)) {
- dev_err(&pdev->dev, "failed to register rpmsg card\n");
- ret = PTR_ERR(rpmsg->card_pdev);
- goto err_pm_disable;
- }
-
return 0;
err_pm_disable:
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index ab6ec1974807..4ca3a16f7ac0 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1401,8 +1401,10 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
goto error_pcm;
} else {
ret = imx_pcm_dma_init(pdev);
- if (ret)
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to init PCM DMA\n");
goto error_pcm;
+ }
}
return 0;
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 289e47c03d40..38aafb8954c7 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -12,6 +12,7 @@
*/
struct imx_audio_rpmsg {
struct platform_device *rpmsg_pdev;
+ struct platform_device *card_pdev;
};
static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
@@ -87,14 +88,24 @@ static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
/* Register platform driver for rpmsg routine */
data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
- IMX_PCM_DRV_NAME,
- PLATFORM_DEVID_AUTO,
+ rpdev->id.name,
+ PLATFORM_DEVID_NONE,
NULL, 0);
if (IS_ERR(data->rpmsg_pdev)) {
dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
ret = PTR_ERR(data->rpmsg_pdev);
}
+ data->card_pdev = platform_device_register_data(&rpdev->dev,
+ "imx-audio-rpmsg",
+ PLATFORM_DEVID_AUTO,
+ rpdev->id.name,
+ strlen(rpdev->id.name) + 1);
+ if (IS_ERR(data->card_pdev)) {
+ dev_err(&rpdev->dev, "failed to register rpmsg card.\n");
+ ret = PTR_ERR(data->card_pdev);
+ }
+
return ret;
}
@@ -105,6 +116,9 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
if (data->rpmsg_pdev)
platform_device_unregister(data->rpmsg_pdev);
+ if (data->card_pdev)
+ platform_device_unregister(data->card_pdev);
+
dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
}
@@ -113,6 +127,7 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
{ .name = "rpmsg-micfil-channel" },
{ },
};
+MODULE_DEVICE_TABLE(rpmsg, imx_audio_rpmsg_id_table);
static struct rpmsg_driver imx_audio_rpmsg_driver = {
.drv.name = "imx_audio_rpmsg",
@@ -126,5 +141,5 @@ module_rpmsg_driver(imx_audio_rpmsg_driver);
MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
-MODULE_ALIAS("platform:imx_audio_rpmsg");
+MODULE_ALIAS("rpmsg:imx_audio_rpmsg");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 6f0d031c1d5f..5b9648f3b087 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -3,7 +3,7 @@
// Copyright 2012 Freescale Semiconductor, Inc.
// Copyright 2012 Linaro Ltd.
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -23,12 +23,11 @@ struct imx_es8328_data {
struct snd_soc_card card;
char codec_dai_name[DAI_NAME_SIZE];
char platform_name[DAI_NAME_SIZE];
- int jack_gpio;
+ struct gpio_desc *jack_gpiod;
};
static struct snd_soc_jack_gpio headset_jack_gpios[] = {
{
- .gpio = -1,
.name = "headset-gpio",
.report = SND_JACK_HEADSET,
.invert = 0,
@@ -54,8 +53,8 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
struct imx_es8328_data, card);
int ret = 0;
- /* Headphone jack detection */
- if (gpio_is_valid(data->jack_gpio)) {
+ if (data->jack_gpiod) {
+ /* Headphone jack detection */
ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone",
SND_JACK_HEADSET | SND_JACK_BTN_0,
&headset_jack,
@@ -64,7 +63,7 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- headset_jack_gpios[0].gpio = data->jack_gpio;
+ headset_jack_gpios[0].desc = data->jack_gpiod;
ret = snd_soc_jack_add_gpios(&headset_jack,
ARRAY_SIZE(headset_jack_gpios),
headset_jack_gpios);
@@ -174,7 +173,11 @@ static int imx_es8328_probe(struct platform_device *pdev)
data->dev = dev;
- data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
+ data->jack_gpiod = devm_gpiod_get_optional(dev, "jack", GPIOD_IN);
+ if (IS_ERR(data->jack_gpiod)) {
+ ret = PTR_ERR(data->jack_gpiod);
+ goto put_device;
+ }
/*
* CPU == Platform
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index fb9244c1e9c5..b84d1dfddba2 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -732,9 +732,6 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
goto fail;
}
- /* platform component name is used by machine driver to link with */
- component->name = info->rpdev->id.name;
-
#ifdef CONFIG_DEBUG_FS
component->debugfs_prefix = "rpmsg";
#endif
@@ -822,9 +819,17 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
imx_rpmsg_pcm_resume)
};
+static const struct platform_device_id imx_rpmsg_pcm_id_table[] = {
+ { .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table);
+
static struct platform_driver imx_pcm_rpmsg_driver = {
.probe = imx_rpmsg_pcm_probe,
.remove_new = imx_rpmsg_pcm_remove,
+ .id_table = imx_rpmsg_pcm_id_table,
.driver = {
.name = IMX_PCM_DRV_NAME,
.pm = &imx_rpmsg_pcm_pm_ops,
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index e5bd63dab10c..0f1ad7ad7d27 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -108,10 +108,8 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card)
static int imx_rpmsg_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link_component *dlc;
- struct device *dev = pdev->dev.parent;
- /* rpmsg_pdev is the platform device for the rpmsg node that probed us */
- struct platform_device *rpmsg_pdev = to_platform_device(dev);
- struct device_node *np = rpmsg_pdev->dev.of_node;
+ struct snd_soc_dai *cpu_dai;
+ struct device_node *np = NULL;
struct of_phandle_args args;
const char *platform_name;
struct imx_rpmsg *data;
@@ -127,10 +125,6 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
goto fail;
}
- ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
- if (ret)
- dev_warn(&pdev->dev, "no reserved DMA memory\n");
-
data->dai.cpus = &dlc[0];
data->dai.num_cpus = 1;
data->dai.platforms = &dlc[1];
@@ -152,6 +146,23 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
*/
data->dai.ignore_pmdown_time = 1;
+ data->dai.cpus->dai_name = pdev->dev.platform_data;
+ cpu_dai = snd_soc_find_dai(data->dai.cpus);
+ if (!cpu_dai) {
+ ret = -EPROBE_DEFER;
+ goto fail;
+ }
+ np = cpu_dai->dev->of_node;
+ if (!np) {
+ dev_err(&pdev->dev, "failed to parse CPU DAI device node\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
+ if (ret)
+ dev_warn(&pdev->dev, "no reserved DMA memory\n");
+
/* Optional codec node */
ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args);
if (ret) {
@@ -170,7 +181,6 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
data->sysclk = clk_get_rate(clk);
}
- data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name))
data->dai.platforms->name = platform_name;
else
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 81077d16d22f..b4876b4f259d 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -752,8 +752,6 @@ int simple_util_init_jack(struct snd_soc_card *card,
if (!prefix)
prefix = "";
- sjack->gpio.gpio = -ENOENT;
-
if (is_hp) {
snprintf(prop, sizeof(prop), "%shp-det", prefix);
pin_name = pin ? pin : "Headphones";
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index f80f79415344..9a02e2b528bc 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -107,7 +107,7 @@ struct avs_spec {
};
struct avs_fw_entry {
- char *name;
+ const char *name;
const struct firmware *fw;
struct list_head node;
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 5c90a6007577..ff3bd1513269 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -85,7 +85,7 @@ static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Internal Mic"),
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 79b4aca41333..4433175814f8 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -54,7 +54,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
if (!dl[i].cpus->dai_name)
return -ENOMEM;
- dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+ dl[i].codecs->name = devm_kstrdup_const(dev, cname, GFP_KERNEL);
if (!dl[i].codecs->name)
return -ENOMEM;
@@ -155,7 +155,7 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
return 0;
}
-static struct snd_soc_dai_link probing_link = {
+static const struct snd_soc_dai_link probing_link = {
.name = "probing-LINK",
.id = -1,
.nonatomic = 1,
@@ -191,7 +191,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
if (!binder->platforms || !binder->codecs)
return -ENOMEM;
- binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+ binder->codecs->name = devm_kstrdup_const(dev, dev_name(&codec->core.dev), GFP_KERNEL);
if (!binder->codecs->name)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
index 027373d6a16d..d41955685664 100644
--- a/sound/soc/intel/avs/boards/i2s_test.c
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -54,76 +54,13 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
return 0;
}
-static int avs_create_dapm_routes(struct device *dev, int ssp_port, int tdm_slot,
- struct snd_soc_dapm_route **routes, int *num_routes)
-{
- struct snd_soc_dapm_route *dr;
- const int num_dr = 2;
-
- dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return -ENOMEM;
-
- dr[0].sink = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot));
- dr[0].source = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", " Tx", ssp_port, tdm_slot));
- if (!dr[0].sink || !dr[0].source)
- return -ENOMEM;
-
- dr[1].sink = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", " Rx", ssp_port, tdm_slot));
- dr[1].source = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot));
- if (!dr[1].sink || !dr[1].source)
- return -ENOMEM;
-
- *routes = dr;
- *num_routes = num_dr;
-
- return 0;
-}
-
-static int avs_create_dapm_widgets(struct device *dev, int ssp_port, int tdm_slot,
- struct snd_soc_dapm_widget **widgets, int *num_widgets)
-{
- struct snd_soc_dapm_widget *dw;
- const int num_dw = 2;
-
- dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
- if (!dw)
- return -ENOMEM;
-
- dw[0].id = snd_soc_dapm_hp;
- dw[0].reg = SND_SOC_NOPM;
- dw[0].name = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot));
- if (!dw[0].name)
- return -ENOMEM;
-
- dw[1].id = snd_soc_dapm_mic;
- dw[1].reg = SND_SOC_NOPM;
- dw[1].name = devm_kasprintf(dev, GFP_KERNEL,
- AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot));
- if (!dw[1].name)
- return -ENOMEM;
-
- *widgets = dw;
- *num_widgets = num_dw;
-
- return 0;
-}
-
static int avs_i2s_test_probe(struct platform_device *pdev)
{
- struct snd_soc_dapm_widget *widgets;
- struct snd_soc_dapm_route *routes;
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
const char *pname;
- int num_routes, num_widgets;
int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
@@ -156,26 +93,10 @@ static int avs_i2s_test_probe(struct platform_device *pdev)
return ret;
}
- ret = avs_create_dapm_routes(dev, ssp_port, tdm_slot, &routes, &num_routes);
- if (ret) {
- dev_err(dev, "Failed to create dapm routes: %d\n", ret);
- return ret;
- }
-
- ret = avs_create_dapm_widgets(dev, ssp_port, tdm_slot, &widgets, &num_widgets);
- if (ret) {
- dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
- return ret;
- }
-
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
card->num_links = 1;
- card->dapm_routes = routes;
- card->num_dapm_routes = num_routes;
- card->dapm_widgets = widgets;
- card->num_dapm_widgets = num_widgets;
card->fully_routed = true;
ret = snd_soc_fixup_dai_links_platform_name(card, pname);
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index 55db75efae41..3164745b1516 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -67,7 +67,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "Headset Mic", NULL, "Platform Clock" },
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index 1cf524216087..e3aa28780df5 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -75,7 +75,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"MIC", NULL, "Platform Clock"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index 4740bba10570..d24316fc4db9 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -38,7 +38,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"Speaker", NULL, "SPOL"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 6e409e29f697..7fd28544f786 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -49,7 +49,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"Speaker", NULL, "SPOL"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
index 1880c315cc4d..ba8c42d026da 100644
--- a/sound/soc/intel/avs/boards/rt5663.c
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -43,7 +43,7 @@ static const struct snd_soc_dapm_route card_routes[] = {
{ "IN1N", NULL, "Headset Mic" },
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 594a971ded9e..823f04dba2f7 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -80,7 +80,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "IN1P", NULL, "Headset Mic" },
};
-static struct snd_soc_jack_pin card_jack_pins[] = {
+static const struct snd_soc_jack_pin card_jack_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index d6f7f046c24e..9e78a3b91208 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -37,8 +37,6 @@ static const struct snd_kcontrol_new card_controls[] = {
static const struct snd_soc_dapm_widget card_widgets[] = {
SND_SOC_DAPM_SPK("Left Speaker", NULL),
SND_SOC_DAPM_SPK("Right Speaker", NULL),
- SND_SOC_DAPM_SPK("DP1", NULL),
- SND_SOC_DAPM_SPK("DP2", NULL),
};
static const struct snd_soc_dapm_route card_base_routes[] = {
@@ -158,7 +156,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = "avs_ssm4567-adi";
+ card->name = "avs_ssm4567";
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
@@ -172,7 +170,6 @@ static int avs_ssm4567_probe(struct platform_device *pdev)
card->dapm_routes = card_base_routes;
card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
card->fully_routed = true;
- card->disable_route_checks = true;
ret = snd_soc_fixup_dai_links_platform_name(card, pname);
if (ret)
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index 82416b86662d..8100c2fa0a7e 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -250,7 +250,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
if (!entry)
return -ENOMEM;
- entry->name = kstrdup(name, GFP_KERNEL);
+ entry->name = kstrdup_const(name, GFP_KERNEL);
if (!entry->name) {
kfree(entry);
return -ENOMEM;
@@ -258,7 +258,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
ret = request_firmware(&entry->fw, name, adev->dev);
if (ret < 0) {
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
return ret;
}
@@ -282,7 +282,7 @@ void avs_release_last_firmware(struct avs_dev *adev)
list_del(&entry->node);
release_firmware(entry->fw);
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
}
@@ -296,7 +296,7 @@ void avs_release_firmwares(struct avs_dev *adev)
list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) {
list_del(&entry->node);
release_firmware(entry->fw);
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
}
}
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 18ac3ce0752e..9f4a85513702 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -41,9 +41,6 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON
config SND_SOC_INTEL_SOF_NUVOTON_COMMON
tristate
-config SND_SOC_INTEL_SOF_SSP_COMMON
- tristate
-
config SND_SOC_INTEL_SOF_BOARD_HELPERS
tristate
@@ -503,7 +500,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
select SND_SOC_INTEL_SOF_REALTEK_COMMON
- select SND_SOC_INTEL_SOF_SSP_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with rt5650 or rt5682 codec.
@@ -521,7 +518,7 @@ config SND_SOC_INTEL_SOF_CS42L42_MACH
select SND_SOC_INTEL_HDA_DSP_COMMON
select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
- select SND_SOC_INTEL_SOF_SSP_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with cs42l42 codec.
@@ -574,7 +571,7 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
select SND_SOC_INTEL_SOF_MAXIM_COMMON
select SND_SOC_INTEL_SOF_NUVOTON_COMMON
select SND_SOC_INTEL_SOF_REALTEK_COMMON
- select SND_SOC_INTEL_SOF_SSP_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with nau8825 codec.
@@ -624,8 +621,9 @@ config SND_SOC_INTEL_SOF_DA7219_MACH
select SND_SOC_MAX98357A
select SND_SOC_MAX98373_I2C
select SND_SOC_DMIC
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
- select SND_SOC_INTEL_SOF_SSP_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with Dialog DA7219 I2S audio codec.
@@ -645,7 +643,7 @@ config SND_SOC_INTEL_SOF_SSP_AMP_MACH
select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_REALTEK_COMMON
select SND_SOC_INTEL_SOF_CIRRUS_COMMON
- select SND_SOC_INTEL_SOF_SSP_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with RT1308/CS35L41 I2S audio codec.
@@ -677,7 +675,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
depends on SOUNDWIRE
- select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_MAX98363
select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98373_SDW
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index bbf796a5f7ba..a93b658ed672 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -40,8 +40,8 @@ snd-soc-sof-sdw-objs += sof_sdw.o \
sof_sdw_maxim.o sof_sdw_rt_amp.o \
sof_sdw_rt5682.o sof_sdw_rt700.o \
sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \
- sof_sdw_rt712_sdca.o sof_sdw_rt715.o \
- sof_sdw_rt715_sdca.o sof_sdw_rt722_sdca.o \
+ sof_sdw_rt712_sdca.o sof_sdw_rt722_sdca.o \
+ sof_sdw_rt_dmic.o \
sof_sdw_cs42l42.o sof_sdw_cs42l43.o \
sof_sdw_cs_amp.o \
sof_sdw_dmic.o \
@@ -101,8 +101,5 @@ obj-$(CONFIG_SND_SOC_INTEL_SOF_CIRRUS_COMMON) += snd-soc-intel-sof-cirrus-common
snd-soc-intel-sof-nuvoton-common-objs += sof_nuvoton_common.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_NUVOTON_COMMON) += snd-soc-intel-sof-nuvoton-common.o
-snd-soc-intel-sof-ssp-common-objs += sof_ssp_common.o
-obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) += snd-soc-intel-sof-ssp-common.o
-
snd-soc-intel-sof-board-helpers-objs += sof_board_helpers.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_BOARD_HELPERS) += snd-soc-intel-sof-board-helpers.o
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 540f7a29310a..3fe3f38c6cb6 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -768,6 +768,7 @@ static struct snd_soc_card broxton_audio_card = {
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = bxt_card_late_probe,
};
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index c0eb65c14aa9..afc499be8db2 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -574,6 +574,7 @@ static struct snd_soc_card broxton_rt298 = {
.dapm_routes = broxton_rt298_map,
.num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = bxt_card_late_probe,
};
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
index 657e4658234c..4098b2d32f9b 100644
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -649,6 +649,8 @@ static int geminilake_audio_probe(struct platform_device *pdev)
card = &glk_audio_card_rt5682_m98357a;
card->dev = &pdev->dev;
snd_soc_card_set_drvdata(card, ctx);
+ if (!snd_soc_acpi_sof_parent(&pdev->dev))
+ card->disable_route_checks = true;
/* override platform name, if required */
mach = pdev->dev.platform_data;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index a5d8965303a8..9dbc15f9d1c9 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -639,6 +639,7 @@ static struct snd_soc_card kabylake_audio_card_da7219_m98357a = {
.dapm_routes = kabylake_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 98c11ec0adc0..e662da5af83b 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -1036,6 +1036,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = {
.codec_conf = max98927_codec_conf,
.num_configs = ARRAY_SIZE(max98927_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
@@ -1054,6 +1055,7 @@ static struct snd_soc_card kbl_audio_card_max98927 = {
.codec_conf = max98927_codec_conf,
.num_configs = ARRAY_SIZE(max98927_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
@@ -1071,6 +1073,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98373 = {
.codec_conf = max98373_codec_conf,
.num_configs = ARRAY_SIZE(max98373_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
@@ -1088,6 +1091,7 @@ static struct snd_soc_card kbl_audio_card_max98373 = {
.codec_conf = max98373_codec_conf,
.num_configs = ARRAY_SIZE(max98373_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
index 30e0aca161cd..894d127c482a 100644
--- a/sound/soc/intel/boards/kbl_rt5660.c
+++ b/sound/soc/intel/boards/kbl_rt5660.c
@@ -518,6 +518,7 @@ static struct snd_soc_card kabylake_audio_card_rt5660 = {
.dapm_routes = kabylake_rt5660_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 9071b1f1cbd0..646e8ff8e961 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -966,6 +966,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
.codec_conf = max98927_codec_conf,
.num_configs = ARRAY_SIZE(max98927_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
@@ -982,6 +983,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = {
.dapm_routes = kabylake_5663_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 178fe9c37df6..924d5d1de03a 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -791,6 +791,7 @@ static struct snd_soc_card kabylake_audio_card = {
.codec_conf = max98927_codec_conf,
.num_configs = ARRAY_SIZE(max98927_codec_conf),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = kabylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index 6e172719c979..4aa7fd2a05e4 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -227,6 +227,8 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
hda_soc_card.dev = &pdev->dev;
+ if (!snd_soc_acpi_sof_parent(&pdev->dev))
+ hda_soc_card.disable_route_checks = true;
if (mach->mach_params.dmic_num > 0) {
snprintf(hda_soc_components, sizeof(hda_soc_components),
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 0e7025834594..e4630c33176e 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -654,6 +654,7 @@ static struct snd_soc_card skylake_audio_card = {
.dapm_routes = skylake_map,
.num_dapm_routes = ARRAY_SIZE(skylake_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = skylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index c59c60e28091..9a8044274908 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -523,6 +523,7 @@ static struct snd_soc_card skylake_rt286 = {
.dapm_routes = skylake_rt286_map,
.num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
.fully_routed = true,
+ .disable_route_checks = true,
.late_probe = skylake_card_late_probe,
};
diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c
index 088894ff4165..eb140e13153f 100644
--- a/sound/soc/intel/boards/sof_board_helpers.c
+++ b/sound/soc/intel/boards/sof_board_helpers.c
@@ -74,6 +74,11 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd)
* DAI Link Helpers
*/
+enum sof_dmic_be_type {
+ SOF_DMIC_01,
+ SOF_DMIC_16K,
+};
+
/* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */
#define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \
SOF_LINK_DMIC01, \
@@ -97,14 +102,14 @@ static struct snd_soc_dai_link_component platform_component[] = {
}
};
-int sof_intel_board_set_codec_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_ssp_codec codec_type, int ssp_codec)
+static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum snd_soc_acpi_intel_codec codec_type,
+ int ssp_codec)
{
struct snd_soc_dai_link_component *cpus;
- dev_dbg(dev, "link %d: codec %s, ssp %d\n", be_id,
- sof_ssp_get_codec_name(codec_type), ssp_codec);
+ dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id,
+ snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec);
/* link name */
link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
@@ -144,11 +149,9 @@ int sof_intel_board_set_codec_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-int sof_intel_board_set_dmic_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_dmic_be_type be_type)
+static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum sof_dmic_be_type be_type)
{
struct snd_soc_dai_link_component *cpus;
@@ -196,16 +199,14 @@ int sof_intel_board_set_dmic_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_dmic_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-int sof_intel_board_set_intel_hdmi_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int hdmi_id, bool idisp_codec)
+static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int hdmi_id, bool idisp_codec)
{
struct snd_soc_dai_link_component *cpus, *codecs;
- dev_dbg(dev, "link %d: intel hdmi, hdmi id %d, idisp codec %d\n",
- be_id, hdmi_id, idisp_codec);
+ dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id,
+ idisp_codec);
/* link name */
link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id);
@@ -256,16 +257,15 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-int sof_intel_board_set_ssp_amp_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_ssp_codec amp_type, int ssp_amp)
+static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum snd_soc_acpi_intel_codec amp_type,
+ int ssp_amp)
{
struct snd_soc_dai_link_component *cpus;
dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id,
- sof_ssp_get_codec_name(amp_type), ssp_amp);
+ snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp);
/* link name */
link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp);
@@ -298,11 +298,9 @@ int sof_intel_board_set_ssp_amp_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-int sof_intel_board_set_bt_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int ssp_bt)
+static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int ssp_bt)
{
struct snd_soc_dai_link_component *cpus;
@@ -341,11 +339,9 @@ int sof_intel_board_set_bt_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-int sof_intel_board_set_hdmi_in_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int ssp_hdmi)
+static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int ssp_hdmi)
{
struct snd_soc_dai_link_component *cpus;
@@ -383,7 +379,6 @@ int sof_intel_board_set_hdmi_in_link(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
static int calculate_num_links(struct sof_card_private *ctx)
{
@@ -427,6 +422,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
int ret;
int ssp_hdmi_in = 0;
unsigned long link_order, link;
+ unsigned long link_ids, be_id;
num_links = calculate_num_links(ctx);
@@ -440,22 +436,34 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
else
link_order = DEFAULT_LINK_ORDER;
- dev_dbg(dev, "create dai links, link_order 0x%lx\n", link_order);
+ if (ctx->link_id_overwrite)
+ link_ids = ctx->link_id_overwrite;
+ else
+ link_ids = 0;
+
+ dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n",
+ link_order, link_ids);
while (link_order) {
link = link_order & SOF_LINK_ORDER_MASK;
link_order >>= SOF_LINK_ORDER_SHIFT;
+ if (ctx->link_id_overwrite) {
+ be_id = link_ids & SOF_LINK_IDS_MASK;
+ link_ids >>= SOF_LINK_IDS_SHIFT;
+ } else {
+ /* use array index as link id */
+ be_id = idx;
+ }
+
switch (link) {
case SOF_LINK_CODEC:
/* headphone codec */
if (ctx->codec_type == CODEC_NONE)
continue;
- ret = sof_intel_board_set_codec_link(dev, &links[idx],
- idx,
- ctx->codec_type,
- ctx->ssp_codec);
+ ret = set_ssp_codec_link(dev, &links[idx], be_id,
+ ctx->codec_type, ctx->ssp_codec);
if (ret) {
dev_err(dev, "fail to set codec link, ret %d\n",
ret);
@@ -471,8 +479,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
continue;
/* at least we have dmic01 */
- ret = sof_intel_board_set_dmic_link(dev, &links[idx],
- idx, SOF_DMIC_01);
+ ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01);
if (ret) {
dev_err(dev, "fail to set dmic01 link, ret %d\n",
ret);
@@ -487,8 +494,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
continue;
/* set up 2 BE links at most */
- ret = sof_intel_board_set_dmic_link(dev, &links[idx],
- idx, SOF_DMIC_16K);
+ ret = set_dmic_link(dev, &links[idx], be_id,
+ SOF_DMIC_16K);
if (ret) {
dev_err(dev, "fail to set dmic16k link, ret %d\n",
ret);
@@ -500,10 +507,9 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
case SOF_LINK_IDISP_HDMI:
/* idisp HDMI */
for (i = 1; i <= ctx->hdmi_num; i++) {
- ret = sof_intel_board_set_intel_hdmi_link(dev,
- &links[idx],
- idx, i,
- ctx->hdmi.idisp_codec);
+ ret = set_idisp_hdmi_link(dev, &links[idx],
+ be_id, i,
+ ctx->hdmi.idisp_codec);
if (ret) {
dev_err(dev, "fail to set hdmi link, ret %d\n",
ret);
@@ -511,6 +517,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
}
idx++;
+ be_id++;
}
break;
case SOF_LINK_AMP:
@@ -518,10 +525,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
if (ctx->amp_type == CODEC_NONE)
continue;
- ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx],
- idx,
- ctx->amp_type,
- ctx->ssp_amp);
+ ret = set_ssp_amp_link(dev, &links[idx], be_id,
+ ctx->amp_type, ctx->ssp_amp);
if (ret) {
dev_err(dev, "fail to set amp link, ret %d\n",
ret);
@@ -536,8 +541,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
if (!ctx->bt_offload_present)
continue;
- ret = sof_intel_board_set_bt_link(dev, &links[idx], idx,
- ctx->ssp_bt);
+ ret = set_bt_offload_link(dev, &links[idx], be_id,
+ ctx->ssp_bt);
if (ret) {
dev_err(dev, "fail to set bt link, ret %d\n",
ret);
@@ -549,10 +554,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
case SOF_LINK_HDMI_IN:
/* HDMI-In */
for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) {
- ret = sof_intel_board_set_hdmi_in_link(dev,
- &links[idx],
- idx,
- ssp_hdmi_in);
+ ret = set_hdmi_in_link(dev, &links[idx], be_id,
+ ssp_hdmi_in);
if (ret) {
dev_err(dev, "fail to set hdmi-in link, ret %d\n",
ret);
@@ -560,6 +563,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
}
idx++;
+ be_id++;
}
break;
case SOF_LINK_NONE:
@@ -584,26 +588,51 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
}
EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
-struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
- const char * const dai_name[], int num_dais)
+struct sof_card_private *
+sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk)
{
- struct snd_soc_dai *dai;
- int index;
- int i;
+ struct sof_card_private *ctx;
- for (index = 0; index < num_dais; index++)
- for_each_rtd_codec_dais(rtd, i, dai)
- if (strstr(dai->name, dai_name[index])) {
- dev_dbg(rtd->card->dev, "get dai %s\n", dai->name);
- return dai;
- }
+ dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk);
+
+ ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev);
+ ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev);
+
+ ctx->dmic_be_num = 2;
+ ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >>
+ SOF_NUM_IDISP_HDMI_SHIFT;
+ /* default number of HDMI DAI's */
+ if (!ctx->hdmi_num)
+ ctx->hdmi_num = 3;
+
+ /* port number/mask of peripherals attached to ssp interface */
+ if (ctx->codec_type != CODEC_NONE)
+ ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >>
+ SOF_SSP_PORT_CODEC_SHIFT;
+
+ if (ctx->amp_type != CODEC_NONE)
+ ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >>
+ SOF_SSP_PORT_AMP_SHIFT;
+
+ if (board_quirk & SOF_BT_OFFLOAD_PRESENT) {
+ ctx->bt_offload_present = true;
+ ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >>
+ SOF_SSP_PORT_BT_OFFLOAD_SHIFT;
+ }
+
+ ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >>
+ SOF_SSP_MASK_HDMI_CAPTURE_SHIFT;
- return NULL;
+ return ctx;
}
-EXPORT_SYMBOL_NS(get_codec_dai_by_name, SND_SOC_INTEL_SOF_BOARD_HELPERS);
+EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers");
MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
+MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH);
diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h
index f42d5d640321..644f6b4a1b7b 100644
--- a/sound/soc/intel/boards/sof_board_helpers.h
+++ b/sound/soc/intel/boards/sof_board_helpers.h
@@ -7,8 +7,46 @@
#define __SOF_INTEL_BOARD_HELPERS_H
#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
#include "sof_hdmi_common.h"
-#include "sof_ssp_common.h"
+
+/*
+ * Common board quirks: from bit 8 to 31, LSB 8 bits reserved for machine
+ * drivers
+ */
+
+/* SSP port number for headphone codec: 3 bits */
+#define SOF_SSP_PORT_CODEC_SHIFT 8
+#define SOF_SSP_PORT_CODEC_MASK (GENMASK(10, 8))
+#define SOF_SSP_PORT_CODEC(quirk) \
+ (((quirk) << SOF_SSP_PORT_CODEC_SHIFT) & SOF_SSP_PORT_CODEC_MASK)
+
+/* SSP port number for speaker amplifier: 3 bits */
+#define SOF_SSP_PORT_AMP_SHIFT 11
+#define SOF_SSP_PORT_AMP_MASK (GENMASK(13, 11))
+#define SOF_SSP_PORT_AMP(quirk) \
+ (((quirk) << SOF_SSP_PORT_AMP_SHIFT) & SOF_SSP_PORT_AMP_MASK)
+
+/* SSP port number for BT audio offload: 3 bits */
+#define SOF_SSP_PORT_BT_OFFLOAD_SHIFT 14
+#define SOF_SSP_PORT_BT_OFFLOAD_MASK (GENMASK(16, 14))
+#define SOF_SSP_PORT_BT_OFFLOAD(quirk) \
+ (((quirk) << SOF_SSP_PORT_BT_OFFLOAD_SHIFT) & SOF_SSP_PORT_BT_OFFLOAD_MASK)
+
+/* SSP port mask for HDMI capture: 6 bits */
+#define SOF_SSP_MASK_HDMI_CAPTURE_SHIFT 17
+#define SOF_SSP_MASK_HDMI_CAPTURE_MASK (GENMASK(22, 17))
+#define SOF_SSP_MASK_HDMI_CAPTURE(quirk) \
+ (((quirk) << SOF_SSP_MASK_HDMI_CAPTURE_SHIFT) & SOF_SSP_MASK_HDMI_CAPTURE_MASK)
+
+/* Number of idisp HDMI BE link: 3 bits */
+#define SOF_NUM_IDISP_HDMI_SHIFT 23
+#define SOF_NUM_IDISP_HDMI_MASK (GENMASK(25, 23))
+#define SOF_NUM_IDISP_HDMI(quirk) \
+ (((quirk) << SOF_NUM_IDISP_HDMI_SHIFT) & SOF_NUM_IDISP_HDMI_MASK)
+
+/* Board uses BT audio offload */
+#define SOF_BT_OFFLOAD_PRESENT BIT(26)
enum {
SOF_LINK_NONE = 0,
@@ -33,6 +71,31 @@ enum {
(((k6) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 5)) | \
(((k7) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 6)))
+#define SOF_LINK_IDS_MASK (0xF)
+#define SOF_LINK_IDS_SHIFT (4)
+
+#define SOF_LINK_IDS(k1, k2, k3, k4, k5, k6, k7) \
+ ((((k1) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 0)) | \
+ (((k2) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 1)) | \
+ (((k3) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 2)) | \
+ (((k4) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 3)) | \
+ (((k5) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 4)) | \
+ (((k6) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 5)) | \
+ (((k7) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 6)))
+
+/*
+ * sof_da7219_private: private data for da7219 machine driver
+ *
+ * @is_jsl_board: true for JSL boards
+ * @mclk_en: true for mclk pin is connected
+ * @pll_bypass: true for PLL bypass mode
+ */
+struct sof_da7219_private {
+ bool is_jsl_board;
+ bool mclk_en;
+ bool pll_bypass;
+};
+
/*
* sof_rt5682_private: private data for rt5682 machine driver
*
@@ -61,14 +124,16 @@ struct sof_rt5682_private {
* @codec_link: pointer to headset codec dai link
* @amp_link: pointer to speaker amplifier dai link
* @link_order_overwrite: custom DAI link order
+ * @link_id_overwrite: custom DAI link ID
+ * @da7219: private data for da7219 machine driver
* @rt5682: private data for rt5682 machine driver
*/
struct sof_card_private {
struct snd_soc_jack headset_jack;
struct sof_hdmi_private hdmi;
- enum sof_ssp_codec codec_type;
- enum sof_ssp_codec amp_type;
+ enum snd_soc_acpi_intel_codec codec_type;
+ enum snd_soc_acpi_intel_codec amp_type;
int dmic_be_num;
int hdmi_num;
@@ -84,41 +149,22 @@ struct sof_card_private {
struct snd_soc_dai_link *amp_link;
unsigned long link_order_overwrite;
+ /*
+ * A variable stores id for all BE DAI links, use SOF_LINK_IDS macro to
+ * build the value; use DAI link array index as id if zero.
+ */
+ unsigned long link_id_overwrite;
union {
+ struct sof_da7219_private da7219;
struct sof_rt5682_private rt5682;
};
};
-enum sof_dmic_be_type {
- SOF_DMIC_01,
- SOF_DMIC_16K,
-};
-
int sof_intel_board_card_late_probe(struct snd_soc_card *card);
int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
struct sof_card_private *ctx);
-
-int sof_intel_board_set_codec_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_ssp_codec codec_type, int ssp_codec);
-int sof_intel_board_set_dmic_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_dmic_be_type be_type);
-int sof_intel_board_set_intel_hdmi_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int hdmi_id, bool idisp_codec);
-int sof_intel_board_set_ssp_amp_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- enum sof_ssp_codec amp_type, int ssp_amp);
-int sof_intel_board_set_bt_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int ssp_bt);
-int sof_intel_board_set_hdmi_in_link(struct device *dev,
- struct snd_soc_dai_link *link, int be_id,
- int ssp_hdmi);
-
-struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
- const char * const dai_name[], int num_dais);
+struct sof_card_private *
+sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk);
#endif /* __SOF_INTEL_BOARD_HELPERS_H */
diff --git a/sound/soc/intel/boards/sof_cirrus_common.h b/sound/soc/intel/boards/sof_cirrus_common.h
index d4ecf8d023d1..1c87637b9ef7 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.h
+++ b/sound/soc/intel/boards/sof_cirrus_common.h
@@ -9,7 +9,7 @@
#define __SOF_CIRRUS_COMMON_H
#include <sound/soc.h>
-#include "sof_ssp_common.h"
+#include <sound/soc-acpi-intel-ssp-common.h>
/*
* Cirrus Logic CS35L41/CS35L53
diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c
index 323b86c42ef9..f4fee2ee0d63 100644
--- a/sound/soc/intel/boards/sof_cs42l42.c
+++ b/sound/soc/intel/boards/sof_cs42l42.c
@@ -22,23 +22,6 @@
#include "../common/soc-intel-quirks.h"
#include "sof_board_helpers.h"
#include "sof_maxim_common.h"
-#include "sof_ssp_common.h"
-
-#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_CS42L42_SSP_AMP_SHIFT 4
-#define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4))
-#define SOF_CS42L42_SSP_AMP(quirk) \
- (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
-#define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7
-#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7))
-#define SOF_CS42L42_NUM_HDMIDEV(quirk) \
- (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
-#define SOF_BT_OFFLOAD_PRESENT BIT(25)
-#define SOF_CS42L42_SSP_BT_SHIFT 26
-#define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26))
-#define SOF_CS42L42_SSP_BT(quirk) \
- (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
static struct snd_soc_jack_pin jack_pins[] = {
{
@@ -52,7 +35,7 @@ static struct snd_soc_jack_pin jack_pins[] = {
};
/* Default: SSP2 */
-static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
+static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2);
static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -229,48 +212,26 @@ static int sof_audio_probe(struct platform_device *pdev)
struct sof_card_private *ctx;
int ret;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
- ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
- ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
+ dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk);
+ if (!ctx)
+ return -ENOMEM;
if (soc_intel_is_glk()) {
ctx->dmic_be_num = 1;
- ctx->hdmi_num = 3;
/* overwrite the DAI link order for GLK boards */
ctx->link_order_overwrite = GLK_LINK_ORDER;
- } else {
- ctx->dmic_be_num = 2;
- ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
- SOF_CS42L42_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!ctx->hdmi_num)
- ctx->hdmi_num = 3;
}
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
- dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
-
- /* port number of peripherals attached to ssp interface */
- ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
- SOF_CS42L42_SSP_BT_SHIFT;
-
- ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
- SOF_CS42L42_SSP_AMP_SHIFT;
-
- ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
-
- if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
- ctx->bt_offload_present = true;
-
/* update dai_link */
ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx);
if (ret)
@@ -293,21 +254,36 @@ static int sof_audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "glk_cs4242_mx98357a",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
- SOF_CS42L42_SSP_AMP(1)),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.name = "jsl_cs4242_mx98360a",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
- SOF_CS42L42_SSP_AMP(1)),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
+ },
+ {
+ .name = "adl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(2)),
+ },
+ {
+ .name = "rpl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(2)),
},
{
- .name = "adl_mx98360a_cs4242",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
- SOF_CS42L42_SSP_AMP(1) |
- SOF_CS42L42_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_PRESENT |
- SOF_CS42L42_SSP_BT(2)),
+ .name = "mtl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(1)),
},
{ }
};
@@ -329,4 +305,3 @@ MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c
index 6eb5a6144e97..fd3a7be993c1 100644
--- a/sound/soc/intel/boards/sof_da7219.c
+++ b/sound/soc/intel/boards/sof_da7219.c
@@ -15,35 +15,25 @@
#include <sound/soc-acpi.h>
#include <sound/sof.h>
#include "../../codecs/da7219.h"
-#include "hda_dsp_common.h"
-#include "sof_hdmi_common.h"
+#include "sof_board_helpers.h"
#include "sof_maxim_common.h"
-#include "sof_ssp_common.h"
-/* Board Quirks */
-#define SOF_DA7219_JSL_BOARD BIT(2)
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_DA7219_JSL_BOARD BIT(0)
+#define SOF_DA7219_MCLK_EN BIT(1)
#define DIALOG_CODEC_DAI "da7219-hifi"
-struct card_private {
- struct snd_soc_jack headset_jack;
- struct sof_hdmi_private hdmi;
- enum sof_ssp_codec codec_type;
- enum sof_ssp_codec amp_type;
-
- unsigned int pll_bypass:1;
-};
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
- struct card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *codec_dai;
int ret = 0;
- if (ctx->pll_bypass)
+ if (ctx->da7219.pll_bypass)
return ret;
/* PLL SRM mode */
@@ -74,8 +64,6 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Line Out"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
};
static const struct snd_soc_dapm_widget widgets[] = {
@@ -83,14 +71,9 @@ static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-
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[] = {
@@ -102,9 +85,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
{ "Line Out", NULL, "Platform Clock" },
-
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
};
static struct snd_soc_jack_pin jack_pins[] = {
@@ -124,7 +104,7 @@ static struct snd_soc_jack_pin jack_pins[] = {
static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
{
- struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_soc_jack *jack = &ctx->headset_jack;
@@ -147,7 +127,8 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
* Use PLL bypass mode if MCLK is available, be sure to set the
* frequency of MCLK to 12.288 or 24.576MHz on topology side.
*/
- if (mclk_rate == 12288000 || mclk_rate == 24576000) {
+ if (ctx->da7219.mclk_en &&
+ (mclk_rate == 12288000 || mclk_rate == 24576000)) {
/* PLL bypass mode */
dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate);
@@ -157,7 +138,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ctx->pll_bypass = 1;
+ ctx->da7219.pll_bypass = true;
}
/*
@@ -188,6 +169,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
+static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
static int max98373_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -222,215 +210,11 @@ static const struct snd_soc_ops max98373_ops = {
.hw_params = max98373_hw_params,
};
-static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
-
- ctx->hdmi.hdmi_comp = dai->component;
-
- return 0;
-}
-
static int card_late_probe(struct snd_soc_card *card)
{
- struct card_private *ctx = snd_soc_card_get_drvdata(card);
-
- if (!ctx->hdmi.idisp_codec)
- return 0;
-
- if (!ctx->hdmi.hdmi_comp)
- return -EINVAL;
-
- return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp);
+ return sof_intel_board_card_late_probe(card);
}
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin")));
-SND_SOC_DAILINK_DEF(dummy_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")));
-
-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_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,
- 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")));
-
-SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-static struct snd_soc_dai_link jsl_dais[] = {
- /* Back End DAI links */
- {
- .name = "SSP1-Codec",
- .id = 0,
- .ignore_pmdown_time = 1,
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1, /* IV feedback */
- SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform),
- },
- {
- .name = "SSP0-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = da7219_codec_init,
- .ignore_pmdown_time = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .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_dai_link adl_dais[] = {
- /* Back End DAI links */
- {
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .init = da7219_codec_init,
- .ignore_pmdown_time = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "dmic01",
- .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_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
- {
- .name = "iDisp4",
- .id = 6,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
- },
- {
- .name = "SSP1-Codec",
- .id = 7,
- .no_pcm = 1,
- .dpcm_playback = 1,
- /* feedback stream or firmware-generated echo reference */
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform),
- },
- {
- .name = "SSP2-BT",
- .id = 8,
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp2_pin, dummy_codec, platform),
- },
-};
-
static struct snd_soc_card card_da7219 = {
.name = "da7219", /* the sof- prefix is added by the core */
.owner = THIS_MODULE,
@@ -444,28 +228,101 @@ static struct snd_soc_card card_da7219 = {
.late_probe = card_late_probe,
};
+static struct snd_soc_dai_link_component da7219_component[] = {
+ {
+ .name = "i2c-DLGS7219:00",
+ .dai_name = DIALOG_CODEC_DAI,
+ }
+};
+
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
+{
+ int ret;
+
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
+
+ if (!ctx->codec_link) {
+ dev_err(dev, "codec link not available");
+ return -EINVAL;
+ }
+
+ /* codec-specific fields for headphone codec */
+ ctx->codec_link->codecs = da7219_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component);
+ ctx->codec_link->init = da7219_codec_init;
+ ctx->codec_link->exit = da7219_codec_exit;
+
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
+
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
+ }
+
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98360A:
+ max_98360a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98373:
+ ctx->amp_link->codecs = max_98373_components;
+ ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components);
+ ctx->amp_link->init = max_98373_spk_codec_init;
+ if (ctx->da7219.is_jsl_board) {
+ ctx->amp_link->ops = &max98373_ops; /* use local ops */
+ } else {
+ /* TBD: implement the amp for later platform */
+ dev_err(dev, "max98373 not support yet\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
static int audio_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
- struct snd_soc_dai_link *dai_links;
- struct card_private *ctx;
+ struct sof_card_private *ctx;
unsigned long board_quirk = 0;
- int ret, amp_idx;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ int ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
board_quirk = (unsigned long)pdev->id_entry->driver_data;
- ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
- ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
+ dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
+ if (!ctx)
+ return -ENOMEM;
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
if (board_quirk & SOF_DA7219_JSL_BOARD) {
+ ctx->da7219.is_jsl_board = true;
+
+ /* overwrite the DAI link order for JSL boards */
+ ctx->link_order_overwrite = JSL_LINK_ORDER;
+
/* backward-compatible with existing devices */
switch (ctx->amp_type) {
case CODEC_MAX98360A:
@@ -480,46 +337,30 @@ static int audio_probe(struct platform_device *pdev)
default:
break;
}
-
- dai_links = jsl_dais;
- amp_idx = 0;
-
- card_da7219.num_links = ARRAY_SIZE(jsl_dais);
- } else {
- dai_links = adl_dais;
- amp_idx = 7;
-
- card_da7219.num_links = ARRAY_SIZE(adl_dais);
}
- dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
+ if (board_quirk & SOF_DA7219_MCLK_EN)
+ ctx->da7219.mclk_en = true;
+
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx);
+ if (ret)
+ return ret;
- /* speaker amp */
+ /* update codec_conf */
switch (ctx->amp_type) {
- case CODEC_MAX98360A:
- max_98360a_dai_link(&dai_links[amp_idx]);
- break;
case CODEC_MAX98373:
- dai_links[amp_idx].codecs = max_98373_components;
- dai_links[amp_idx].num_codecs = ARRAY_SIZE(max_98373_components);
- dai_links[amp_idx].init = max_98373_spk_codec_init;
- if (board_quirk & SOF_DA7219_JSL_BOARD) {
- dai_links[amp_idx].ops = &max98373_ops; /* use local ops */
- } else {
- /* TBD: implement the amp for later platform */
- dev_err(&pdev->dev, "max98373 not support yet\n");
- return -EINVAL;
- }
-
max_98373_set_codec_conf(&card_da7219);
break;
+ case CODEC_MAX98360A:
+ case CODEC_NONE:
+ /* no codec conf required */
+ break;
default:
dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
return -EINVAL;
}
- card_da7219.dai_link = dai_links;
-
card_da7219.dev = &pdev->dev;
ret = snd_soc_fixup_dai_links_platform_name(&card_da7219,
@@ -534,16 +375,28 @@ static int audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
- .name = "jsl_mx98373_da7219",
- .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD),
+ .name = "jsl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
- .name = "jsl_mx98360_da7219",
- .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD),
+ .name = "adl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_mx98360_da7219",
- /* no quirk needed for this board */
+ .name = "rpl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{ }
};
@@ -564,6 +417,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec");
MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h
index fe0212fbad8e..8886f985de68 100644
--- a/sound/soc/intel/boards/sof_maxim_common.h
+++ b/sound/soc/intel/boards/sof_maxim_common.h
@@ -11,7 +11,7 @@
#define __SOF_MAXIM_COMMON_H
#include <sound/soc.h>
-#include "sof_ssp_common.h"
+#include <sound/soc-acpi-intel-ssp-common.h>
/*
* Maxim MAX98373
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 719c2fbaf515..fe5f9e8dd652 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -24,27 +24,8 @@
#include "sof_realtek_common.h"
#include "sof_maxim_common.h"
#include "sof_nuvoton_common.h"
-#include "sof_ssp_common.h"
-
-#define SOF_NAU8825_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_NAU8825_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_NAU8825_SSP_AMP_SHIFT 4
-#define SOF_NAU8825_SSP_AMP_MASK (GENMASK(6, 4))
-#define SOF_NAU8825_SSP_AMP(quirk) \
- (((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK)
-#define SOF_NAU8825_NUM_HDMIDEV_SHIFT 7
-#define SOF_NAU8825_NUM_HDMIDEV_MASK (GENMASK(9, 7))
-#define SOF_NAU8825_NUM_HDMIDEV(quirk) \
- (((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK)
-
-/* BT audio offload: reserve 3 bits for future */
-#define SOF_BT_OFFLOAD_SSP_SHIFT 10
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(12, 10))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(13)
-
-static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
+
+static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0);
static struct snd_soc_jack_pin jack_pins[] = {
{
@@ -264,41 +245,19 @@ static int sof_audio_probe(struct platform_device *pdev)
struct sof_card_private *ctx;
int ret;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data;
- ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
- ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
-
dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk);
- /* default number of DMIC DAI's */
- ctx->dmic_be_num = 2;
- ctx->hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >>
- SOF_NAU8825_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!ctx->hdmi_num)
- ctx->hdmi_num = 3;
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk);
+ if (!ctx)
+ return -ENOMEM;
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
- /* port number of peripherals attached to ssp interface */
- ctx->ssp_bt = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >>
- SOF_NAU8825_SSP_AMP_SHIFT;
-
- ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK;
-
- if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- ctx->bt_offload_present = true;
-
/* update dai_link */
ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx);
if (ret)
@@ -312,10 +271,10 @@ static int sof_audio_probe(struct platform_device *pdev)
case CODEC_RT1015P:
sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
break;
- case CODEC_NONE:
case CODEC_MAX98360A:
case CODEC_NAU8318:
case CODEC_RT1019P:
+ case CODEC_NONE:
/* no codec conf required */
break;
default:
@@ -339,34 +298,33 @@ static int sof_audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
- .name = "sof_nau8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
-
- },
- {
.name = "adl_rt1019p_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_NAU8825_SSP_AMP(2) |
- SOF_NAU8825_NUM_HDMIDEV(4)),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.name = "adl_nau8825_def",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "rpl_nau8825_def",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
+ },
+ {
+ .name = "mtl_nau8825_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{ }
};
@@ -392,4 +350,3 @@ MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_NUVOTON_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_nuvoton_common.h b/sound/soc/intel/boards/sof_nuvoton_common.h
index 53a84f9a67c0..8a0f283260e7 100644
--- a/sound/soc/intel/boards/sof_nuvoton_common.h
+++ b/sound/soc/intel/boards/sof_nuvoton_common.h
@@ -9,7 +9,7 @@
#define __SOF_NUVOTON_COMMON_H
#include <sound/soc.h>
-#include "sof_ssp_common.h"
+#include <sound/soc-acpi-intel-ssp-common.h>
/*
* Nuvoton NAU8318
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
index e3fa2924c1c1..289e85b61660 100644
--- a/sound/soc/intel/boards/sof_realtek_common.h
+++ b/sound/soc/intel/boards/sof_realtek_common.h
@@ -11,7 +11,7 @@
#define __SOF_REALTEK_COMMON_H
#include <sound/soc.h>
-#include "sof_ssp_common.h"
+#include <sound/soc-acpi-intel-ssp-common.h>
/*
* Realtek ALC1011
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 640d17c6cd35..aadd341a202c 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -27,37 +27,14 @@
#include "sof_board_helpers.h"
#include "sof_maxim_common.h"
#include "sof_realtek_common.h"
-#include "sof_ssp_common.h"
-
-#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_RT5682_MCLK_EN BIT(3)
-#define SOF_RT5682_SSP_AMP_SHIFT 6
-#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
-#define SOF_RT5682_SSP_AMP(quirk) \
- (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
-#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9)
-#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10
-#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10))
-#define SOF_RT5682_NUM_HDMIDEV(quirk) \
- ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
-
-/* BT audio offload: reserve 3 bits for future */
-#define SOF_BT_OFFLOAD_SSP_SHIFT 19
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(21, 19))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22)
-
-/* HDMI capture*/
-#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27
-#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27))
-#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \
- (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK)
+
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_RT5682_MCLK_EN BIT(0)
+#define SOF_RT5682_MCLK_BYTCHT_EN BIT(1)
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0);
+ SOF_SSP_PORT_CODEC(0);
static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
{
@@ -72,7 +49,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"),
},
- .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
+ .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -80,7 +57,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
},
- .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
+ .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -89,7 +66,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(1)),
+ SOF_SSP_PORT_CODEC(1)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -97,8 +74,8 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -107,7 +84,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0)),
+ SOF_SSP_PORT_CODEC(0)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -116,9 +93,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -128,9 +105,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -139,9 +116,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -150,9 +127,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -160,11 +137,10 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(2) |
- SOF_RT5682_SSP_AMP(0) |
- SOF_RT5682_NUM_HDMIDEV(3) |
- SOF_BT_OFFLOAD_SSP(1) |
- SOF_SSP_BT_OFFLOAD_PRESENT
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT
),
},
{}
@@ -630,19 +606,29 @@ static int sof_audio_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct sof_card_private *ctx;
+ bool is_legacy_cpu;
int ret;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
dmi_check_system(sof_rt5682_quirk_table);
- ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
- ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
+ if (soc_intel_is_byt() || soc_intel_is_cht()) {
+ is_legacy_cpu = true;
+
+ /* default quirk for legacy cpu */
+ sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
+ SOF_RT5682_MCLK_BYTCHT_EN |
+ SOF_SSP_PORT_CODEC(2);
+ }
+
+ dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk);
+ if (!ctx)
+ return -ENOMEM;
if (ctx->codec_type == CODEC_RT5650) {
sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650",
@@ -653,23 +639,12 @@ static int sof_audio_probe(struct platform_device *pdev)
ctx->amp_type = CODEC_RT5650;
}
- if (soc_intel_is_byt() || soc_intel_is_cht()) {
+ if (is_legacy_cpu) {
ctx->rt5682.is_legacy_cpu = true;
ctx->dmic_be_num = 0;
/* HDMI is not supported by SOF on Baytrail/CherryTrail */
ctx->hdmi_num = 0;
- /* default quirk for legacy cpu */
- sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_BYTCHT_EN |
- SOF_RT5682_SSP_CODEC(2);
} else {
- ctx->dmic_be_num = 2;
- ctx->hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >>
- SOF_RT5682_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!ctx->hdmi_num)
- ctx->hdmi_num = 3;
-
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
}
@@ -694,23 +669,6 @@ static int sof_audio_probe(struct platform_device *pdev)
}
}
- dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
-
- /* port number/mask of peripherals attached to ssp interface */
- ctx->ssp_mask_hdmi_in = (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >>
- SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
-
- ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- ctx->ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >>
- SOF_RT5682_SSP_AMP_SHIFT;
-
- ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK;
-
- if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- ctx->bt_offload_present = true;
-
/* update dai_link */
ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx);
if (ret)
@@ -733,11 +691,11 @@ static int sof_audio_probe(struct platform_device *pdev)
case CODEC_RT1015P:
sof_rt1015p_codec_conf(&sof_audio_card_rt5682);
break;
- case CODEC_NONE:
case CODEC_MAX98357A:
case CODEC_MAX98360A:
case CODEC_RT1019P:
case CODEC_RT5650:
+ case CODEC_NONE:
/* no codec conf required */
break;
default:
@@ -764,98 +722,93 @@ static const struct platform_device_id board_ids[] = {
.name = "sof_rt5682",
},
{
- .name = "cml_rt1015_rt5682",
+ .name = "cml_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.name = "jsl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.name = "tgl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "adl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "adl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.name = "adl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(1) |
- SOF_RT5682_NUM_HDMIDEV(3) |
+ SOF_SSP_PORT_CODEC(1) |
/* SSP 0 and SSP 2 are used for HDMI IN */
- SOF_HDMI_CAPTURE_SSP_MASK(0x5)),
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
.name = "rpl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.name = "rpl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "rpl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(1) |
- SOF_RT5682_NUM_HDMIDEV(3) |
+ SOF_SSP_PORT_CODEC(1) |
/* SSP 0 and SSP 2 are used for HDMI IN */
- SOF_HDMI_CAPTURE_SSP_MASK(0x5)),
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
.name = "mtl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(3) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "mtl_mx98360_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(3)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.name = "mtl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(2) |
- SOF_RT5682_SSP_AMP(0) |
- SOF_RT5682_NUM_HDMIDEV(3) |
- SOF_BT_OFFLOAD_SSP(1) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{ }
};
@@ -881,4 +834,3 @@ MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 08f330ed5c2e..b94835448b1b 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -5,6 +5,7 @@
* sof_sdw - ASOC Machine driver for Intel SoundWire platforms
*/
+#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/module.h>
@@ -35,7 +36,9 @@ static void log_quirks(struct device *dev)
dev_dbg(dev, "SSP port %ld\n",
SOF_SSP_GET_PORT(sof_sdw_quirk));
if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
- dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
+ dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n");
+ if (sof_sdw_quirk & SOF_CODEC_SPKR)
+ dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n");
}
static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
@@ -514,6 +517,24 @@ static struct snd_soc_dai_link_component platform_component[] = {
}
};
+struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
+ const char * const dai_name[],
+ int num_dais)
+{
+ struct snd_soc_dai *dai;
+ int index;
+ int i;
+
+ for (index = 0; index < num_dais; index++)
+ for_each_rtd_codec_dais(rtd, i, dai)
+ if (strstr(dai->name, dai_name[index])) {
+ dev_dbg(rtd->card->dev, "get dai %s\n", dai->name);
+ return dai;
+ }
+
+ return NULL;
+}
+
/* these wrappers are only needed to avoid typecast compilation errors */
int sdw_startup(struct snd_pcm_substream *substream)
{
@@ -730,7 +751,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "rt712-sdca-dmic-aif1",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt712_sdca_dmic_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -760,7 +781,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "rt712-sdca-dmic-aif1",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt712_sdca_dmic_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -819,10 +840,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dais = {
{
.direction = {false, true},
- .dai_name = "rt715-aif2",
+ .dai_name = "rt715-sdca-aif2",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt715_sdca_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -834,10 +855,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dais = {
{
.direction = {false, true},
- .dai_name = "rt715-aif2",
+ .dai_name = "rt715-sdca-aif2",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt715_sdca_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -852,7 +873,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "rt715-aif2",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt715_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -867,7 +888,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "rt715-aif2",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .rtd_init = rt715_rtd_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 1,
@@ -883,6 +904,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
.init = sof_sdw_rt_sdca_jack_init,
.exit = sof_sdw_rt_sdca_jack_exit,
+ .rtd_init = rt_sdca_jack_rtd_init,
},
{
.direction = {true, false},
@@ -890,14 +912,14 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_type = SOF_SDW_DAI_TYPE_AMP,
/* No feedback capability is provided by rt722-sdca codec driver*/
.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
- .init = sof_sdw_rt722_spk_init,
+ .rtd_init = rt722_spk_rtd_init,
},
{
.direction = {false, true},
.dai_name = "rt722-sdca-aif3",
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt722_sdca_dmic_init,
+ .rtd_init = rt_dmic_rtd_init,
},
},
.dai_num = 3,
@@ -994,8 +1016,17 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_type = SOF_SDW_DAI_TYPE_JACK,
.dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID},
},
+ {
+ .direction = {true, false},
+ .dai_name = "cs42l43-dp6",
+ .dai_type = SOF_SDW_DAI_TYPE_AMP,
+ .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
+ .init = sof_sdw_cs42l43_spk_init,
+ .rtd_init = cs42l43_spk_rtd_init,
+ .quirk = SOF_CODEC_SPKR,
+ },
},
- .dai_num = 3,
+ .dai_num = 4,
},
{
.part_id = 0xaaaa, /* generic codec mockup */
@@ -1006,7 +1037,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "sdw-mockup-aif1",
.dai_type = SOF_SDW_DAI_TYPE_JACK,
.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = NULL,
},
},
.dai_num = 1,
@@ -1020,7 +1050,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "sdw-mockup-aif1",
.dai_type = SOF_SDW_DAI_TYPE_JACK,
.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = NULL,
},
},
.dai_num = 1,
@@ -1034,7 +1063,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_name = "sdw-mockup-aif1",
.dai_type = SOF_SDW_DAI_TYPE_AMP,
.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
- .init = NULL,
},
},
.dai_num = 1,
@@ -1048,14 +1076,13 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.direction = {false, true},
.dai_type = SOF_SDW_DAI_TYPE_MIC,
.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = NULL,
},
},
.dai_num = 1,
},
};
-static inline int find_codec_info_part(const u64 adr)
+static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr)
{
unsigned int part_id, sdw_version;
int i;
@@ -1070,102 +1097,41 @@ static inline int find_codec_info_part(const u64 adr)
if (part_id == codec_info_list[i].part_id &&
(!codec_info_list[i].version_id ||
sdw_version == codec_info_list[i].version_id))
- return i;
+ return &codec_info_list[i];
- return -EINVAL;
+ return NULL;
}
-static inline int find_codec_info_acpi(const u8 *acpi_id)
+static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id)
{
int i;
if (!acpi_id[0])
- return -EINVAL;
+ return NULL;
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
- return i;
+ return &codec_info_list[i];
- return -EINVAL;
+ return NULL;
}
-/*
- * get BE dailink number and CPU DAI number based on sdw link adr.
- * Since some sdw slaves may be aggregated, the CPU DAI number
- * may be larger than the number of BE dailinks.
- */
-static int get_dailink_info(struct device *dev,
- const struct snd_soc_acpi_link_adr *adr_link,
- int *sdw_be_num, int *codecs_num)
+static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name,
+ int *dai_index)
{
- bool group_visited[SDW_MAX_GROUPS];
- bool no_aggregation;
- int i;
- int j;
-
- no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
- *sdw_be_num = 0;
-
- if (!adr_link)
- return -EINVAL;
-
- for (i = 0; i < SDW_MAX_GROUPS; i++)
- group_visited[i] = false;
-
- for (; adr_link->num_adr; adr_link++) {
- const struct snd_soc_acpi_endpoint *endpoint;
- struct sof_sdw_codec_info *codec_info;
- int codec_index;
- int stream;
- u64 adr;
-
- /* make sure the link mask has a single bit set */
- if (!is_power_of_2(adr_link->mask))
- return -EINVAL;
-
- for (i = 0; i < adr_link->num_adr; i++) {
- adr = adr_link->adr_d[i].adr;
- codec_index = find_codec_info_part(adr);
- if (codec_index < 0)
- return codec_index;
-
- codec_info = &codec_info_list[codec_index];
-
- *codecs_num += codec_info->dai_num;
-
- if (!adr_link->adr_d[i].name_prefix) {
- dev_err(dev, "codec 0x%llx does not have a name prefix\n",
- adr_link->adr_d[i].adr);
- return -EINVAL;
- }
-
- endpoint = adr_link->adr_d[i].endpoints;
- if (endpoint->aggregated && !endpoint->group_id) {
- dev_err(dev, "invalid group id on link %x\n",
- adr_link->mask);
- return -EINVAL;
- }
-
- for (j = 0; j < codec_info->dai_num; j++) {
- /* count DAI number for playback and capture */
- for_each_pcm_streams(stream) {
- if (!codec_info->dais[j].direction[stream])
- continue;
+ int i, j;
- /* count BE for each non-aggregated slave or group */
- if (!endpoint->aggregated || no_aggregation ||
- !group_visited[endpoint->group_id])
- (*sdw_be_num)++;
- }
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
+ *dai_index = j;
+ return &codec_info_list[i];
}
-
- if (endpoint->aggregated)
- group_visited[endpoint->group_id] = true;
}
}
- return 0;
+ return NULL;
}
static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
@@ -1250,195 +1216,45 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
return true;
}
-static int fill_sdw_codec_dlc(struct device *dev,
- const struct snd_soc_acpi_link_adr *adr_link,
- struct snd_soc_dai_link_component *codec,
- int adr_index, int dai_index)
+static const char *get_codec_name(struct device *dev,
+ const struct sof_sdw_codec_info *codec_info,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int adr_index)
{
- unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;
u64 adr = adr_link->adr_d[adr_index].adr;
- int codec_index;
-
- codec_index = find_codec_info_part(adr);
- if (codec_index < 0)
- return codec_index;
-
- sdw_version = SDW_VERSION(adr);
- link_id = SDW_DISCO_LINK_ID(adr);
- unique_id = SDW_UNIQUE_ID(adr);
- mfg_id = SDW_MFG_ID(adr);
- part_id = SDW_PART_ID(adr);
- class_id = SDW_CLASS_ID(adr);
-
- if (codec_info_list[codec_index].codec_name)
- codec->name = devm_kstrdup(dev,
- codec_info_list[codec_index].codec_name,
- GFP_KERNEL);
+ unsigned int sdw_version = SDW_VERSION(adr);
+ unsigned int link_id = SDW_DISCO_LINK_ID(adr);
+ unsigned int unique_id = SDW_UNIQUE_ID(adr);
+ unsigned int mfg_id = SDW_MFG_ID(adr);
+ unsigned int part_id = SDW_PART_ID(adr);
+ unsigned int class_id = SDW_CLASS_ID(adr);
+
+ if (codec_info->codec_name)
+ return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL);
else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
class_id, adr_index))
- codec->name = devm_kasprintf(dev, GFP_KERNEL,
- "sdw:0:%01x:%04x:%04x:%02x", link_id,
- mfg_id, part_id, class_id);
+ return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
+ link_id, mfg_id, part_id, class_id);
else
- codec->name = devm_kasprintf(dev, GFP_KERNEL,
- "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id,
- mfg_id, part_id, class_id, unique_id);
-
- if (!codec->name)
- return -ENOMEM;
-
- codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name;
-
- return 0;
-}
-
-static int set_codec_init_func(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *adr_link,
- struct snd_soc_dai_link *dai_links,
- bool playback, int group_id, int adr_index, int dai_index)
-{
- int i = adr_index;
-
- do {
- /*
- * Initialize the codec. If codec is part of an aggregated
- * group (group_id>0), initialize all codecs belonging to
- * same group.
- * The first link should start with adr_link->adr_d[adr_index]
- * because that is the device that we want to initialize and
- * we should end immediately if it is not aggregated (group_id=0)
- */
- for ( ; i < adr_link->num_adr; i++) {
- int codec_index;
-
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
-
- /* The group_id is > 0 iff the codec is aggregated */
- if (adr_link->adr_d[i].endpoints->group_id != group_id)
- continue;
-
- if (codec_info_list[codec_index].dais[dai_index].init)
- codec_info_list[codec_index].dais[dai_index].init(card,
- adr_link,
- dai_links,
- &codec_info_list[codec_index],
- playback);
- if (!group_id)
- return 0;
- }
-
- i = 0;
- adr_link++;
- } while (adr_link->mask);
-
- return 0;
-}
-
-/*
- * check endpoint status in slaves and gather link ID for all slaves in
- * the same group to generate different CPU DAI. Now only support
- * one sdw link with all slaves set with only single group id.
- *
- * one slave on one sdw link with aggregated = 0
- * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
- *
- * two or more slaves on one sdw link with aggregated = 0
- * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
- *
- * multiple links with multiple slaves with aggregated = 1
- * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
- */
-static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
- struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
- int *codec_num, unsigned int *group_id,
- int adr_index)
-{
- bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
- int i;
-
- if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) {
- cpu_dai_id[0] = ffs(adr_link->mask) - 1;
- *cpu_dai_num = 1;
- *codec_num = 1;
- *group_id = 0;
- return 0;
- }
-
- *codec_num = 0;
- *cpu_dai_num = 0;
- *group_id = adr_link->adr_d[adr_index].endpoints->group_id;
-
- /* Count endpoints with the same group_id in the adr_link */
- for (; adr_link && adr_link->num_adr; adr_link++) {
- unsigned int link_codecs = 0;
-
- for (i = 0; i < adr_link->num_adr; i++) {
- if (adr_link->adr_d[i].endpoints->aggregated &&
- adr_link->adr_d[i].endpoints->group_id == *group_id)
- link_codecs++;
- }
-
- if (link_codecs) {
- *codec_num += link_codecs;
-
- if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) {
- dev_err(dev, "cpu_dai_id array overflowed\n");
- return -EINVAL;
- }
+ return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
+ link_id, mfg_id, part_id, class_id, unique_id);
- cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1;
- }
- }
-
- return 0;
-}
-
-static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps,
- int codec_num, int cpu_num)
-{
- int step;
- int i;
-
- step = codec_num / cpu_num;
- for (i = 0; i < codec_num; i++) {
- sdw_codec_ch_maps[i].cpu = i / step;
- sdw_codec_ch_maps[i].codec = i;
- }
-}
-
-static inline int find_codec_info_dai(const char *dai_name, int *dai_index)
-{
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
- for (j = 0; j < codec_info_list[i].dai_num; j++) {
- if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
- *dai_index = j;
- return i;
- }
- }
- }
-
- return -EINVAL;
+ return NULL;
}
static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_sdw_codec_info *codec_info;
struct snd_soc_dai *dai;
- int codec_index;
int dai_index;
int ret;
int i;
for_each_rtd_codec_dais(rtd, i, dai) {
- codec_index = find_codec_info_dai(dai->name, &dai_index);
- if (codec_index < 0)
+ codec_info = find_codec_info_dai(dai->name, &dai_index);
+ if (!codec_info)
return -EINVAL;
- codec_info = &codec_info_list[codec_index];
/*
* A codec dai can be connected to different dai links for capture and playback,
* but we only need to call the rtd_init function once.
@@ -1458,187 +1274,445 @@ static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+struct sof_sdw_endpoint {
+ struct list_head list;
+
+ u32 link_mask;
+ const char *codec_name;
+
+ struct sof_sdw_codec_info *codec_info;
+ const struct sof_sdw_dai_info *dai_info;
+};
+
+struct sof_sdw_dailink {
+ bool initialised;
+
+ u8 group_id;
+ u32 link_mask[SNDRV_PCM_STREAM_LAST + 1];
+ int num_devs[SNDRV_PCM_STREAM_LAST + 1];
+ struct list_head endpoints;
+};
+
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
-static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
- struct snd_soc_dai_link *dai_links, int sdw_be_num,
- const struct snd_soc_acpi_link_adr *adr_link,
- struct snd_soc_codec_conf *codec_conf,
- int codec_count, int *be_id,
- int *codec_conf_index,
- bool *ignore_pch_dmic,
- bool append_dai_type,
- int adr_index,
- int dai_index)
+static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct device *dev = card->dev;
- const struct snd_soc_acpi_link_adr *adr_link_next;
- struct snd_soc_dai_link_component *codecs;
- struct snd_soc_dai_link_component *cpus;
- struct sof_sdw_codec_info *codec_info;
- int cpu_dai_id[SDW_MAX_CPU_DAIS];
- int cpu_dai_num;
- unsigned int group_id;
- int codec_dlc_index = 0;
- int codec_index;
- int codec_num;
- int stream;
- int i = 0;
- int j, k;
- int ret;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ const struct snd_soc_acpi_link_adr *adr_link;
+ int i;
- ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
- &group_id, adr_index);
- if (ret)
- return ret;
+ for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
+ *num_devs += adr_link->num_adr;
- codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
- if (!codecs)
- return -ENOMEM;
+ for (i = 0; i < adr_link->num_adr; i++)
+ *num_ends += adr_link->adr_d[i].num_endpoints;
+ }
- /* generate codec name on different links in the same group */
- j = adr_index;
- for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr &&
- i < cpu_dai_num; adr_link_next++) {
- /* skip the link excluded by this processed group */
- if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1)
- continue;
+ dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
- /* j reset after loop, adr_index only applies to first link */
- for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) {
- const struct snd_soc_acpi_endpoint *endpoints;
+ return 0;
+}
- endpoints = adr_link_next->adr_d[j].endpoints;
+static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks,
+ const struct snd_soc_acpi_endpoint *new)
+{
+ while (dailinks->initialised) {
+ if (new->aggregated && dailinks->group_id == new->group_id)
+ return dailinks;
- if (group_id && (!endpoints->aggregated ||
- endpoints->group_id != group_id))
- continue;
+ dailinks++;
+ }
+
+ INIT_LIST_HEAD(&dailinks->endpoints);
+ dailinks->group_id = new->group_id;
+ dailinks->initialised = true;
+
+ return dailinks;
+}
+
+static int parse_sdw_endpoints(struct snd_soc_card *card,
+ struct sof_sdw_dailink *sof_dais,
+ struct sof_sdw_endpoint *sof_ends)
+{
+ struct device *dev = card->dev;
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ struct snd_soc_codec_conf *codec_conf = card->codec_conf;
+ const struct snd_soc_acpi_link_adr *adr_link;
+ struct sof_sdw_endpoint *sof_end = sof_ends;
+ int num_dais = 0;
+ int i, j;
+
+ for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
+ int num_link_dailinks = 0;
+
+ if (!is_power_of_2(adr_link->mask)) {
+ dev_err(dev, "link with multiple mask bits: 0x%x\n",
+ adr_link->mask);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < adr_link->num_adr; i++) {
+ const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
+ struct sof_sdw_codec_info *codec_info;
+ const char *codec_name;
- /* sanity check */
- if (*codec_conf_index >= codec_count) {
- dev_err(dev, "codec_conf array overflowed\n");
+ if (!adr_dev->name_prefix) {
+ dev_err(dev, "codec 0x%llx does not have a name prefix\n",
+ adr_dev->adr);
return -EINVAL;
}
- ret = fill_sdw_codec_dlc(dev, adr_link_next,
- &codecs[codec_dlc_index],
- j, dai_index);
- if (ret)
- return ret;
+ codec_info = find_codec_info_part(adr_dev->adr);
+ if (!codec_info)
+ return -EINVAL;
+
+ ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic;
- codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index];
- codec_conf[*codec_conf_index].name_prefix =
- adr_link_next->adr_d[j].name_prefix;
+ codec_name = get_codec_name(dev, codec_info, adr_link, i);
+ if (!codec_name)
+ return -ENOMEM;
+
+ codec_conf->dlc.name = codec_name;
+ codec_conf->name_prefix = adr_dev->name_prefix;
+ codec_conf++;
+
+ dev_dbg(dev, "Adding prefix %s for %s\n",
+ adr_dev->name_prefix, codec_name);
+
+ for (j = 0; j < adr_dev->num_endpoints; j++) {
+ const struct snd_soc_acpi_endpoint *adr_end;
+ const struct sof_sdw_dai_info *dai_info;
+ struct sof_sdw_dailink *sof_dai;
+ int stream;
+
+ adr_end = &adr_dev->endpoints[j];
+ dai_info = &codec_info->dais[adr_end->num];
+ sof_dai = find_dailink(sof_dais, adr_end);
+
+ if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk))
+ continue;
+
+ dev_dbg(dev,
+ "Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n",
+ ffs(adr_link->mask) - 1, adr_dev->adr,
+ adr_end->num, type_strings[dai_info->dai_type],
+ dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
+ dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
+ adr_end->aggregated ? "group" : "solo",
+ adr_end->group_id);
+
+ if (adr_end->num >= codec_info->dai_num) {
+ dev_err(dev,
+ "%d is too many endpoints for codec: 0x%x\n",
+ adr_end->num, codec_info->part_id);
+ return -EINVAL;
+ }
- codec_dlc_index++;
- (*codec_conf_index)++;
+ for_each_pcm_streams(stream) {
+ if (dai_info->direction[stream] &&
+ dai_info->dailink[stream] < 0) {
+ dev_err(dev,
+ "Invalid dailink id %d for codec: 0x%x\n",
+ dai_info->dailink[stream],
+ codec_info->part_id);
+ return -EINVAL;
+ }
+
+ if (dai_info->direction[stream]) {
+ num_dais += !sof_dai->num_devs[stream];
+ sof_dai->num_devs[stream]++;
+ sof_dai->link_mask[stream] |= adr_link->mask;
+ }
+ }
+
+ num_link_dailinks += !!list_empty(&sof_dai->endpoints);
+ list_add_tail(&sof_end->list, &sof_dai->endpoints);
+
+ sof_end->link_mask = adr_link->mask;
+ sof_end->codec_name = codec_name;
+ sof_end->codec_info = codec_info;
+ sof_end->dai_info = dai_info;
+ sof_end++;
+ }
}
- j = 0;
- /* check next link to create codec dai in the processed group */
- i++;
+ ctx->append_dai_type |= (num_link_dailinks > 1);
}
- /* find codec info to create BE DAI */
- codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr);
- if (codec_index < 0)
- return codec_index;
- codec_info = &codec_info_list[codec_index];
+ WARN_ON(codec_conf != card->codec_conf + card->num_configs);
+
+ return num_dais;
+}
- if (codec_info->ignore_pch_dmic)
- *ignore_pch_dmic = true;
+static int create_sdw_dailink(struct snd_soc_card *card,
+ struct sof_sdw_dailink *sof_dai,
+ struct snd_soc_dai_link **dai_links,
+ int *be_id)
+{
+ struct device *dev = card->dev;
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct sof_sdw_endpoint *sof_end;
+ int stream;
for_each_pcm_streams(stream) {
- struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps;
- char *name, *cpu_name;
- int playback, capture;
static const char * const sdw_stream_name[] = {
"SDW%d-Playback",
"SDW%d-Capture",
"SDW%d-Playback-%s",
"SDW%d-Capture-%s",
};
+ struct snd_soc_dai_link_ch_map *codec_maps;
+ struct snd_soc_dai_link_component *codecs;
+ struct snd_soc_dai_link_component *cpus;
+ int num_cpus = hweight32(sof_dai->link_mask[stream]);
+ int num_codecs = sof_dai->num_devs[stream];
+ int playback, capture;
+ int cur_link = 0;
+ int i = 0, j = 0;
+ char *name;
- if (!codec_info->dais[dai_index].direction[stream])
+ if (!sof_dai->num_devs[stream])
continue;
- *be_id = codec_info->dais[dai_index].dailink[stream];
+ sof_end = list_first_entry(&sof_dai->endpoints,
+ struct sof_sdw_endpoint, list);
+
+ *be_id = sof_end->dai_info->dailink[stream];
if (*be_id < 0) {
dev_err(dev, "Invalid dailink id %d\n", *be_id);
return -EINVAL;
}
- sdw_codec_ch_maps = devm_kcalloc(dev, codec_num,
- sizeof(*sdw_codec_ch_maps), GFP_KERNEL);
- if (!sdw_codec_ch_maps)
- return -ENOMEM;
-
/* create stream name according to first link id */
- if (append_dai_type) {
+ if (ctx->append_dai_type)
name = devm_kasprintf(dev, GFP_KERNEL,
- sdw_stream_name[stream + 2], cpu_dai_id[0],
- type_strings[codec_info->dais[dai_index].dai_type]);
- } else {
+ sdw_stream_name[stream + 2],
+ ffs(sof_end->link_mask) - 1,
+ type_strings[sof_end->dai_info->dai_type]);
+ else
name = devm_kasprintf(dev, GFP_KERNEL,
- sdw_stream_name[stream], cpu_dai_id[0]);
- }
+ sdw_stream_name[stream],
+ ffs(sof_end->link_mask) - 1);
if (!name)
return -ENOMEM;
- cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL);
+ cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;
- /*
- * generate CPU DAI name base on the sdw link ID and
- * PIN ID with offset of 2 according to sdw dai driver.
- */
- for (k = 0; k < cpu_dai_num; k++) {
- cpu_name = devm_kasprintf(dev, GFP_KERNEL,
- "SDW%d Pin%d", cpu_dai_id[k],
- ctx->sdw_pin_index[cpu_dai_id[k]]++);
- if (!cpu_name)
- return -ENOMEM;
+ codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
+ if (!codecs)
+ return -ENOMEM;
- cpus[k].dai_name = cpu_name;
- }
+ codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
+ if (!codec_maps)
+ return -ENOMEM;
- /*
- * We create sdw dai links at first stage, so link index should
- * not be larger than sdw_be_num
- */
- if (*link_index >= sdw_be_num) {
- dev_err(dev, "invalid dai link index %d\n", *link_index);
- return -EINVAL;
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (!sof_end->dai_info->direction[stream])
+ continue;
+
+ if (cur_link != sof_end->link_mask) {
+ int link_num = ffs(sof_end->link_mask) - 1;
+ int pin_num = ctx->sdw_pin_index[link_num]++;
+
+ cur_link = sof_end->link_mask;
+
+ cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SDW%d Pin%d",
+ link_num, pin_num);
+ if (!cpus[i].dai_name)
+ return -ENOMEM;
+ i++;
+ }
+
+ codec_maps[j].cpu = i - 1;
+ codec_maps[j].codec = j;
+
+ codecs[j].name = sof_end->codec_name;
+ codecs[j].dai_name = sof_end->dai_info->dai_name;
+ j++;
}
+ WARN_ON(i != num_cpus || j != num_codecs);
+
playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
- init_dai_link(dev, dai_links + *link_index, be_id, name,
- playback, capture, cpus, cpu_dai_num, codecs, codec_num,
+ init_dai_link(dev, *dai_links, be_id, name, playback, capture,
+ cpus, num_cpus, codecs, num_codecs,
sof_sdw_rtd_init, &sdw_ops);
/*
* SoundWire DAILINKs use 'stream' functions and Bank Switch operations
* based on wait_for_completion(), tag them as 'nonatomic'.
*/
- dai_links[*link_index].nonatomic = true;
-
- set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
- dai_links[*link_index].ch_maps = sdw_codec_ch_maps;
- ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
- playback, group_id, adr_index, dai_index);
- if (ret < 0) {
- dev_err(dev, "failed to init codec %d\n", codec_index);
+ (*dai_links)->nonatomic = true;
+ (*dai_links)->ch_maps = codec_maps;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->dai_info->init)
+ sof_end->dai_info->init(card, *dai_links,
+ sof_end->codec_info,
+ playback);
+ }
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+
+static int create_sdw_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct sof_sdw_dailink *sof_dais)
+{
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret, i;
+
+ for (i = 0; i < SDW_MAX_LINKS; i++)
+ ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
+
+ /* generate DAI links by each sdw link */
+ while (sof_dais->initialised) {
+ int current_be_id;
+
+ ret = create_sdw_dailink(card, sof_dais, dai_links, &current_be_id);
+ if (ret)
+ return ret;
+
+ /* Update the be_id to match the highest ID used for SDW link */
+ if (*be_id < current_be_id)
+ *be_id = current_be_id;
+
+ sof_dais++;
+ }
+
+ return 0;
+}
+
+static int create_ssp_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct sof_sdw_codec_info *ssp_info,
+ unsigned long ssp_mask)
+{
+ struct device *dev = card->dev;
+ int i, j = 0;
+ int ret;
+
+ for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
+ char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
+ char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
+ ssp_info->acpi_id, j++);
+ int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
+ int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
+
+ ret = init_simple_dai_link(dev, *dai_links, be_id, name,
+ playback, capture, cpu_dai_name,
+ codec_name, ssp_info->dais[0].dai_name,
+ NULL, ssp_info->ops);
+ if (ret)
+ return ret;
+
+ ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
+ if (ret < 0)
return ret;
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+
+static int create_dmic_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id)
+{
+ struct device *dev = card->dev;
+ int ret;
+
+ ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
+ 0, 1, // DMIC only supports capture
+ "DMIC01 Pin", "dmic-codec", "dmic-hifi",
+ sof_sdw_dmic_init, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
+
+ ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
+ 0, 1, // DMIC only supports capture
+ "DMIC16k Pin", "dmic-codec", "dmic-hifi",
+ /* don't call sof_sdw_dmic_init() twice */
+ NULL, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
+
+ return 0;
+}
+
+static int create_hdmi_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ int hdmi_num)
+{
+ struct device *dev = card->dev;
+ struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int i, ret;
+
+ for (i = 0; i < hdmi_num; i++) {
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
+ char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
+ char *codec_name, *codec_dai_name;
+
+ if (ctx->hdmi.idisp_codec) {
+ codec_name = "ehdaudio0D2";
+ codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "intel-hdmi-hifi%d", i + 1);
+ } else {
+ codec_name = "snd-soc-dummy";
+ codec_dai_name = "snd-soc-dummy-dai";
}
+
+ ret = init_simple_dai_link(dev, *dai_links, be_id, name,
+ 1, 0, // HDMI only supports playback
+ cpu_dai_name, codec_name, codec_dai_name,
+ i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
}
return 0;
}
+static int create_bt_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id)
+{
+ struct device *dev = card->dev;
+ int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
+ SOF_BT_OFFLOAD_SSP_SHIFT;
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
+ char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
+ int ret;
+
+ ret = init_simple_dai_link(dev, *dai_links, be_id, name,
+ 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name,
+ snd_soc_dummy_dlc.dai_name, NULL, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
+
+ return 0;
+}
+
static int sof_card_dai_links_create(struct snd_soc_card *card)
{
struct device *dev = card->dev;
@@ -1646,38 +1720,61 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
- const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
- bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);
struct snd_soc_codec_conf *codec_conf;
- bool append_dai_type = false;
- bool ignore_pch_dmic = false;
- int codec_conf_num = 0;
- int codec_conf_index = 0;
- bool group_generated[SDW_MAX_GROUPS] = { };
- int ssp_codec_index, ssp_mask;
+ struct sof_sdw_codec_info *ssp_info;
+ struct sof_sdw_endpoint *sof_ends;
+ struct sof_sdw_dailink *sof_dais;
+ int num_devs = 0;
+ int num_ends = 0;
struct snd_soc_dai_link *dai_links;
- int num_links, link_index = 0;
- char *name, *cpu_dai_name;
- char *codec_name, *codec_dai_name;
- int i, j, be_id = 0;
- int codec_index;
+ int num_links;
+ int be_id = 0;
int hdmi_num;
+ unsigned long ssp_mask;
int ret;
- ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num);
+ ret = count_sdw_endpoints(card, &num_devs, &num_ends);
if (ret < 0) {
- dev_err(dev, "failed to get sdw link info %d\n", ret);
+ dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
}
+ /* One per DAI link, worst case is a DAI link for every endpoint */
+ sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL);
+ if (!sof_dais)
+ return -ENOMEM;
+
+ /* One per endpoint, ie. each DAI on each codec/amp */
+ sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
+ if (!sof_ends) {
+ ret = -ENOMEM;
+ goto err_dai;
+ }
+
+ /* will be populated when acpi endpoints are parsed */
+ codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
+ if (!codec_conf) {
+ ret = -ENOMEM;
+ goto err_end;
+ }
+
+ card->codec_conf = codec_conf;
+ card->num_configs = num_devs;
+
+ ret = parse_sdw_endpoints(card, sof_dais, sof_ends);
+ if (ret < 0)
+ goto err_end;
+
+ sdw_be_num = ret;
+
/*
* on generic tgl platform, I2S or sdw mode is supported
* based on board rework. A ACPI device is registered in
* system only when I2S mode is supported, not sdw mode.
* Here check ACPI ID to confirm I2S is supported.
*/
- ssp_codec_index = find_codec_info_acpi(mach->id);
- if (ssp_codec_index >= 0) {
+ ssp_info = find_codec_info_acpi(mach->id);
+ if (ssp_info) {
ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
ssp_num = hweight_long(ssp_mask);
}
@@ -1704,201 +1801,60 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
/* allocate BE dailinks */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
- if (!dai_links)
- return -ENOMEM;
-
- /* allocate codec conf, will be populated when dailinks are created */
- codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf),
- GFP_KERNEL);
- if (!codec_conf)
- return -ENOMEM;
-
- /* SDW */
- if (!sdw_be_num)
- goto SSP;
-
- for (i = 0; i < SDW_MAX_LINKS; i++)
- ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
-
- for (; adr_link->num_adr; adr_link++) {
- /*
- * If there are two or more different devices on the same sdw link, we have to
- * append the codec type to the dai link name to prevent duplicated dai link name.
- * The same type devices on the same sdw link will be in the same
- * snd_soc_acpi_adr_device array. They won't be described in different adr_links.
- */
- for (i = 0; i < adr_link->num_adr; i++) {
- /* find codec info to get dai_num */
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
- if (codec_info_list[codec_index].dai_num > 1) {
- append_dai_type = true;
- goto out;
- }
- for (j = 0; j < i; j++) {
- if ((SDW_PART_ID(adr_link->adr_d[i].adr) !=
- SDW_PART_ID(adr_link->adr_d[j].adr)) ||
- (SDW_MFG_ID(adr_link->adr_d[i].adr) !=
- SDW_MFG_ID(adr_link->adr_d[j].adr))) {
- append_dai_type = true;
- goto out;
- }
- }
- }
+ if (!dai_links) {
+ ret = -ENOMEM;
+ goto err_end;
}
-out:
-
- /* generate DAI links by each sdw link */
- for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) {
- for (i = 0; i < adr_link->num_adr; i++) {
- const struct snd_soc_acpi_endpoint *endpoint;
-
- endpoint = adr_link->adr_d[i].endpoints;
-
- /* this group has been generated */
- if (endpoint->aggregated &&
- group_generated[endpoint->group_id])
- continue;
- /* find codec info to get dai_num */
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
-
- for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
- int current_be_id;
-
- ret = create_sdw_dailink(card, &link_index, dai_links,
- sdw_be_num, adr_link,
- codec_conf, codec_conf_num,
- &current_be_id, &codec_conf_index,
- &ignore_pch_dmic, append_dai_type, i, j);
- if (ret < 0) {
- dev_err(dev, "failed to create dai link %d\n", link_index);
- return ret;
- }
-
- /* Update the be_id to match the highest ID used for SDW link */
- if (be_id < current_be_id)
- be_id = current_be_id;
- }
+ card->dai_link = dai_links;
+ card->num_links = num_links;
- if (aggregation && endpoint->aggregated)
- group_generated[endpoint->group_id] = true;
- }
+ /* SDW */
+ if (sdw_be_num) {
+ ret = create_sdw_dailinks(card, &dai_links, &be_id, sof_dais);
+ if (ret)
+ goto err_end;
}
-SSP:
/* SSP */
- if (!ssp_num)
- goto DMIC;
-
- for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
- struct sof_sdw_codec_info *info;
- int playback, capture;
-
- if (!(ssp_mask & 0x1))
- continue;
-
- info = &codec_info_list[ssp_codec_index];
-
- name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
- cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
- codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
- info->acpi_id, j++);
-
- playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
- capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
-
- ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
- playback, capture, cpu_dai_name,
- codec_name, info->dais[0].dai_name,
- NULL, info->ops);
+ if (ssp_num) {
+ ret = create_ssp_dailinks(card, &dai_links, &be_id,
+ ssp_info, ssp_mask);
if (ret)
- return ret;
-
- ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0);
- if (ret < 0)
- return ret;
-
- link_index++;
+ goto err_end;
}
-DMIC:
/* dmic */
if (dmic_num > 0) {
- if (ignore_pch_dmic) {
+ if (ctx->ignore_pch_dmic) {
dev_warn(dev, "Ignoring PCH DMIC\n");
- goto HDMI;
+ } else {
+ ret = create_dmic_dailinks(card, &dai_links, &be_id);
+ if (ret)
+ goto err_end;
}
-
- ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic01",
- 0, 1, // DMIC only supports capture
- "DMIC01 Pin", "dmic-codec", "dmic-hifi",
- sof_sdw_dmic_init, NULL);
- if (ret)
- return ret;
-
- link_index++;
-
- ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic16k",
- 0, 1, // DMIC only supports capture
- "DMIC16k Pin", "dmic-codec", "dmic-hifi",
- /* don't call sof_sdw_dmic_init() twice */
- NULL, NULL);
- if (ret)
- return ret;
-
- link_index++;
}
-HDMI:
/* HDMI */
- for (i = 0; i < hdmi_num; i++) {
- name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
- cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
-
- if (ctx->hdmi.idisp_codec) {
- codec_name = "ehdaudio0D2";
- codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "intel-hdmi-hifi%d", i + 1);
- } else {
- codec_name = "snd-soc-dummy";
- codec_dai_name = "snd-soc-dummy-dai";
- }
-
- ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
- 1, 0, // HDMI only supports playback
- cpu_dai_name, codec_name, codec_dai_name,
- i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
- if (ret)
- return ret;
-
- link_index++;
- }
+ ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
+ if (ret)
+ goto err_end;
+ /* BT */
if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
- cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
-
- ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name,
- 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name,
- snd_soc_dummy_dlc.dai_name, NULL, NULL);
+ ret = create_bt_dailinks(card, &dai_links, &be_id);
if (ret)
- return ret;
+ goto err_end;
}
- card->dai_link = dai_links;
- card->num_links = num_links;
+ WARN_ON(dai_links != card->dai_link + card->num_links);
- card->codec_conf = codec_conf;
- card->num_configs = codec_conf_num;
+err_end:
+ kfree(sof_ends);
+err_dai:
+ kfree(sof_dais);
- return 0;
+ return ret;
}
static int sof_sdw_card_late_probe(struct snd_soc_card *card)
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index b1d57034361c..8468487a6bd6 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -50,7 +50,10 @@ enum {
#define SOF_SDW_PCH_DMIC BIT(6)
#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7)
#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0))
+/* Deprecated and no longer supported by the code */
#define SOF_SDW_NO_AGGREGATION BIT(14)
+/* If a CODEC has an optional speaker output, this quirk will enable it */
+#define SOF_CODEC_SPKR BIT(15)
/* BT audio offload: reserve 3 bits for future */
#define SOF_BT_OFFLOAD_SSP_SHIFT 15
@@ -63,7 +66,7 @@ enum {
#define SOF_SDW_DAI_TYPE_AMP 1
#define SOF_SDW_DAI_TYPE_MIC 2
-#define SOF_SDW_MAX_DAI_NUM 3
+#define SOF_SDW_MAX_DAI_NUM 8
struct sof_sdw_codec_info;
@@ -73,13 +76,13 @@ struct sof_sdw_dai_info {
const int dai_type;
const int dailink[2]; /* dailink id for each direction */
int (*init)(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
int (*rtd_init)(struct snd_soc_pcm_runtime *rtd);
bool rtd_init_done; /* Indicate that the rtd_init callback is done */
+ unsigned long quirk;
};
struct sof_sdw_codec_info {
@@ -103,10 +106,16 @@ struct mc_private {
struct device *amp_dev1, *amp_dev2;
/* To store SDW Pin index for each SoundWire link */
unsigned int sdw_pin_index[SDW_MAX_LINKS];
+ bool append_dai_type;
+ bool ignore_pch_dmic;
};
extern unsigned long sof_sdw_quirk;
+struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd,
+ const char * const dai_name[],
+ int num_dais);
+
int sdw_startup(struct snd_pcm_substream *substream);
int sdw_prepare(struct snd_pcm_substream *substream);
int sdw_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -125,7 +134,6 @@ int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd);
/* RT711 support */
int sof_sdw_rt711_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
@@ -133,7 +141,6 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
/* RT711-SDCA support */
int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
@@ -144,34 +151,25 @@ extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
/* generic amp support */
int sof_sdw_rt_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-/* RT722-SDCA support */
-int sof_sdw_rt722_spk_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
/* MAXIM codec support */
int sof_sdw_maxim_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
+/* CS42L43 support */
+int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback);
+
/* CS AMP support */
int sof_sdw_cs_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback);
@@ -180,16 +178,16 @@ int sof_sdw_cs_amp_init(struct snd_soc_card *card,
int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd);
int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd);
+int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd);
int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd);
-int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
-int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd);
-int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd);
+int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
+int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd);
int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd);
diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c
index 0dc297f7de01..b999f4e7901a 100644
--- a/sound/soc/intel/boards/sof_sdw_cs42l42.c
+++ b/sound/soc/intel/boards/sof_sdw_cs42l42.c
@@ -15,7 +15,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
static const struct snd_soc_dapm_widget cs42l42_widgets[] = {
diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/intel/boards/sof_sdw_cs42l43.c
index a9b6edac2ecd..5361249f0f53 100644
--- a/sound/soc/intel/boards/sof_sdw_cs42l43.c
+++ b/sound/soc/intel/boards/sof_sdw_cs42l43.c
@@ -30,6 +30,17 @@ static const struct snd_soc_dapm_route cs42l43_hs_map[] = {
{ "cs42l43 ADC1_IN1_N", NULL, "Headset Mic" },
};
+static const struct snd_soc_dapm_widget cs42l43_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route cs42l43_spk_map[] = {
+ { "Speaker", NULL, "cs42l43 AMP1_OUT_P", },
+ { "Speaker", NULL, "cs42l43 AMP1_OUT_N", },
+ { "Speaker", NULL, "cs42l43 AMP2_OUT_P", },
+ { "Speaker", NULL, "cs42l43 AMP2_OUT_N", },
+};
+
static const struct snd_soc_dapm_widget cs42l43_dmic_widgets[] = {
SND_SOC_DAPM_MIC("DMIC", NULL),
};
@@ -108,6 +119,45 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
+int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:cs42l43-spk",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_spk_widgets,
+ ARRAY_SIZE(cs42l43_spk_widgets));
+ if (ret) {
+ dev_err(card->dev, "cs42l43 speaker widgets addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_spk_map,
+ ARRAY_SIZE(cs42l43_spk_map));
+ if (ret)
+ dev_err(card->dev, "cs42l43 speaker map addition failed: %d\n", ret);
+
+ return ret;
+}
+
+int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback)
+{
+ /* Do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+
+ return 0;
+}
+
int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c
index 56cf75bc6cc4..e29a586ce7c0 100644
--- a/sound/soc/intel/boards/sof_sdw_cs_amp.c
+++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c
@@ -57,7 +57,6 @@ int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
}
int sof_sdw_cs_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/intel/boards/sof_sdw_maxim.c
index 034730432671..432e5112415a 100644
--- a/sound/soc/intel/boards/sof_sdw_maxim.c
+++ b/sound/soc/intel/boards/sof_sdw_maxim.c
@@ -139,7 +139,6 @@ static int mx8373_sdw_late_probe(struct snd_soc_card *card)
}
int sof_sdw_maxim_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c
index 6b008a5a343b..f812aea64322 100644
--- a/sound/soc/intel/boards/sof_sdw_rt5682.c
+++ b/sound/soc/intel/boards/sof_sdw_rt5682.c
@@ -15,7 +15,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
static const struct snd_soc_dapm_widget rt5682_widgets[] = {
diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c
index 88e785a54b16..a2648c900e74 100644
--- a/sound/soc/intel/boards/sof_sdw_rt700.c
+++ b/sound/soc/intel/boards/sof_sdw_rt700.c
@@ -13,7 +13,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
static const struct snd_soc_dapm_widget rt700_widgets[] = {
diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c
index cdd1587b246c..7e54fc5cbe09 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711.c
+++ b/sound/soc/intel/boards/sof_sdw_rt711.c
@@ -15,7 +15,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
/*
@@ -159,7 +158,6 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
}
int sof_sdw_rt711_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c
index ebb4b58c198b..0c4cd4cdbd45 100644
--- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c
+++ b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c
@@ -13,7 +13,6 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
static const struct snd_soc_dapm_widget rt712_spk_widgets[] = {
@@ -67,27 +66,3 @@ int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static const char * const dmics[] = {
- "rt712-sdca-dmic"
-};
-
-int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_component *component;
-
- codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics));
- if (!codec_dai)
- return -EINVAL;
-
- component = codec_dai->component;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:%s",
- card->components, component->name_prefix);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c
deleted file mode 100644
index b5a886cd595d..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt715.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt715 - Helpers to handle RT715 from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "sof_sdw_common.h"
-
-int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:rt715",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
diff --git a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c
deleted file mode 100644
index 4b37a8a6dd2e..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt715_sdca - Helpers to handle RT715-SDCA from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "sof_sdw_common.h"
-
-int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:rt715-sdca",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c
index fe3a2bff95bc..e5c2a36e400b 100644
--- a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c
+++ b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c
@@ -27,7 +27,7 @@ static const struct snd_kcontrol_new rt722_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Speaker"),
};
-static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd)
+int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret;
@@ -59,39 +59,3 @@ static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-int sof_sdw_rt722_spk_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt722_spk_init;
-
- return 0;
-}
-
-static int rt722_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:%s",
- card->components, component->name_prefix);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
-int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt722_sdca_dmic_rtd_init;
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c
index 202edab95000..1b415708500e 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_amp.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c
@@ -281,7 +281,6 @@ int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_
}
int sof_sdw_rt_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/intel/boards/sof_sdw_rt_dmic.c
new file mode 100644
index 000000000000..2f7ed9b31e79
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_rt_dmic.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2024 Intel Corporation
+
+/*
+ * sof_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "sof_board_helpers.h"
+#include "sof_sdw_common.h"
+
+static const char * const dmics[] = {
+ "rt715",
+ "rt715-sdca",
+ "rt712-sdca-dmic",
+ "rt722-sdca",
+};
+
+int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_component *component;
+ struct snd_soc_dai *codec_dai;
+ char *mic_name;
+
+ codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics));
+ if (!codec_dai)
+ return -EINVAL;
+
+ component = codec_dai->component;
+
+ /*
+ * rt715-sdca (aka rt714) is a special case that uses different name in card->components
+ * and component->name_prefix.
+ */
+ if (!strcmp(component->name_prefix, "rt714"))
+ mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "rt715-sdca");
+ else
+ mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_prefix);
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s mic:%s", card->components,
+ mic_name);
+ if (!card->components)
+ return -ENOMEM;
+
+ dev_dbg(card->dev, "card->components: %s\n", card->components);
+
+ return 0;
+}
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
index 5253d8332780..85c09513bc35 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
+++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
@@ -15,7 +15,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_board_helpers.h"
#include "sof_sdw_common.h"
/*
@@ -86,7 +85,7 @@ static struct snd_soc_jack_pin rt_sdca_jack_pins[] = {
};
static const char * const jack_codecs[] = {
- "rt711", "rt712", "rt713"
+ "rt711", "rt712", "rt713", "rt722"
};
int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd)
@@ -192,7 +191,6 @@ int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link
}
int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
bool playback)
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
index ee2e813bf4c0..206c9b723805 100644
--- a/sound/soc/intel/boards/sof_ssp_amp.c
+++ b/sound/soc/intel/boards/sof_ssp_amp.c
@@ -20,34 +20,12 @@
#include "sof_board_helpers.h"
#include "sof_realtek_common.h"
#include "sof_cirrus_common.h"
-#include "sof_ssp_common.h"
-
-/* SSP port ID for speaker amplifier */
-#define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0))
-#define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0))
-
-/* HDMI capture*/
-#define SOF_HDMI_CAPTURE_SSP_MASK_SHIFT 4
-#define SOF_HDMI_CAPTURE_SSP_MASK_MASK (GENMASK(9, 4))
-#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \
- (((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_MASK)
-
-/* HDMI playback */
-#define SOF_HDMI_PLAYBACK_PRESENT BIT(13)
-#define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14
-#define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14))
-#define SOF_NO_OF_HDMI_PLAYBACK(quirk) \
- (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
-
-/* BT audio offload */
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17)
-#define SOF_BT_OFFLOAD_SSP_SHIFT 18
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
+
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_HDMI_PLAYBACK_PRESENT BIT(0)
/* Default: SSP2 */
-static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
+static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2);
static const struct dmi_system_id chromebook_platforms[] = {
{
@@ -75,197 +53,107 @@ static struct snd_soc_card sof_ssp_amp_card = {
#define HDMI_IN_BE_ID 0
#define SPK_BE_ID 2
#define DMIC01_BE_ID 3
-#define DMIC16K_BE_ID 4
#define INTEL_HDMI_BE_ID 5
-
-static struct snd_soc_dai_link *
-sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type,
- int ssp_amp, int dmic_be_num, int hdmi_num,
- bool idisp_codec)
+/* extra BE links to support no-hdmi-in boards */
+#define DMIC16K_BE_ID 4
+#define BT_OFFLOAD_BE_ID 8
+
+#define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \
+ SOF_LINK_AMP, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_BT_OFFLOAD, \
+ SOF_LINK_NONE)
+
+#define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \
+ SPK_BE_ID, \
+ DMIC01_BE_ID, \
+ DMIC16K_BE_ID, \
+ INTEL_HDMI_BE_ID, \
+ BT_OFFLOAD_BE_ID, \
+ 0)
+
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
{
- struct snd_soc_dai_link *links;
- int i;
- int id = 0;
int ret;
- bool fixed_be = false;
- int be_id;
- unsigned long ssp_mask_hdmi_in;
-
- links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
- sizeof(struct snd_soc_dai_link), GFP_KERNEL);
- if (!links)
- return NULL;
-
- /* HDMI-In SSP */
- ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >>
- SOF_HDMI_CAPTURE_SSP_MASK_SHIFT;
-
- if (ssp_mask_hdmi_in) {
- int port = 0;
-
- /* the topology supports HDMI-IN uses fixed BE ID for DAI links */
- fixed_be = true;
-
- be_id = HDMI_IN_BE_ID;
- for_each_set_bit(port, &ssp_mask_hdmi_in, 32) {
- ret = sof_intel_board_set_hdmi_in_link(dev, &links[id],
- be_id, port);
- if (ret)
- return NULL;
-
- id++;
- be_id++;
- }
- }
-
- /* codec SSP */
- if (amp_type != CODEC_NONE) {
- be_id = fixed_be ? SPK_BE_ID : id;
- ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id,
- amp_type, ssp_amp);
- if (ret)
- return NULL;
-
- /* codec-specific fields */
- switch (amp_type) {
- case CODEC_CS35L41:
- cs35l41_set_dai_link(&links[id]);
- break;
- case CODEC_RT1308:
- sof_rt1308_dai_link(&links[id]);
- break;
- default:
- dev_err(dev, "invalid amp type %d\n", amp_type);
- return NULL;
- }
- id++;
- }
-
- /* dmic */
- if (dmic_be_num > 0) {
- /* at least we have dmic01 */
- be_id = fixed_be ? DMIC01_BE_ID : id;
- ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id,
- SOF_DMIC_01);
- if (ret)
- return NULL;
-
- id++;
- }
-
- if (dmic_be_num > 1) {
- /* set up 2 BE links at most */
- be_id = fixed_be ? DMIC16K_BE_ID : id;
- ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id,
- SOF_DMIC_16K);
- if (ret)
- return NULL;
-
- id++;
- }
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
- /* HDMI playback */
- for (i = 1; i <= hdmi_num; i++) {
- be_id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id;
- ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], be_id,
- i, idisp_codec);
- if (ret)
- return NULL;
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
- id++;
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
}
- /* BT audio offload */
- if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- ret = sof_intel_board_set_bt_link(dev, &links[id], id, port);
- if (ret)
- return NULL;
-
- id++;
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_CS35L41:
+ cs35l41_set_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1308:
+ sof_rt1308_dai_link(ctx->amp_link);
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- return links;
+ return 0;
}
static int sof_ssp_amp_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
- struct snd_soc_dai_link *dai_links;
struct sof_card_private *ctx;
int ret;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
- ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
+ dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk);
- if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
- ctx->dmic_be_num = 2;
- else
- ctx->dmic_be_num = 0;
-
- /* port number/mask of peripherals attached to ssp interface */
- ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >>
- SOF_HDMI_CAPTURE_SSP_MASK_SHIFT;
-
- ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
-
- /* set number of dai links */
- sof_ssp_amp_card.num_links = ctx->dmic_be_num;
-
- if (ctx->amp_type != CODEC_NONE)
- sof_ssp_amp_card.num_links++;
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk);
+ if (!ctx)
+ return -ENOMEM;
- if (ctx->ssp_mask_hdmi_in)
- sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in);
+ if (!dmi_check_system(chromebook_platforms) &&
+ (mach->mach_params.dmic_num == 0))
+ ctx->dmic_be_num = 0;
if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
- ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
- SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
- /* default number of HDMI DAI's */
- if (!ctx->hdmi_num)
- ctx->hdmi_num = 3;
-
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
-
- sof_ssp_amp_card.num_links += ctx->hdmi_num;
} else {
ctx->hdmi_num = 0;
}
- if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- ctx->bt_offload_present = true;
- sof_ssp_amp_card.num_links++;
- }
+ ctx->link_order_overwrite = SSP_AMP_LINK_ORDER;
- dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type,
- ctx->ssp_amp, ctx->dmic_be_num,
- ctx->hdmi_num,
- ctx->hdmi.idisp_codec);
- if (!dai_links)
- return -ENOMEM;
+ if (ctx->ssp_mask_hdmi_in) {
+ /* the topology supports HDMI-IN uses fixed BE ID for DAI links */
+ ctx->link_id_overwrite = SSP_AMP_LINK_IDS;
+ }
- sof_ssp_amp_card.dai_link = dai_links;
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx);
+ if (ret)
+ return ret;
/* update codec_conf */
switch (ctx->amp_type) {
case CODEC_CS35L41:
cs35l41_set_codec_conf(&sof_ssp_amp_card);
break;
- case CODEC_NONE:
case CODEC_RT1308:
+ case CODEC_NONE:
/* no codec conf required */
break;
default:
@@ -292,38 +180,35 @@ static const struct platform_device_id board_ids[] = {
},
{
.name = "tgl_rt1308_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
- SOF_HDMI_CAPTURE_SSP_MASK(0x22)),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) |
+ SOF_SSP_MASK_HDMI_CAPTURE(0x22)),
/* SSP 1 and SSP 5 are used for HDMI IN */
},
{
.name = "adl_cs35l41",
- .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
- SOF_NO_OF_HDMI_PLAYBACK(4) |
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
SOF_HDMI_PLAYBACK_PRESENT |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "adl_lt6911_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
/* SSP 0 and SSP 2 are used for HDMI IN */
- SOF_NO_OF_HDMI_PLAYBACK(3) |
SOF_HDMI_PLAYBACK_PRESENT),
},
{
.name = "rpl_lt6911_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
/* SSP 0 and SSP 2 are used for HDMI IN */
- SOF_NO_OF_HDMI_PLAYBACK(3) |
SOF_HDMI_PLAYBACK_PRESENT),
},
{
.name = "mtl_lt6911_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
- /* SSP 0 and SSP 2 are used for HDMI IN */
- SOF_NO_OF_HDMI_PLAYBACK(3) |
- SOF_HDMI_PLAYBACK_PRESENT),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
},
{ }
};
@@ -346,4 +231,3 @@ MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_ssp_common.c b/sound/soc/intel/boards/sof_ssp_common.c
deleted file mode 100644
index 96072790e9c0..000000000000
--- a/sound/soc/intel/boards/sof_ssp_common.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// Copyright(c) 2023 Intel Corporation. All rights reserved.
-
-#include <linux/device.h>
-#include <sound/soc-acpi.h>
-#include "sof_ssp_common.h"
-
-/*
- * Codec probe function
- */
-#define CODEC_MAP_ENTRY(n, h, t) \
- { \
- .name = n, \
- .acpi_hid = h, \
- .codec_type = t, \
- }
-
-struct codec_map {
- const char *name;
- const char *acpi_hid;
- enum sof_ssp_codec codec_type;
-};
-
-static const struct codec_map codecs[] = {
- /* Cirrus Logic */
- CODEC_MAP_ENTRY("CS42L42", CS42L42_ACPI_HID, CODEC_CS42L42),
-
- /* Dialog */
- CODEC_MAP_ENTRY("DA7219", DA7219_ACPI_HID, CODEC_DA7219),
-
- /* Everest */
- CODEC_MAP_ENTRY("ES8316", ES8316_ACPI_HID, CODEC_ES8316),
- CODEC_MAP_ENTRY("ES8326", ES8326_ACPI_HID, CODEC_ES8326),
- CODEC_MAP_ENTRY("ES8336", ES8336_ACPI_HID, CODEC_ES8336),
-
- /* Nuvoton */
- CODEC_MAP_ENTRY("NAU8825", NAU8825_ACPI_HID, CODEC_NAU8825),
-
- /* Realtek */
- CODEC_MAP_ENTRY("RT5650", RT5650_ACPI_HID, CODEC_RT5650),
- CODEC_MAP_ENTRY("RT5682", RT5682_ACPI_HID, CODEC_RT5682),
- CODEC_MAP_ENTRY("RT5682S", RT5682S_ACPI_HID, CODEC_RT5682S),
-};
-
-static const struct codec_map amps[] = {
- /* Cirrus Logic */
- CODEC_MAP_ENTRY("CS35L41", CS35L41_ACPI_HID, CODEC_CS35L41),
-
- /* Maxim */
- CODEC_MAP_ENTRY("MAX98357A", MAX_98357A_ACPI_HID, CODEC_MAX98357A),
- CODEC_MAP_ENTRY("MAX98360A", MAX_98360A_ACPI_HID, CODEC_MAX98360A),
- CODEC_MAP_ENTRY("MAX98373", MAX_98373_ACPI_HID, CODEC_MAX98373),
- CODEC_MAP_ENTRY("MAX98390", MAX_98390_ACPI_HID, CODEC_MAX98390),
-
- /* Nuvoton */
- CODEC_MAP_ENTRY("NAU8318", NAU8318_ACPI_HID, CODEC_NAU8318),
-
- /* Realtek */
- CODEC_MAP_ENTRY("RT1011", RT1011_ACPI_HID, CODEC_RT1011),
- CODEC_MAP_ENTRY("RT1015", RT1015_ACPI_HID, CODEC_RT1015),
- CODEC_MAP_ENTRY("RT1015P", RT1015P_ACPI_HID, CODEC_RT1015P),
- CODEC_MAP_ENTRY("RT1019P", RT1019P_ACPI_HID, CODEC_RT1019P),
- CODEC_MAP_ENTRY("RT1308", RT1308_ACPI_HID, CODEC_RT1308),
-};
-
-enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(codecs); i++) {
- if (!acpi_dev_present(codecs[i].acpi_hid, NULL, -1))
- continue;
-
- dev_dbg(dev, "codec %s found\n", codecs[i].name);
- return codecs[i].codec_type;
- }
-
- return CODEC_NONE;
-}
-EXPORT_SYMBOL_NS(sof_ssp_detect_codec_type, SND_SOC_INTEL_SOF_SSP_COMMON);
-
-enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(amps); i++) {
- if (!acpi_dev_present(amps[i].acpi_hid, NULL, -1))
- continue;
-
- dev_dbg(dev, "amp %s found\n", amps[i].name);
- return amps[i].codec_type;
- }
-
- return CODEC_NONE;
-}
-EXPORT_SYMBOL_NS(sof_ssp_detect_amp_type, SND_SOC_INTEL_SOF_SSP_COMMON);
-
-const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(codecs); i++) {
- if (codecs[i].codec_type != codec_type)
- continue;
-
- return codecs[i].name;
- }
- for (i = 0; i < ARRAY_SIZE(amps); i++) {
- if (amps[i].codec_type != codec_type)
- continue;
-
- return amps[i].name;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_NS(sof_ssp_get_codec_name, SND_SOC_INTEL_SOF_SSP_COMMON);
-
-MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers");
-MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index f7370e5b4e9e..a86457674726 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -15,5 +15,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-hda-match.o \
soc-acpi-intel-sdw-mockup-match.o
+snd-soc-acpi-intel-match-objs += soc-acpi-intel-ssp-common.o
+
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index 0da79a3ba1f0..1ea2d9c582ee 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -7,6 +7,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
@@ -447,11 +448,6 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = {
{}
};
-static const struct snd_soc_acpi_codecs adl_max98373_amp = {
- .num_codecs = 1,
- .codecs = {"MX98373"}
-};
-
static const struct snd_soc_acpi_codecs adl_max98357a_amp = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -464,12 +460,7 @@ static const struct snd_soc_acpi_codecs adl_max98360a_amp = {
static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
-};
-
-static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
- .num_codecs = 1,
- .codecs = {"RTL1015"}
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
@@ -477,49 +468,20 @@ static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
.codecs = {"RTL1019"}
};
-static const struct snd_soc_acpi_codecs adl_max98390_amp = {
- .num_codecs = 1,
- .codecs = {"MX98390"}
-};
-
static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
.num_codecs = 1,
.codecs = {"INTC10B0"}
};
-static const struct snd_soc_acpi_codecs adl_nau8318_amp = {
- .num_codecs = 1,
- .codecs = {"NVTN2012"}
-};
-
-static struct snd_soc_acpi_codecs adl_rt5650_amp = {
- .num_codecs = 1,
- .codecs = {"10EC5650"}
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
{
.comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98373_amp,
- .sof_tplg_filename = "sof-adl-max98373-rt5682.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
.drv_name = "adl_mx98357_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98357a_amp,
.sof_tplg_filename = "sof-adl-max98357a-rt5682.tplg",
},
{
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-rt5682.tplg",
- },
- {
.id = "10508825",
.drv_name = "adl_rt1019p_8825",
.machine_quirk = snd_soc_acpi_codec_list,
@@ -527,53 +489,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
},
{
- .id = "10508825",
- .drv_name = "adl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98373_amp,
- .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_rt1019p_amp,
- .sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_rt1015p_amp,
- .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_nau8318_amp,
- .sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "sof_nau8825",
- .sof_tplg_filename = "sof-adl-nau8825.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98390_amp,
- .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg",
- },
- {
.comp_ids = &adl_rt5682_rt5682s_hp,
.drv_name = "adl_rt5682_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
@@ -581,18 +496,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg",
},
{
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682_def",
- .sof_tplg_filename = "sof-adl-rt5682.tplg",
- },
- {
- .id = "10134242",
- .drv_name = "adl_mx98360a_cs4242",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg",
- },
- {
.comp_ids = &essx_83x6,
.drv_name = "adl_es83x6_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
@@ -608,19 +511,43 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{
- .id = "10EC5650",
- .drv_name = "adl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_rt5650_amp,
- .sof_tplg_filename = "sof-adl-rt5650.tplg",
- },
- {
.id = "DLGS7219",
- .drv_name = "adl_mx98360_da7219",
+ .drv_name = "adl_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98360a_amp,
.sof_tplg_filename = "sof-adl-max98360a-da7219.tplg",
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "adl_cs42l42_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "adl_nau8825_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
+ .drv_name = "adl_rt5682_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &adl_rt5682_rt5682s_hp,
+ .drv_name = "adl_rt5682_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
/* place amp-only boards in the end of table */
{
.id = "CSC3541",
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index e52797aae6e6..79d26e0f2c28 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -24,6 +24,15 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
static const struct snd_soc_acpi_link_adr arl_rvp[] = {
{
.mask = BIT(0),
@@ -33,6 +42,15 @@ static const struct snd_soc_acpi_link_adr arl_rvp[] = {
{}
};
+static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = {
{},
};
@@ -46,6 +64,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711.tplg",
},
+ {
+ .link_mask = 0x1, /* link0 required */
+ .links = arl_sdca_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-rt711-l0.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines);
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 5eab17820532..d47a548959ea 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -49,21 +49,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
},
{
.id = "10EC5682",
- .drv_name = "cml_rt1015_rt5682",
+ .drv_name = "cml_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rt1015_spk_codecs,
.sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
},
{
.id = "10EC5682",
- .drv_name = "sof_rt5682",
+ .drv_name = "cml_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &max98357a_spk_codecs,
.sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
},
{
.id = "10EC5682",
- .drv_name = "sof_rt5682",
+ .drv_name = "cml_rt5682_def",
.sof_tplg_filename = "sof-cml-rt5682.tplg",
},
{
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 a6ac2525df17..d4b397c53bcc 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -52,14 +52,14 @@ static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
{
.id = "DLGS7219",
- .drv_name = "jsl_mx98373_da7219",
+ .drv_name = "jsl_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &mx98373_spk,
.sof_tplg_filename = "sof-jsl-da7219.tplg",
},
{
.id = "DLGS7219",
- .drv_name = "jsl_mx98360_da7219",
+ .drv_name = "jsl_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &mx98360a_spk,
.sof_tplg_filename = "sof-jsl-da7219-mx98360a.tplg",
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index e9a5da079089..75935b454e5d 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -8,6 +8,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs mtl_max98357a_amp = {
@@ -20,14 +21,9 @@ static const struct snd_soc_acpi_codecs mtl_max98360a_amp = {
.codecs = {"MX98360A"}
};
-static const struct snd_soc_acpi_codecs mtl_rt1019p_amp = {
- .num_codecs = 1,
- .codecs = {"RTL1019"}
-};
-
static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
static const struct snd_soc_acpi_codecs mtl_essx_83x6 = {
@@ -40,11 +36,6 @@ static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = {
.codecs = {"INTC10B0"}
};
-static const struct snd_soc_acpi_codecs mtl_rt5650_amp = {
- .num_codecs = 1,
- .codecs = {"10EC5650"}
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
{
.comp_ids = &mtl_rt5682_rt5682s_hp,
@@ -61,13 +52,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
.sof_tplg_filename = "sof-mtl-max98360a-rt5682.tplg",
},
{
- .comp_ids = &mtl_rt5682_rt5682s_hp,
- .drv_name = "mtl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &mtl_rt1019p_amp,
- .sof_tplg_filename = "sof-mtl-rt1019-rt5682.tplg",
- },
- {
.comp_ids = &mtl_essx_83x6,
.drv_name = "mtl_es83x6_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
@@ -82,12 +66,36 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
{
- .id = "10EC5650",
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "mtl_cs42l42_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "mtl_nau8825_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
.drv_name = "mtl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &mtl_rt5650_amp,
- .sof_tplg_filename = "sof-mtl-rt5650.tplg",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &mtl_rt5682_rt5682s_hp,
+ .drv_name = "mtl_rt5682_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
},
/* place amp-only boards in the end of table */
{
@@ -338,11 +346,38 @@ static const struct snd_soc_acpi_link_adr mtl_712_only[] = {
{}
};
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
{
.adr = 0x00003001FA424301ull,
- .num_endpoints = 1,
- .endpoints = &single_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
.name_prefix = "cs42l43"
}
};
@@ -352,13 +387,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
.adr = 0x00013701FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_r_endpoint,
- .name_prefix = "AMP8"
+ .name_prefix = "AMP3"
},
{
.adr = 0x00013601FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_3_endpoint,
- .name_prefix = "AMP7"
+ .name_prefix = "AMP4"
}
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 00a21af210fa..34588db6138a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -7,6 +7,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
@@ -347,7 +348,7 @@ static const struct snd_soc_acpi_link_adr rplp_crb[] = {
static const struct snd_soc_acpi_codecs rpl_rt5682_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
static const struct snd_soc_acpi_codecs rpl_essx_83x6 = {
@@ -365,26 +366,11 @@ static const struct snd_soc_acpi_codecs rpl_max98360a_amp = {
.codecs = {"MX98360A"},
};
-static const struct snd_soc_acpi_codecs rpl_max98373_amp = {
- .num_codecs = 1,
- .codecs = {"MX98373"}
-};
-
static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = {
.num_codecs = 1,
.codecs = {"INTC10B0"}
};
-static const struct snd_soc_acpi_codecs rpl_nau8318_amp = {
- .num_codecs = 1,
- .codecs = {"NVTN2012"}
-};
-
-static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = {
- .num_codecs = 1,
- .codecs = {"RTL1019"}
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{
.comp_ids = &rpl_rt5682_hp,
@@ -395,41 +381,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
},
{
.comp_ids = &rpl_rt5682_hp,
- .drv_name = "rpl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_max98360a_amp,
- .sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "rpl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_max98373_amp,
- .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "rpl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_max98360a_amp,
- .sof_tplg_filename = "sof-rpl-max98360a-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "rpl_nau8825_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_nau8318_amp,
- .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg",
- },
- {
- .comp_ids = &rpl_rt5682_hp,
- .drv_name = "rpl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_rt1019p_amp,
- .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg",
- },
- {
- .comp_ids = &rpl_rt5682_hp,
.drv_name = "rpl_rt5682_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rpl_lt6911_hdmi,
@@ -450,11 +401,50 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "rpl_cs42l42_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "rpl_nau8825_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
+ .drv_name = "rpl_rt5682_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &rpl_rt5682_hp,
+ .drv_name = "rpl_rt5682_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ /* place amp-only boards in the end of table */
{
.id = "INTC10B0",
.drv_name = "rpl_lt6911_hdmi_ssp",
.sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg"
},
+ {
+ .id = "DLGS7219",
+ .drv_name = "rpl_da7219_def",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rpl_max98360a_amp,
+ .sof_tplg_filename = "sof-rpl-max98360a-da7219.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-ssp-common.c b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c
new file mode 100644
index 000000000000..a887f019afe2
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+
+#include <linux/device.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+
+/*
+ * Codec probe function
+ */
+#define CODEC_MAP_ENTRY(n, s, h, t) \
+ { \
+ .name = n, \
+ .tplg_suffix = s, \
+ .acpi_hid = h, \
+ .codec_type = t, \
+ }
+
+struct codec_map {
+ const char *name;
+ const char *tplg_suffix;
+ const char *acpi_hid;
+ enum snd_soc_acpi_intel_codec codec_type;
+};
+
+static const struct codec_map codecs[] = {
+ /* Cirrus Logic */
+ CODEC_MAP_ENTRY("CS42L42", "cs42l42", CS42L42_ACPI_HID, CODEC_CS42L42),
+
+ /* Dialog */
+ CODEC_MAP_ENTRY("DA7219", "da7219", DA7219_ACPI_HID, CODEC_DA7219),
+
+ /* Everest */
+ CODEC_MAP_ENTRY("ES8316", "es8336", ES8316_ACPI_HID, CODEC_ES8316),
+ CODEC_MAP_ENTRY("ES8326", "es8336", ES8326_ACPI_HID, CODEC_ES8326),
+ CODEC_MAP_ENTRY("ES8336", "es8336", ES8336_ACPI_HID, CODEC_ES8336),
+
+ /* Nuvoton */
+ CODEC_MAP_ENTRY("NAU8825", "nau8825", NAU8825_ACPI_HID, CODEC_NAU8825),
+
+ /* Realtek */
+ CODEC_MAP_ENTRY("RT5650", "rt5650", RT5650_ACPI_HID, CODEC_RT5650),
+ CODEC_MAP_ENTRY("RT5682", "rt5682", RT5682_ACPI_HID, CODEC_RT5682),
+ CODEC_MAP_ENTRY("RT5682S", "rt5682", RT5682S_ACPI_HID, CODEC_RT5682S),
+};
+
+static const struct codec_map amps[] = {
+ /* Cirrus Logic */
+ CODEC_MAP_ENTRY("CS35L41", "cs35l41", CS35L41_ACPI_HID, CODEC_CS35L41),
+
+ /* Maxim */
+ CODEC_MAP_ENTRY("MAX98357A", "max98357a", MAX_98357A_ACPI_HID, CODEC_MAX98357A),
+ CODEC_MAP_ENTRY("MAX98360A", "max98360a", MAX_98360A_ACPI_HID, CODEC_MAX98360A),
+ CODEC_MAP_ENTRY("MAX98373", "max98373", MAX_98373_ACPI_HID, CODEC_MAX98373),
+ CODEC_MAP_ENTRY("MAX98390", "max98390", MAX_98390_ACPI_HID, CODEC_MAX98390),
+
+ /* Nuvoton */
+ CODEC_MAP_ENTRY("NAU8318", "nau8318", NAU8318_ACPI_HID, CODEC_NAU8318),
+
+ /* Realtek */
+ CODEC_MAP_ENTRY("RT1011", "rt1011", RT1011_ACPI_HID, CODEC_RT1011),
+ CODEC_MAP_ENTRY("RT1015", "rt1015", RT1015_ACPI_HID, CODEC_RT1015),
+ CODEC_MAP_ENTRY("RT1015P", "rt1015", RT1015P_ACPI_HID, CODEC_RT1015P),
+ CODEC_MAP_ENTRY("RT1019P", "rt1019", RT1019P_ACPI_HID, CODEC_RT1019P),
+ CODEC_MAP_ENTRY("RT1308", "rt1308", RT1308_ACPI_HID, CODEC_RT1308),
+};
+
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_codec_type(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (!acpi_dev_present(codecs[i].acpi_hid, NULL, -1))
+ continue;
+
+ dev_dbg(dev, "codec %s found\n", codecs[i].name);
+ return codecs[i].codec_type;
+ }
+
+ return CODEC_NONE;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_codec_type, SND_SOC_ACPI_INTEL_MATCH);
+
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_amp_type(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (!acpi_dev_present(amps[i].acpi_hid, NULL, -1))
+ continue;
+
+ dev_dbg(dev, "amp %s found\n", amps[i].name);
+ return amps[i].codec_type;
+ }
+
+ return CODEC_NONE;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_amp_type, SND_SOC_ACPI_INTEL_MATCH);
+
+const char *
+snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (codecs[i].codec_type != codec_type)
+ continue;
+
+ return codecs[i].name;
+ }
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (amps[i].codec_type != codec_type)
+ continue;
+
+ return amps[i].name;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_name, SND_SOC_ACPI_INTEL_MATCH);
+
+const char *
+snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (codecs[i].codec_type != codec_type)
+ continue;
+
+ return codecs[i].tplg_suffix;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_tplg_suffix, SND_SOC_ACPI_INTEL_MATCH);
+
+const char *
+snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (amps[i].codec_type != codec_type)
+ continue;
+
+ return amps[i].tplg_suffix;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_amp_tplg_suffix, SND_SOC_ACPI_INTEL_MATCH);
+
+MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
+MODULE_LICENSE("GPL");
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 0fba0a60d9c7..161ba532d270 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -8,6 +8,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
@@ -15,11 +16,6 @@ static const struct snd_soc_acpi_codecs essx_83x6 = {
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static const struct snd_soc_acpi_codecs tgl_codecs = {
- .num_codecs = 1,
- .codecs = {"MX98357A"}
-};
-
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
.aggregated = 0,
@@ -414,11 +410,38 @@ static const struct snd_soc_acpi_link_adr tgl_712_only[] = {
{}
};
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = {
{
.adr = 0x00033001FA424301ull,
- .num_endpoints = 1,
- .endpoints = &single_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
.name_prefix = "cs42l43"
}
};
@@ -443,13 +466,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
.adr = 0x00013701FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_l_endpoint,
- .name_prefix = "AMP8"
+ .name_prefix = "AMP3"
},
{
.adr = 0x00013601FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_2_endpoint,
- .name_prefix = "AMP7"
+ .name_prefix = "AMP4"
}
};
@@ -472,19 +495,9 @@ static const struct snd_soc_acpi_link_adr tgl_cs42l43_cs35l56[] = {
{}
};
-static const struct snd_soc_acpi_codecs tgl_max98373_amp = {
- .num_codecs = 1,
- .codecs = {"MX98373"}
-};
-
-static const struct snd_soc_acpi_codecs tgl_rt1011_amp = {
- .num_codecs = 1,
- .codecs = {"10EC1011"}
-};
-
static const struct snd_soc_acpi_codecs tgl_rt5682_rt5682s_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = {
@@ -494,27 +507,6 @@ static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
{
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_codecs,
- .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg",
- },
- {
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_max98373_amp,
- .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg",
- },
- {
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_rt5682_def",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_rt1011_amp,
- .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg",
- },
- {
.comp_ids = &essx_83x6,
.drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-tgl-es8336", /* the tplg suffix is added at run time */
@@ -522,6 +514,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .comp_ids = &tgl_rt5682_rt5682s_hp,
+ .drv_name = "tgl_rt5682_def",
+ .sof_tplg_filename = "sof-tgl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ /* place amp-only boards in the end of table */
{
.id = "10EC1308",
.drv_name = "tgl_rt1308_hdmi_ssp",
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index dd2f806526c1..ef00792e1d49 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -182,6 +182,9 @@ static int kirkwood_dma_hw_params(struct snd_soc_component *component,
const struct mbus_dram_target_info *dram = mv_mbus_dram_info();
unsigned long addr = substream->runtime->dma_addr;
+ if (!dram)
+ return 0;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_PLAYBACK_WIN, addr, dram);
diff --git a/sound/soc/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c
index fa90361865c6..ec18b122cd79 100644
--- a/sound/soc/loongson/loongson_i2s_pci.c
+++ b/sound/soc/loongson/loongson_i2s_pci.c
@@ -160,7 +160,6 @@ static struct pci_driver loongson_i2s_driver = {
.id_table = loongson_i2s_ids,
.probe = loongson_i2s_pci_probe,
.driver = {
- .owner = THIS_MODULE,
.pm = pm_sleep_ptr(&loongson_i2s_pm),
},
};
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile
index 42e636c10c1e..363cc258a3d5 100644
--- a/sound/soc/mediatek/common/Makefile
+++ b/sound/soc/mediatek/common/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o
+snd-soc-mtk-common-objs += mtk-dai-adda-common.o
+
obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o
diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.c b/sound/soc/mediatek/common/mtk-dai-adda-common.c
new file mode 100644
index 000000000000..4dc1412489d6
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-dai-adda-common.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Common
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+
+#include "mtk-base-afe.h"
+#include "mtk-dai-adda-common.h"
+
+unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_adda_dl_rate_transform);
+
+unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_adda_ul_rate_transform);
diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.h b/sound/soc/mediatek/common/mtk-dai-adda-common.h
new file mode 100644
index 000000000000..208b0dd89f57
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-dai-adda-common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef _MTK_DAI_ADDA_COMMON_H_
+#define _MTK_DAI_ADDA_COMMON_H_
+
+struct mtk_base_afe;
+
+enum adda_input_mode_rate {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum adda_voice_mode_rate {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+enum adda_rxif_delay_data {
+ DELAY_DATA_MISO1 = 0,
+ DELAY_DATA_MISO0 = 1,
+ DELAY_DATA_MISO2 = 1,
+};
+
+unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate);
+unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate);
+#endif
diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c
index a58e1e3674de..000a086a8cf4 100644
--- a/sound/soc/mediatek/common/mtk-soundcard-driver.c
+++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c
@@ -22,7 +22,11 @@ static int set_card_codec_info(struct snd_soc_card *card,
codec_node = of_get_child_by_name(sub_node, "codec");
if (!codec_node) {
- dev_dbg(dev, "%s no specified codec\n", dai_link->name);
+ dev_dbg(dev, "%s no specified codec: setting dummy.\n", dai_link->name);
+
+ dai_link->codecs = &snd_soc_dummy_dlc;
+ dai_link->num_codecs = 1;
+ dai_link->dynamic = 1;
return 0;
}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
index 0ac6409c6d61..78f3ad758c12 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
@@ -10,86 +10,7 @@
#include "mt6797-afe-common.h"
#include "mt6797-interconnection.h"
#include "mt6797-reg.h"
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
+#include "../common/mtk-dai-adda-common.h"
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
@@ -246,7 +167,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
/* set input sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) << 28;
/* set output mode */
switch (rate) {
@@ -296,7 +217,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
0x1 << 0,
0x0 << 0);
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
index 5b8a274419ed..be69bcea2a78 100644
--- a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
@@ -10,6 +10,7 @@
#include "mt8183-afe-common.h"
#include "mt8183-interconnection.h"
#include "mt8183-reg.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
AUDIO_SDM_LEVEL_MUTE = 0,
@@ -18,91 +19,6 @@ enum {
/* you need to change formula of hp impedance and dc trim too */
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -369,7 +285,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) << 28;
/* set output mode */
switch (rate) {
@@ -420,7 +336,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
0x1 << 0,
0x0 << 0);
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
index ad6d4b5cf697..dbd157d1a1ea 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
@@ -11,6 +11,7 @@
#include "mt8186-afe-common.h"
#include "mt8186-afe-gpio.h"
#include "mt8186-interconnection.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
UL_IIR_SW = 0,
@@ -33,35 +34,6 @@ enum {
AUDIO_SDM_3RD,
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
#define SDM_AUTO_RESET_THRESHOLD 0x190000
struct mtk_afe_adda_priv {
@@ -83,64 +55,6 @@ static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
return afe_priv->dai_priv[dai_id];
}
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_dbg(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- }
-
- return MTK_AFE_ADDA_DL_RATE_48K;
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_dbg(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- }
-
- return MTK_AFE_ADDA_UL_RATE_48K;
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -658,7 +572,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
adda_priv->dl_rate = rate;
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) <<
DL_2_INPUT_MODE_CTL_SFT;
/* set output mode, UP_SAMPLING_RATE_X8 */
@@ -721,7 +635,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
}
} else {
unsigned int ul_src_con0 = 0;
- unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
+ unsigned int voice_mode = mtk_adda_ul_rate_transform(afe, rate);
adda_priv->ul_rate = rate;
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
index 7dc029f2b428..8a17d1935c48 100644
--- a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
@@ -14,6 +14,7 @@
#include "mt8188-afe-clk.h"
#include "mt8188-afe-common.h"
#include "mt8188-reg.h"
+#include "../common/mtk-dai-adda-common.h"
#define ADDA_HIRES_THRES 48000
@@ -24,94 +25,10 @@ enum {
SUPPLY_SEQ_ADDA_AFE_ON,
};
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
-};
-
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO0 = 1,
-};
-
struct mtk_dai_adda_priv {
bool hires_required;
};
-static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %u invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int afe_adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %u invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe)
{
struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -440,7 +357,7 @@ static int mtk_dai_da_configure(struct mtk_base_afe *afe,
/* set sampling rate */
mask |= DL_2_INPUT_MODE_CTL_MASK;
val |= FIELD_PREP(DL_2_INPUT_MODE_CTL_MASK,
- afe_adda_dl_rate_transform(afe, rate));
+ mtk_adda_dl_rate_transform(afe, rate));
/* turn off saturation */
mask |= DL_2_CH1_SATURATION_EN_CTL;
@@ -474,7 +391,7 @@ static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
mask = UL_VOICE_MODE_CTL_MASK;
val = FIELD_PREP(UL_VOICE_MODE_CTL_MASK,
- afe_adda_ul_rate_transform(afe, rate));
+ mtk_adda_ul_rate_transform(afe, rate));
regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
mask, val);
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
index bdd1e91824d9..aed22baef9fb 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -2205,44 +2205,34 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
/* reset controller to reset audio regs before regmap cache */
rstc = devm_reset_control_get_exclusive(dev, "audiosys");
- if (IS_ERR(rstc)) {
- ret = PTR_ERR(rstc);
- dev_err(dev, "could not get audiosys reset:%d\n", ret);
- return ret;
- }
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n");
ret = reset_control_reset(rstc);
- if (ret) {
- dev_err(dev, "failed to trigger audio reset:%d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to trigger audio reset\n");
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev))
- goto err_pm_disable;
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
/* regmap init */
afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
- if (IS_ERR(afe->regmap)) {
- dev_err(dev, "could not get regmap from parent\n");
- ret = PTR_ERR(afe->regmap);
- goto err_pm_disable;
- }
+ if (IS_ERR(afe->regmap))
+ return dev_err_probe(dev, PTR_ERR(afe->regmap),
+ "could not get regmap from parent");
+
ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config);
- if (ret) {
- dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "regmap_attach_dev fail\n");
/* enable clock for regcache get default value from hw */
afe_priv->pm_runtime_bypass_reg_ctl = true;
pm_runtime_get_sync(&pdev->dev);
ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config);
- if (ret) {
- dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "regmap_reinit_cache fail\n");
pm_runtime_put_sync(&pdev->dev);
afe_priv->pm_runtime_bypass_reg_ctl = false;
@@ -2254,10 +2244,8 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
afe->memif_size = MT8192_MEMIF_NUM;
afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
GFP_KERNEL);
- if (!afe->memif) {
- ret = -ENOMEM;
- goto err_pm_disable;
- }
+ if (!afe->memif)
+ return -ENOMEM;
for (i = 0; i < afe->memif_size; i++) {
afe->memif[i].data = &memif_data[i];
@@ -2271,47 +2259,35 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
afe->irqs_size = MT8192_IRQ_NUM;
afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
GFP_KERNEL);
- if (!afe->irqs) {
- ret = -ENOMEM;
- goto err_pm_disable;
- }
+ if (!afe->irqs)
+ return -ENOMEM;
for (i = 0; i < afe->irqs_size; i++)
afe->irqs[i].irq_data = &irq_data[i];
/* request irq */
irq_id = platform_get_irq(pdev, 0);
- if (irq_id < 0) {
- ret = irq_id;
- goto err_pm_disable;
- }
+ if (irq_id < 0)
+ return irq_id;
ret = devm_request_irq(dev, irq_id, mt8192_afe_irq_handler,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
- if (ret) {
- dev_err(dev, "could not request_irq for Afe_ISR_Handle\n");
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
/* init sub_dais */
INIT_LIST_HEAD(&afe->sub_dais);
for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
ret = dai_register_cbs[i](afe);
- if (ret) {
- dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
- i, ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "dai %d register fail", i);
}
/* init dai_driver and component_driver */
ret = mtk_afe_combine_sub_dai(afe);
- if (ret) {
- dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
- ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "mtk_afe_combine_sub_dai fail\n");
/* others */
afe->mtk_afe_hardware = &mt8192_afe_hardware;
@@ -2327,26 +2303,17 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
/* register platform */
ret = devm_snd_soc_register_component(&pdev->dev,
&mt8192_afe_component, NULL, 0);
- if (ret) {
- dev_warn(dev, "err_platform\n");
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't register AFE component\n");
ret = devm_snd_soc_register_component(&pdev->dev,
&mt8192_afe_pcm_component,
afe->dai_drivers,
afe->num_dai_drivers);
- if (ret) {
- dev_warn(dev, "err_dai_component\n");
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't register AFE-PCM component\n");
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void mt8192_afe_pcm_dev_remove(struct platform_device *pdev)
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
index 36d33032a37a..99de85b87643 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
@@ -13,6 +13,7 @@
#include "mt8192-afe-common.h"
#include "mt8192-afe-gpio.h"
#include "mt8192-interconnection.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
UL_IIR_SW = 0,
@@ -35,93 +36,8 @@ enum {
AUDIO_SDM_3RD,
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
#define SDM_AUTO_RESET_THRESHOLD 0x190000
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -1156,7 +1072,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
unsigned int dl_src2_con1 = 0;
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) <<
DL_2_INPUT_MODE_CTL_SFT;
/* set output mode, UP_SAMPLING_RATE_X8 */
@@ -1246,7 +1162,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
unsigned int voice_mode = 0;
unsigned int ul_src_con0 = 0; /* default value */
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
index 0dd35255066b..8da1587128cc 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
@@ -12,6 +12,7 @@
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h"
#include "mt8195-reg.h"
+#include "../common/mtk-dai-adda-common.h"
#define ADDA_DL_GAIN_LOOPBACK 0x1800
#define ADDA_HIRES_THRES 48000
@@ -26,35 +27,6 @@ enum {
};
enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
-};
-
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO0 = 1,
- DELAY_DATA_MISO2 = 1,
-};
-
-enum {
MTK_AFE_ADDA,
MTK_AFE_ADDA6,
};
@@ -63,62 +35,6 @@ struct mtk_dai_adda_priv {
bool hires_required;
};
-static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int afe_adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
static int mt8195_adda_mtkaif_init(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -644,7 +560,7 @@ static int mtk_dai_da_configure(struct mtk_base_afe *afe,
/* set sampling rate */
mask |= DL_2_INPUT_MODE_CTL_MASK;
- val |= DL_2_INPUT_MODE_CTL(afe_adda_dl_rate_transform(afe, rate));
+ val |= DL_2_INPUT_MODE_CTL(mtk_adda_dl_rate_transform(afe, rate));
/* turn off saturation */
mask |= DL_2_CH1_SATURATION_EN_CTL;
@@ -681,7 +597,7 @@ static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
unsigned int mask = 0;
mask |= UL_VOICE_MODE_CTL_MASK;
- val |= UL_VOICE_MODE_CTL(afe_adda_ul_rate_transform(afe, rate));
+ val |= UL_VOICE_MODE_CTL(mtk_adda_ul_rate_transform(afe, rate));
switch (id) {
case MT8195_AFE_IO_UL_SRC1:
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index 329e6ab1b222..8d9a1e345a22 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -119,7 +119,7 @@ static void rsnd_cmd_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
}
#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
@@ -157,10 +157,6 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
struct rsnd_cmd *cmd;
int i, nr;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
/* same number as DVC */
nr = priv->dvc_nr;
if (!nr)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 0b1aa23c1189..6bc7027ed4db 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1512,7 +1512,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
continue;
for_each_endpoint_of_node(ports, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+ if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
@@ -1531,7 +1531,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
for_each_child_of_node(node, dai_np) {
__rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+ if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index e39eb2ac7e95..a26ec7b780cd 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -284,7 +284,7 @@ static void rsnd_ctu_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
}
#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
@@ -323,10 +323,6 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
char name[CTU_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_ctu_of_node(priv);
if (!node)
return 0; /* not used is not error */
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 1c494e521463..7b499eee5080 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -585,8 +585,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct device *dev = rsnd_priv_to_dev(priv);
- phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
- phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
+ phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
+ phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
!!(rsnd_io_to_mod_ssiu(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
@@ -666,7 +666,7 @@ rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
int is_play, int is_from)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
- phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_GEN4_SDMC);
+ phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC);
int id = rsnd_mod_id(mod);
int busif = rsnd_mod_id_sub(mod);
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 16befcbc312c..da91dd301aab 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -294,7 +294,7 @@ static void rsnd_dvc_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
}
#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
@@ -331,10 +331,6 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
char name[RSND_DVC_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_dvc_of_node(priv);
if (!node)
return 0; /* not used is not error */
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 86bdecc24956..d1f20cde66be 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -178,8 +178,6 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
- if (!res)
return -ENODEV;
base = devm_ioremap_resource(dev, res);
@@ -216,69 +214,219 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
}
/*
+ * (A) : Gen4 is 0xa0c, but it is not used.
+ * see
+ * rsnd_ssiu_init()
+ */
+static const struct rsnd_regmap_field_conf conf_common_ssiu[] = {
+ RSND_GEN_S_REG(SSI_MODE0, 0x800),
+ RSND_GEN_S_REG(SSI_MODE1, 0x804),
+ RSND_GEN_S_REG(SSI_MODE2, 0x808), // (A)
+ RSND_GEN_S_REG(SSI_CONTROL, 0x810),
+ RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
+ RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
+ RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
+ RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
+ RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
+ 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),
+ RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
+ RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
+ RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
+ RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
+ RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c),
+ RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484),
+ RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488),
+ RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0),
+ RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4),
+ RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8),
+ RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0),
+ RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4),
+ RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8),
+ RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0),
+ RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4),
+ RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8),
+ RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80),
+ RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84),
+ RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88),
+ RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0),
+ RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4),
+ RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8),
+ RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0),
+ RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4),
+ RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8),
+ RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0),
+ RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4),
+ RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_scu[] = {
+ RSND_GEN_M_REG(SRC_I_BUSIF_MODE, 0x0, 0x20),
+ RSND_GEN_M_REG(SRC_O_BUSIF_MODE, 0x4, 0x20),
+ RSND_GEN_M_REG(SRC_BUSIF_DALIGN, 0x8, 0x20),
+ RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
+ RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
+ RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
+ RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20),
+ RSND_GEN_M_REG(CMD_BUSIF_DALIGN, 0x188, 0x20),
+ RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
+ RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
+ RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
+ RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
+ RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
+ RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
+ RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
+ RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
+ RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
+ RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
+ RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
+ RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
+ RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
+ RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
+ RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
+ RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
+ RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
+ RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
+ RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
+ RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
+ RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
+ RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
+ RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
+ RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
+ RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
+ RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
+ RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
+ RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
+ RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
+ RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
+ RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
+ RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
+ RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
+ RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
+ RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
+ RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
+ RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
+ RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
+ RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
+ RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
+ RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
+ RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
+ RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
+ RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
+ RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
+ RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
+ RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
+ RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
+ RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
+ RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
+ RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
+ RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
+ RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
+ RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
+ RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
+ RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
+ RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
+ RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
+ RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
+ RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
+ RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
+ RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
+ RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
+ RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
+ RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
+ RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
+ RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
+ RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
+ RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
+ RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
+ RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
+ RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
+ RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
+ RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_adg[] = {
+ RSND_GEN_S_REG(BRRA, 0x00),
+ RSND_GEN_S_REG(BRRB, 0x04),
+ RSND_GEN_S_REG(BRGCKR, 0x08),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
+ RSND_GEN_S_REG(DIV_EN, 0x30),
+ RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34),
+ RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38),
+ RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c),
+ RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40),
+ RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
+ RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_ssi[] = {
+ RSND_GEN_M_REG(SSICR, 0x00, 0x40),
+ RSND_GEN_M_REG(SSISR, 0x04, 0x40),
+ RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
+ RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
+ RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
+};
+
+/*
* Gen4
*/
static int rsnd_gen4_probe(struct rsnd_priv *priv)
{
- static const struct rsnd_regmap_field_conf conf_ssiu[] = {
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
- RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
- RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
- RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
- RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
-
- RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0),
- RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4),
- RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8),
- RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20),
- RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24),
- RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28),
- RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40),
- RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44),
- RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48),
- RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60),
- RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64),
- RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68),
- RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500),
- RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504),
- RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508),
- RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520),
- RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524),
- RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528),
- RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540),
- RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544),
- RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548),
- RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560),
- RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564),
- RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568),
- RSND_GEN_S_REG(SSI_CTRL, 0x010),
- RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018),
- RSND_GEN_S_REG(SSI_MODE, 0x00c),
- RSND_GEN_S_REG(SSI_MODE2, 0xa0c),
- };
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_S_REG(SSICR, 0x00),
- RSND_GEN_S_REG(SSISR, 0x04),
- RSND_GEN_S_REG(SSITDR, 0x08),
- RSND_GEN_S_REG(SSIRDR, 0x0c),
- RSND_GEN_S_REG(SSIWSR, 0x20),
- };
- static const struct rsnd_regmap_field_conf conf_sdmc[] = {
- RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000),
- };
- int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg);
- int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu);
- int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi);
- int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc);
+ struct rsnd_regmap_field_conf conf_null[] = { };
+
+ /*
+ * ssiu: SSIU0
+ * ssi : SSI0
+ */
+ int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+ int ret_ssi = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+ int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null);
return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
}
@@ -288,215 +436,17 @@ static int rsnd_gen4_probe(struct rsnd_priv *priv)
*/
static int rsnd_gen2_probe(struct rsnd_priv *priv)
{
- static const struct rsnd_regmap_field_conf conf_ssiu[] = {
- RSND_GEN_S_REG(SSI_MODE0, 0x800),
- RSND_GEN_S_REG(SSI_MODE1, 0x804),
- RSND_GEN_S_REG(SSI_MODE2, 0x808),
- RSND_GEN_S_REG(SSI_CONTROL, 0x810),
- RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
- RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
- RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
- RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
- RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
- 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),
-
- /* FIXME: it needs SSI_MODE2/3 in the future */
- RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
- RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
- RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
- RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
- RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c),
- RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484),
- RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488),
- RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0),
- RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4),
- RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8),
- RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0),
- RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4),
- RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8),
- RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0),
- RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4),
- RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8),
- RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80),
- RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84),
- RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88),
- RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0),
- RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4),
- RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8),
- RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0),
- RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4),
- RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8),
- RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0),
- RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4),
- RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8),
- };
-
- static const struct rsnd_regmap_field_conf conf_scu[] = {
- RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20),
- RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20),
- RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20),
- RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
- RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
- RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
- RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20),
- RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20),
- RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
- RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
- RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
- RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
- RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
- RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
- RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
- RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
- RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
- RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
- RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
- RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
- RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
- RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
- RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
- RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
- RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
- RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
- RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
- RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
- RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
- RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
- RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
- RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
- RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
- RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
- RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
- RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
- RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
- RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
- RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
- RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
- RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
- RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
- RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
- RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
- RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
- RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
- RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
- RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
- RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
- RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
- RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
- RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
- RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
- RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
- RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
- RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
- RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
- RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
- RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
- RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
- RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
- RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
- RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
- RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
- RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
- RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
- RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
- RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
- RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
- RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
- RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
- RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
- RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
- RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
- RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
- RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
- RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
- RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
- RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
- RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
- RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
- RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
- RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
- RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
- RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
- RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
- };
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
- RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
- RSND_GEN_S_REG(DIV_EN, 0x30),
- RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34),
- RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38),
- RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c),
- RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40),
- RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44),
- RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48),
- RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c),
- RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50),
- RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54),
- RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
- RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_M_REG(SSICR, 0x00, 0x40),
- RSND_GEN_M_REG(SSISR, 0x04, 0x40),
- RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
- RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
- RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
- };
- int ret_ssiu;
- int ret_scu;
- int ret_adg;
- int ret_ssi;
-
- ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu);
- ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu);
- ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg);
- ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi);
- if (ret_ssiu < 0 ||
- ret_scu < 0 ||
- ret_adg < 0 ||
- ret_ssi < 0)
- return ret_ssiu | ret_scu | ret_adg | ret_ssi;
-
- return 0;
+ /*
+ * ssi : SSI0 - SSI9
+ * ssiu: SSIU0 - SSIU9
+ * scu : SRC0 - SRC9 etc
+ */
+ int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+ int ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU, "scu", conf_common_scu);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+
+ return ret_ssi | ret_ssiu | ret_scu | ret_adg;
}
/*
@@ -505,30 +455,13 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
static int rsnd_gen1_probe(struct rsnd_priv *priv)
{
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_M_REG(SSICR, 0x00, 0x40),
- RSND_GEN_M_REG(SSISR, 0x04, 0x40),
- RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
- RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
- RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
- };
- int ret_adg;
- int ret_ssi;
-
- ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
- ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
- if (ret_adg < 0 ||
- ret_ssi < 0)
- return ret_adg | ret_ssi;
+ /*
+ * ssi : SSI0 - SSI8
+ */
+ int ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
- return 0;
+ return ret_adg | ret_ssi;
}
/*
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 1de0e085804c..024d91cc8748 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -259,7 +259,7 @@ static void rsnd_mix_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
}
#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
@@ -295,10 +295,6 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
char name[MIX_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_mix_of_node(priv);
if (!node)
return 0; /* not used is not error */
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index da716b1f52e4..ff294aa2d640 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -20,20 +20,11 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#define RSND_GEN1_SRU 0
-#define RSND_GEN1_ADG 1
-#define RSND_GEN1_SSI 2
-
-#define RSND_GEN2_SCU 0
-#define RSND_GEN2_ADG 1
-#define RSND_GEN2_SSIU 2
-#define RSND_GEN2_SSI 3
-
-#define RSND_GEN4_ADG 0
-#define RSND_GEN4_SSIU 1
-#define RSND_GEN4_SSI 2
-#define RSND_GEN4_SDMC 3
-
+#define RSND_BASE_ADG 0
+#define RSND_BASE_SSI 1
+#define RSND_BASE_SSIU 2
+#define RSND_BASE_SCU 3 // for Gen2/Gen3
+#define RSND_BASE_SDMC 3 // for Gen4 reuse
#define RSND_BASE_MAX 4
/*
@@ -200,7 +191,6 @@ enum rsnd_reg {
SSI_SYS_INT_ENABLE5,
SSI_SYS_INT_ENABLE6,
SSI_SYS_INT_ENABLE7,
- SSI_BUSIF,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@@ -713,7 +703,7 @@ struct rsnd_priv {
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
-#define rsnd_is_e3(priv) (((priv)->flags & \
+#define rsnd_is_gen3_e3(priv) (((priv)->flags & \
(RSND_GEN_MASK | RSND_SOC_MASK)) == \
(RSND_GEN3 | RSND_SOC_E))
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 3241a1bdc9ea..e7f86db0d94c 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -310,7 +310,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
/*
* E3 need to overwrite
*/
- if (rsnd_is_e3(priv))
+ if (rsnd_is_gen3_e3(priv))
switch (rsnd_mod_id(mod)) {
case 0:
case 4:
@@ -606,13 +606,13 @@ static void rsnd_src_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
rsnd_mod_id(mod) * 0x20, 0x20);
seq_puts(m, "\n");
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x1c0, 0x20);
seq_puts(m, "\n");
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x200 + rsnd_mod_id(mod) * 0x40, 0x40);
}
#define DEBUG_INFO .debug_info = rsnd_src_debug_info
@@ -652,10 +652,6 @@ int rsnd_src_probe(struct rsnd_priv *priv)
char name[RSND_SRC_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_src_of_node(priv);
if (!node)
return 0; /* not used is not error */
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 0a46aa1975fa..8d2a86383ae0 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -1049,7 +1049,7 @@ static void rsnd_ssi_debug_info(struct seq_file *m,
seq_printf(m, "chan: %d\n", ssi->chan);
seq_printf(m, "user: %d\n", ssi->usrcnt);
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI,
rsnd_mod_id(mod) * 0x40, 0x40);
}
#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 17bd8cc86dd0..665e8b2db579 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -413,7 +413,7 @@ static void rsnd_ssiu_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
rsnd_mod_id(mod) * 0x80, 0x80);
}
#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
diff --git a/sound/soc/soc-card-test.c b/sound/soc/soc-card-test.c
new file mode 100644
index 000000000000..075c52fe82e5
--- /dev/null
+++ b/sound/soc/soc-card-test.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/device.h>
+#include <kunit/test.h>
+#include <linux/module.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-card.h>
+
+struct soc_card_test_priv {
+ struct device *card_dev;
+ struct snd_soc_card *card;
+};
+
+static const struct snd_kcontrol_new test_card_controls[] = {
+ SOC_SINGLE("Fee", SND_SOC_NOPM, 0, 1, 0),
+ SOC_SINGLE("Fi", SND_SOC_NOPM, 1, 1, 0),
+ SOC_SINGLE("Fo", SND_SOC_NOPM, 2, 1, 0),
+ SOC_SINGLE("Fum", SND_SOC_NOPM, 3, 1, 0),
+ SOC_SINGLE("Left Fee", SND_SOC_NOPM, 4, 1, 0),
+ SOC_SINGLE("Right Fee", SND_SOC_NOPM, 5, 1, 0),
+ SOC_SINGLE("Left Fi", SND_SOC_NOPM, 6, 1, 0),
+ SOC_SINGLE("Right Fi", SND_SOC_NOPM, 7, 1, 0),
+ SOC_SINGLE("Left Fo", SND_SOC_NOPM, 8, 1, 0),
+ SOC_SINGLE("Right Fo", SND_SOC_NOPM, 9, 1, 0),
+ SOC_SINGLE("Left Fum", SND_SOC_NOPM, 10, 1, 0),
+ SOC_SINGLE("Right Fum", SND_SOC_NOPM, 11, 1, 0),
+};
+
+static void test_snd_soc_card_get_kcontrol(struct kunit *test)
+{
+ struct soc_card_test_priv *priv = test->priv;
+ struct snd_soc_card *card = priv->card;
+ struct snd_kcontrol *kc;
+ struct soc_mixer_control *mc;
+ int i, ret;
+
+ ret = snd_soc_add_card_controls(card, test_card_controls, ARRAY_SIZE(test_card_controls));
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /* Look up every control */
+ for (i = 0; i < ARRAY_SIZE(test_card_controls); ++i) {
+ kc = snd_soc_card_get_kcontrol(card, test_card_controls[i].name);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kc, "Failed to find '%s'\n",
+ test_card_controls[i].name);
+ if (!kc)
+ continue;
+
+ /* Test that it is the correct control */
+ mc = (struct soc_mixer_control *)kc->private_value;
+ KUNIT_EXPECT_EQ_MSG(test, mc->shift, i, "For '%s'\n", test_card_controls[i].name);
+ }
+
+ /* Test some names that should not be found */
+ kc = snd_soc_card_get_kcontrol(card, "None");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, "Left None");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, "Left");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, NULL);
+ KUNIT_EXPECT_NULL(test, kc);
+}
+
+static void test_snd_soc_card_get_kcontrol_locked(struct kunit *test)
+{
+ struct soc_card_test_priv *priv = test->priv;
+ struct snd_soc_card *card = priv->card;
+ struct snd_kcontrol *kc, *kcw;
+ struct soc_mixer_control *mc;
+ int i, ret;
+
+ ret = snd_soc_add_card_controls(card, test_card_controls, ARRAY_SIZE(test_card_controls));
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /* Look up every control */
+ for (i = 0; i < ARRAY_SIZE(test_card_controls); ++i) {
+ down_read(&card->snd_card->controls_rwsem);
+ kc = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name);
+ up_read(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kc, "Failed to find '%s'\n",
+ test_card_controls[i].name);
+ if (!kc)
+ continue;
+
+ /* Test that it is the correct control */
+ mc = (struct soc_mixer_control *)kc->private_value;
+ KUNIT_EXPECT_EQ_MSG(test, mc->shift, i, "For '%s'\n", test_card_controls[i].name);
+
+ down_write(&card->snd_card->controls_rwsem);
+ kcw = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name);
+ up_write(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kcw, "Failed to find '%s'\n",
+ test_card_controls[i].name);
+
+ KUNIT_EXPECT_PTR_EQ(test, kc, kcw);
+ }
+
+ /* Test some names that should not be found */
+ down_read(&card->snd_card->controls_rwsem);
+ kc = snd_soc_card_get_kcontrol_locked(card, "None");
+ up_read(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NULL(test, kc);
+
+ down_read(&card->snd_card->controls_rwsem);
+ kc = snd_soc_card_get_kcontrol_locked(card, "Left None");
+ up_read(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NULL(test, kc);
+
+ down_read(&card->snd_card->controls_rwsem);
+ kc = snd_soc_card_get_kcontrol_locked(card, "Left");
+ up_read(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NULL(test, kc);
+
+ down_read(&card->snd_card->controls_rwsem);
+ kc = snd_soc_card_get_kcontrol_locked(card, NULL);
+ up_read(&card->snd_card->controls_rwsem);
+ KUNIT_EXPECT_NULL(test, kc);
+}
+
+static int soc_card_test_case_init(struct kunit *test)
+{
+ struct soc_card_test_priv *priv;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ test->priv = priv;
+
+ priv->card_dev = kunit_device_register(test, "sound-soc-card-test");
+ priv->card_dev = get_device(priv->card_dev);
+ if (!priv->card_dev)
+ return -ENODEV;
+
+ priv->card = kunit_kzalloc(test, sizeof(*priv->card), GFP_KERNEL);
+ if (!priv->card)
+ return -ENOMEM;
+
+ priv->card->name = "soc-card-test";
+ priv->card->dev = priv->card_dev;
+ priv->card->owner = THIS_MODULE;
+
+ ret = snd_soc_register_card(priv->card);
+ if (!ret)
+ return ret;
+
+ return 0;
+}
+
+static void soc_card_test_case_exit(struct kunit *test)
+{
+ struct soc_card_test_priv *priv = test->priv;
+
+ if (priv->card)
+ snd_soc_unregister_card(priv->card);
+
+ if (priv->card_dev)
+ put_device(priv->card_dev);
+}
+
+static struct kunit_case soc_card_test_cases[] = {
+ KUNIT_CASE(test_snd_soc_card_get_kcontrol),
+ KUNIT_CASE(test_snd_soc_card_get_kcontrol_locked),
+ {}
+};
+
+static struct kunit_suite soc_card_test_suite = {
+ .name = "soc-card",
+ .test_cases = soc_card_test_cases,
+ .init = soc_card_test_case_init,
+ .exit = soc_card_test_case_exit,
+};
+
+kunit_test_suites(&soc_card_test_suite);
+
+MODULE_DESCRIPTION("ASoC soc-card KUnit test");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c
index 8a2f163da6bc..0a3104d4ad23 100644
--- a/sound/soc/soc-card.c
+++ b/sound/soc/soc-card.c
@@ -32,33 +32,20 @@ static inline int _soc_card_ret(struct snd_soc_card *card,
struct snd_kcontrol *snd_soc_card_get_kcontrol_locked(struct snd_soc_card *soc_card,
const char *name)
{
- struct snd_card *card = soc_card->snd_card;
- struct snd_kcontrol *kctl;
-
- /* must be held read or write */
- lockdep_assert_held(&card->controls_rwsem);
-
if (unlikely(!name))
return NULL;
- list_for_each_entry(kctl, &card->controls, list)
- if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
- return kctl;
- return NULL;
+ return snd_ctl_find_id_mixer_locked(soc_card->snd_card, name);
}
EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol_locked);
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
const char *name)
{
- struct snd_card *card = soc_card->snd_card;
- struct snd_kcontrol *kctl;
-
- down_read(&card->controls_rwsem);
- kctl = snd_soc_card_get_kcontrol_locked(soc_card, name);
- up_read(&card->controls_rwsem);
+ if (unlikely(!name))
+ return NULL;
- return kctl;
+ return snd_ctl_find_id_mixer(soc_card->snd_card, name);
}
EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2ec13d1634b6..3ab6626ad680 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2796,10 +2796,12 @@ int snd_soc_component_initialize(struct snd_soc_component *component,
INIT_LIST_HEAD(&component->list);
mutex_init(&component->io_mutex);
- component->name = fmt_single_name(dev, &component->id);
if (!component->name) {
- dev_err(dev, "ASoC: Failed to allocate name\n");
- return -ENOMEM;
+ component->name = fmt_single_name(dev, &component->id);
+ if (!component->name) {
+ dev_err(dev, "ASoC: Failed to allocate name\n");
+ return -ENOMEM;
+ }
}
component->dev = dev;
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 6f8773a8fc05..fefe394dce72 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -45,7 +45,7 @@ static inline int _soc_dai_ret(struct snd_soc_dai *dai,
* @dai: DAI
* @clk_id: DAI specific clock ID
* @freq: new clock frequency in Hz
- * @dir: new clock direction - input/output.
+ * @dir: new clock direction (SND_SOC_CLOCK_IN or SND_SOC_CLOCK_OUT)
*
* Configures the DAI master (MCLK) or system (SYSCLK) clocking.
*/
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 092ca09f3631..83db1a83d8ba 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -441,6 +441,9 @@ int snd_dmaengine_pcm_register(struct device *dev,
pcm->config = config;
pcm->flags = flags;
+ if (config->name)
+ pcm->component.name = config->name;
+
ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
if (ret)
goto err_free_dma;
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index b2cc13b9c77b..63971396b708 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -8,7 +8,6 @@
#include <sound/jack.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
@@ -345,21 +344,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
goto undo;
}
} else {
- /* legacy GPIO number */
- if (!gpio_is_valid(gpios[i].gpio)) {
- dev_err(jack->card->dev,
- "ASoC: Invalid gpio %d\n",
- gpios[i].gpio);
- ret = -EINVAL;
- goto undo;
- }
-
- ret = gpio_request_one(gpios[i].gpio, GPIOF_IN,
- gpios[i].name);
- if (ret)
- goto undo;
-
- gpios[i].desc = gpio_to_desc(gpios[i].gpio);
+ dev_err(jack->card->dev, "ASoC: Invalid gpio at index %d\n", i);
+ ret = -EINVAL;
+ goto undo;
}
got_gpio:
INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
@@ -373,7 +360,7 @@ got_gpio:
gpios[i].name,
&gpios[i]);
if (ret < 0)
- goto err;
+ goto undo;
if (gpios[i].wake) {
ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
@@ -401,8 +388,6 @@ got_gpio:
devres_add(jack->card->dev, tbl);
return 0;
-err:
- gpio_free(gpios[i].gpio);
undo:
jack_free_gpios(jack, i, gpios);
devres_free(tbl);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index ba4890991f0d..fad9432a10f1 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1083,8 +1083,15 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
break;
}
- /* add route, but keep going if some fail */
- snd_soc_dapm_add_routes(dapm, route, 1);
+ ret = snd_soc_dapm_add_routes(dapm, route, 1);
+ if (ret) {
+ if (!dapm->card->disable_route_checks) {
+ dev_err(tplg->dev, "ASoC: dapm_add_routes failed: %d\n", ret);
+ break;
+ }
+ dev_info(tplg->dev,
+ "ASoC: disable_route_checks set, ignoring dapm_add_routes errors\n");
+ }
}
return ret;
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index aad904839b81..2d5e58846499 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -289,6 +289,8 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
(void *)sdev->basefw.fw->data,
sdev->basefw.fw->size);
+ if (ret < 0)
+ return ret;
fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
plat_data->fw_filename_prefix,
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index b073720b4cf4..457144203999 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -146,17 +146,9 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *dai;
struct hdac_ext_stream *hext_stream;
- /* only allocate a stream_tag for the first DAI in the dailink */
- dai = snd_soc_rtd_to_cpu(rtd, 0);
- if (dai == cpu_dai)
- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
- else
- hext_stream = snd_soc_dai_get_dma_data(dai, substream);
-
+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
if (!hext_stream)
return NULL;
@@ -169,14 +161,9 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *dai;
- /* only release a stream_tag for the first DAI in the dailink */
- dai = snd_soc_rtd_to_cpu(rtd, 0);
- if (dai == cpu_dai)
- snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
+ snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
}
static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
@@ -446,28 +433,6 @@ out:
return ret;
}
-static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
- struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
- struct snd_sof_widget *swidget = w->dobj.private;
- struct snd_sof_dai *dai = swidget->private;
- struct sof_ipc4_copier *ipc4_copier = dai->private;
- struct sof_ipc4_alh_configuration_blob *blob;
-
- blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
-
- /*
- * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
- * the multi-gateway firmware configuration. The DMA hardware can take care of
- * multiple links without needing any firmware assistance
- */
- blob->alh_cfg.device_count = 1;
-
- return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
-}
-
static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
@@ -509,7 +474,7 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
};
static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
- .get_hext_stream = sdw_hda_ipc4_get_hext_stream,
+ .get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index c1682bcdb5a6..3f2fd84907d2 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -29,14 +29,6 @@ static bool hda_use_tplg_nhlt;
module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
-static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
-{
- struct snd_sof_widget *swidget = w->dobj.private;
- struct snd_soc_component *component = swidget->scomp;
-
- return snd_soc_component_get_drvdata(component);
-}
-
int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
struct snd_sof_dai_config_data *data)
{
@@ -221,15 +213,15 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
}
-static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int __maybe_unused hda_dai_hw_params_data(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai,
+ struct snd_sof_dai_config_data *data,
+ unsigned int flags)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
struct hdac_ext_stream *hext_stream;
- struct snd_sof_dai_config_data data = { 0 };
- unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
struct snd_sof_dev *sdev = widget_to_sdev(w);
int ret;
@@ -249,9 +241,19 @@ static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
hext_stream = ops->get_hext_stream(sdev, dai, substream);
flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
- data.dai_data = hdac_stream(hext_stream)->stream_tag - 1;
+ data->dai_data = hdac_stream(hext_stream)->stream_tag - 1;
- return hda_dai_config(w, flags, &data);
+ return hda_dai_config(w, flags, data);
+}
+
+static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
+
+ return hda_dai_hw_params_data(substream, params, dai, &data, flags);
}
/*
@@ -341,11 +343,14 @@ static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
return ipc4_copier;
}
-static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *cpu_dai)
+static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ struct snd_sof_dai_config_data *data,
+ unsigned int flags)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_ipc4_dma_config_tlv *dma_config_tlv;
const struct hda_dai_widget_dma_ops *ops;
struct sof_ipc4_dma_config *dma_config;
@@ -353,6 +358,8 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
struct snd_sof_dev *sdev;
+ struct snd_soc_dai *dai;
+ int cpu_dai_id;
int stream_id;
int ret;
@@ -363,9 +370,9 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
}
/* use HDaudio stream handling */
- ret = hda_dai_hw_params(substream, params, cpu_dai);
+ ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
if (ret < 0) {
- dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
+ dev_err(cpu_dai->dev, "%s: hda_dai_hw_params_data failed: %d\n", __func__, ret);
return ret;
}
@@ -392,7 +399,12 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
/* configure TLV */
ipc4_copier = widget_to_copier(w);
- dma_config_tlv = &ipc4_copier->dma_config_tlv;
+ for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
+ if (dai == cpu_dai)
+ break;
+ }
+
+ dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
/* dma_config_priv_size is zero */
dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
@@ -403,13 +415,27 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
dma_config->pre_allocated_by_host = 1;
dma_config->dma_channel_id = stream_id - 1;
dma_config->stream_id = stream_id;
- dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
+ /*
+ * Currently we use a DMA for each device in ALH blob. The device will
+ * be copied in sof_ipc4_prepare_copier_module.
+ */
+ dma_config->dma_stream_channel_map.device_count = 1;
dma_config->dma_priv_config_size = 0;
skip_tlv:
return 0;
}
+static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
+
+ return non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
+}
+
static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
@@ -436,15 +462,29 @@ static const struct snd_soc_dai_ops dmic_dai_ops = {
int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai,
- int link_id)
+ int link_id,
+ int intel_alh_id)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_ipc4_dma_config_tlv *dma_config_tlv;
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
const struct hda_dai_widget_dma_ops *ops;
+ struct sof_ipc4_dma_config *dma_config;
+ struct sof_ipc4_copier *ipc4_copier;
struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dai *dai;
struct snd_sof_dev *sdev;
+ bool cpu_dai_found = false;
+ int cpu_dai_id;
+ int ch_mask;
int ret;
+ int i;
- ret = non_hda_dai_hw_params(substream, params, cpu_dai);
+ data.dai_index = (link_id << 8) | cpu_dai->id;
+ data.dai_node_id = intel_alh_id;
+ ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
return ret;
@@ -457,9 +497,25 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream)
return -ENODEV;
- /* in the case of SoundWire we need to program the PCMSyCM registers */
+ /*
+ * in the case of SoundWire we need to program the PCMSyCM registers. In case
+ * of aggregated devices, we need to define the channel mask for each sublink
+ * by reconstructing the split done in soc-pcm.c
+ */
+ for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
+ if (dai == cpu_dai) {
+ cpu_dai_found = true;
+ break;
+ }
+ }
+
+ if (!cpu_dai_found)
+ return -ENODEV;
+
+ ch_mask = GENMASK(params_channels(params) - 1, 0);
+
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
- GENMASK(params_channels(params) - 1, 0),
+ ch_mask,
hdac_stream(hext_stream)->stream_tag,
substream->stream);
if (ret < 0) {
@@ -468,6 +524,22 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ ipc4_copier = widget_to_copier(w);
+ dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
+ dma_config = &dma_config_tlv->dma_config;
+ dma_config->dma_stream_channel_map.mapping[0].device = data.dai_index;
+ dma_config->dma_stream_channel_map.mapping[0].channel_mask = ch_mask;
+
+ /*
+ * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier
+ * will be handled in sof_ipc4_prepare_copier_module.
+ */
+ for_each_rtd_cpu_dais(rtd, i, dai) {
+ w = snd_soc_dai_get_widget(dai, substream->stream);
+ ipc4_copier = widget_to_copier(w);
+ memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv,
+ sizeof(*dma_config_tlv));
+ }
return 0;
}
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 7fe72b065451..d38dc43c2f1c 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -24,12 +24,14 @@
#include <linux/soundwire/sdw_intel.h>
#include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
#include <sound/sof.h>
#include <sound/sof/xtensa.h>
#include <sound/hda-mlink.h>
#include "../sof-audio.h"
#include "../sof-pci-dev.h"
#include "../ops.h"
+#include "../ipc4-topology.h"
#include "hda.h"
#include "telemetry.h"
@@ -144,12 +146,37 @@ static int sdw_params_stream(struct device *dev,
data.dai_index = (params_data->link_id << 8) | d->id;
data.dai_data = params_data->alh_stream_id;
+ data.dai_node_id = data.dai_data;
return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_PARAMS, &data);
}
+static int sdw_params_free(struct device *dev, struct sdw_intel_stream_free_data *free_data)
+{
+ struct snd_soc_dai *d = free_data->dai;
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, free_data->substream->stream);
+ struct snd_sof_dev *sdev = widget_to_sdev(w);
+
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier_data *copier_data;
+ struct sof_ipc4_copier *ipc4_copier;
+
+ ipc4_copier = dai->private;
+ ipc4_copier->dai_index = 0;
+ copier_data = &ipc4_copier->data;
+
+ /* clear the node ID */
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ }
+
+ return 0;
+}
+
struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
+ .free_stream = sdw_params_free,
};
static int sdw_ace2x_params_stream(struct device *dev,
@@ -158,7 +185,8 @@ static int sdw_ace2x_params_stream(struct device *dev,
return sdw_hda_dai_hw_params(params_data->substream,
params_data->hw_params,
params_data->dai,
- params_data->link_id);
+ params_data->link_id,
+ params_data->alh_stream_id);
}
static int sdw_ace2x_free_stream(struct device *dev,
@@ -1676,13 +1704,36 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach,
mach_params->dai_drivers = desc->ops->drv;
}
+static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach)
+{
+ u32 dmic_ssp_quirk;
+ u32 codec_amp_name_quirk;
+
+ /*
+ * In current implementation dmic and ssp quirks are designed for es8336
+ * machine driver and could not be mixed with codec name and amp name
+ * quirks.
+ */
+ dmic_ssp_quirk = mach->tplg_quirk_mask &
+ (SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER | SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER);
+ codec_amp_name_quirk = mach->tplg_quirk_mask &
+ (SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME);
+
+ if (dmic_ssp_quirk && codec_amp_name_quirk)
+ return -EINVAL;
+
+ return 0;
+}
+
struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
struct snd_sof_pdata *sof_pdata = sdev->pdata;
const struct sof_dev_desc *desc = sof_pdata->desc;
struct snd_soc_acpi_mach *mach = NULL;
+ enum snd_soc_acpi_intel_codec codec_type;
const char *tplg_filename;
+ const char *tplg_suffix;
/* Try I2S or DMIC if it is supported */
if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC)))
@@ -1701,6 +1752,17 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
tplg_fixup = true;
}
+ /*
+ * Checking quirk mask integrity; some quirk flags could not be
+ * set concurrently.
+ */
+ if (tplg_fixup &&
+ check_tplg_quirk_mask(mach)) {
+ dev_err(sdev->dev, "Invalid tplg quirk mask 0x%x\n",
+ mach->tplg_quirk_mask);
+ return NULL;
+ }
+
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
@@ -1775,6 +1837,52 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
}
+ codec_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev);
+
+ if (tplg_fixup &&
+ mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME &&
+ codec_type != CODEC_NONE) {
+ tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(codec_type);
+ if (!tplg_suffix) {
+ dev_err(sdev->dev, "no tplg suffix found, amp %d\n",
+ codec_type);
+ return NULL;
+ }
+
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-%s",
+ sof_pdata->tplg_filename,
+ tplg_suffix);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
+ add_extension = true;
+ }
+
+ codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev);
+
+ if (tplg_fixup &&
+ mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME &&
+ codec_type != CODEC_NONE) {
+ tplg_suffix = snd_soc_acpi_intel_get_codec_tplg_suffix(codec_type);
+ if (!tplg_suffix) {
+ dev_err(sdev->dev, "no tplg suffix found, codec %d\n",
+ codec_type);
+ return NULL;
+ }
+
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-%s",
+ sof_pdata->tplg_filename,
+ tplg_suffix);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
+ add_extension = true;
+ }
+
if (tplg_fixup && add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
@@ -1842,3 +1950,4 @@ MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
MODULE_IMPORT_NS(SOUNDWIRE_INTEL);
MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
+MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH);
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 81a1d4606d3c..c939a24d770e 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -850,7 +850,8 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai,
- int link_id);
+ int link_id,
+ int intel_alh_id);
int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai,
@@ -1005,4 +1006,12 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
struct snd_soc_dai *cpu_dai);
+static inline struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
+{
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_soc_component *component = swidget->scomp;
+
+ return snd_soc_component_get_drvdata(component);
+}
+
#endif
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index c79479afa8d0..641c4f24cca9 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -80,6 +80,14 @@ static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
fw_header->len, fw_header->num_module_entries);
+ /* copy the fw_version of basefw into debugfs at first boot */
+ if (fw == sdev->basefw.fw) {
+ sdev->fw_version.major = fw_header->major_version;
+ sdev->fw_version.minor = fw_header->minor_version;
+ sdev->fw_version.micro = fw_header->hotfix_version;
+ sdev->fw_version.build = fw_header->build_version;
+ }
+
fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
sizeof(*fw_module), GFP_KERNEL);
if (!fw_lib->modules)
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index afed618a15f0..e157ab80a103 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -98,7 +98,7 @@ extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
extern const struct sof_ipc_pcm_ops ipc4_pcm_ops;
extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
-int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state);
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index bb4cf6dd1e18..34ec27cf0d94 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -586,7 +586,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
switch (ipc4_copier->dai_type) {
case SOF_DAI_INTEL_ALH:
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_alh_configuration_blob *blob;
struct snd_soc_dapm_path *p;
struct snd_sof_widget *w;
@@ -1297,7 +1296,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
}
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
- struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
struct sof_ipc4_alh_configuration_blob *blob;
unsigned int group_id;
@@ -1307,9 +1305,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
ALH_MULTI_GTW_BASE;
ida_free(&alh_group_ida, group_id);
}
-
- /* clear the node ID */
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
}
}
@@ -1474,6 +1469,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
u32 deep_buffer_dma_ms = 0;
int output_fmt_index;
bool single_output_format;
+ int i;
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
@@ -1691,6 +1687,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*/
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
struct sof_ipc4_alh_configuration_blob *blob;
+ struct sof_ipc4_dma_config *dma_config;
struct sof_ipc4_copier_data *alh_data;
struct sof_ipc4_copier *alh_copier;
struct snd_sof_widget *w;
@@ -1699,7 +1696,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
u32 ch_map;
u32 step;
u32 mask;
- int i;
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
@@ -1723,6 +1719,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*/
i = 0;
list_for_each_entry(w, &sdev->widget_list, list) {
+ u32 node_type;
+
if (w->widget->sname &&
strcmp(w->widget->sname, swidget->widget->sname))
continue;
@@ -1730,7 +1728,22 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
dai = w->private;
alh_copier = (struct sof_ipc4_copier *)dai->private;
alh_data = &alh_copier->data;
- blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id;
+ node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
+ blob->alh_cfg.mapping[i].device = SOF_IPC4_NODE_TYPE(node_type);
+ blob->alh_cfg.mapping[i].device |=
+ SOF_IPC4_NODE_INDEX(alh_copier->dai_index);
+
+ /*
+ * The mapping[i] device in ALH blob should be the same as the
+ * dma_config_tlv[i] mapping device if a dma_config_tlv is present.
+ * The device id will be used for DMA tlv mapping purposes.
+ */
+ if (ipc4_copier->dma_config_tlv[i].length) {
+ dma_config = &ipc4_copier->dma_config_tlv[i].dma_config;
+ blob->alh_cfg.mapping[i].device =
+ dma_config->dma_stream_channel_map.mapping[0].device;
+ }
+
/*
* Set the same channel mask for playback as the audio data is
* duplicated for all speakers. For capture, split the channels
@@ -1809,19 +1822,18 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
- if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID &&
- ipc4_copier->dma_config_tlv.length) {
- dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) +
- ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size;
-
- /* paranoia check on TLV size/length */
- if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length +
- sizeof(uint32_t) * 2) {
- dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n",
- dma_config_tlv_size, ipc4_copier->dma_config_tlv.length);
- return -EINVAL;
- }
+ dma_config_tlv_size = 0;
+ for (i = 0; i < SOF_IPC4_DMA_DEVICE_MAX_COUNT; i++) {
+ if (ipc4_copier->dma_config_tlv[i].type != SOF_IPC4_GTW_DMA_CONFIG_ID)
+ continue;
+ dma_config_tlv_size += ipc4_copier->dma_config_tlv[i].length;
+ dma_config_tlv_size +=
+ ipc4_copier->dma_config_tlv[i].dma_config.dma_priv_config_size;
+ dma_config_tlv_size += (sizeof(ipc4_copier->dma_config_tlv[i]) -
+ sizeof(ipc4_copier->dma_config_tlv[i].dma_config));
+ }
+ if (dma_config_tlv_size) {
ipc_size += dma_config_tlv_size;
/* we also need to increase the size at the gtw level */
@@ -2833,17 +2845,24 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
case SOF_DAI_INTEL_HDA:
gtw_attr = ipc4_copier->gtw_attr;
gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
- fallthrough;
+ if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
+ }
+ break;
case SOF_DAI_INTEL_ALH:
/*
* Do not clear the node ID when this op is invoked with
* SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
- * unprepare.
+ * unprepare. The node_id for multi-gateway DAI's will be overwritten with the
+ * group_id during copier's ipc_prepare op.
*/
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
+ ipc4_copier->dai_index = data->dai_node_id;
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
+ copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id);
}
+
break;
case SOF_DAI_INTEL_DMIC:
case SOF_DAI_INTEL_SSP:
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index dce174a190dd..6e33208a357f 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -45,6 +45,7 @@
#define SOF_IPC4_NODE_INDEX_MASK 0xFF
#define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK)
#define SOF_IPC4_NODE_TYPE(x) ((x) << 8)
+#define SOF_IPC4_GET_NODE_TYPE(node_id) ((node_id) >> 8)
/* Node ID for SSP type DAI copiers */
#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4)
@@ -313,7 +314,7 @@ struct sof_ipc4_copier {
struct sof_ipc4_gtw_attributes *gtw_attr;
u32 dai_type;
int dai_index;
- struct sof_ipc4_dma_config_tlv dma_config_tlv;
+ struct sof_ipc4_dma_config_tlv dma_config_tlv[SOF_IPC4_DMA_DEVICE_MAX_COUNT];
};
/**
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index f03cee94bce6..4e11df6b4823 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -196,9 +196,8 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
struct snd_sof_pcm *spcm;
- int ret, err = 0;
+ int ret;
/* nothing to do for BE */
if (rtd->dai_link->no_pcm)
@@ -211,42 +210,18 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
- if (spcm->prepared[substream->stream]) {
- /* stop DMA first if needed */
- if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
- snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
-
- /* free PCM in the DSP */
- if (pcm_ops && pcm_ops->hw_free) {
- ret = pcm_ops->hw_free(component, substream);
- if (ret < 0)
- err = ret;
- }
-
- spcm->prepared[substream->stream] = false;
- }
-
- /* reset DMA */
- ret = snd_sof_pcm_platform_hw_free(sdev, substream);
- if (ret < 0) {
- dev_err(component->dev, "error: platform hw free failed\n");
- err = ret;
- }
-
- /* free the DAPM widget list */
- ret = sof_widget_list_free(sdev, spcm, substream->stream);
- if (ret < 0)
- err = ret;
+ ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
- return err;
+ return ret;
}
static int sof_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
int ret;
@@ -258,8 +233,18 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- if (spcm->prepared[substream->stream])
- return 0;
+ if (spcm->prepared[substream->stream]) {
+ if (!spcm->pending_stop[substream->stream])
+ return 0;
+
+ /*
+ * this case should be reached in case of xruns where we absolutely
+ * want to free-up and reset all PCM/DMA resources
+ */
+ ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
+ if (ret < 0)
+ return ret;
+ }
dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
@@ -302,6 +287,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
spcm->pcm.pcm_id, substream->stream, cmd);
+ spcm->pending_stop[substream->stream] = false;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ipc_first = true;
@@ -371,6 +358,15 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
/* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */
if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
+
+ /*
+ * set the pending_stop flag to indicate that pipeline stop has been delayed.
+ * This will be used later to stop the pipelines during prepare when recovering
+ * from xruns.
+ */
+ if (pcm_ops && pcm_ops->platform_stop_during_hw_free &&
+ cmd == SNDRV_PCM_TRIGGER_STOP)
+ spcm->pending_stop[substream->stream] = true;
break;
default:
break;
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index e693dcb475e4..32fef64ef10d 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -834,35 +834,48 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs
{
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
int ret;
+ int err = 0;
if (spcm->prepared[substream->stream]) {
/* stop DMA first if needed */
if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
- /* Send PCM_FREE IPC to reset pipeline */
+ /* free PCM in the DSP */
if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(sdev->component, substream);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
+ __func__, ret);
+ err = ret;
+ }
}
spcm->prepared[substream->stream] = false;
+ spcm->pending_stop[substream->stream] = false;
}
/* reset the DMA */
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: platform hw free failed %d\n",
+ __func__, ret);
+ if (!err)
+ err = ret;
+ }
/* free widget list */
if (free_widget_list) {
ret = sof_widget_list_free(sdev, spcm, dir);
- if (ret < 0)
- dev_err(sdev->dev, "failed to free widgets during suspend\n");
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
+ __func__, ret);
+ if (!err)
+ err = ret;
+ }
}
- return ret;
+ return err;
}
/*
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 86bbb531e142..f4134257789e 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -91,6 +91,7 @@ struct snd_sof_pcm;
struct snd_sof_dai_config_data {
int dai_index;
int dai_data; /* contains DAI-specific information */
+ int dai_node_id; /* contains DAI-specific information for Gateway configuration */
};
/**
@@ -348,6 +349,7 @@ struct snd_sof_pcm {
struct list_head list; /* list in sdev pcm list */
struct snd_pcm_hw_params params[2];
bool prepared[2]; /* PCM_PARAMS set successfully */
+ bool pending_stop[2]; /* only used if (!pcm_ops->platform_stop_during_hw_free) */
};
struct snd_sof_led_control {
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index 8a32d05e23e1..2dcdf113b66e 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -115,9 +115,16 @@
#define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e
#define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7
+#define SUN50I_ADDA_MDET_CTRL 0x1c
+#define SUN50I_ADDA_MDET_CTRL_SELDETADC_FS 4
+#define SUN50I_ADDA_MDET_CTRL_SELDETADC_DB 2
+#define SUN50I_ADDA_MDET_CTRL_SELDETADC_BF 0
+
#define SUN50I_ADDA_JACK_MIC_CTRL 0x1d
+#define SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN 7
#define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN 6
#define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5
+#define SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN 4
/* mixer controls */
static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
@@ -296,6 +303,19 @@ static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {
SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
};
+static int sun50i_codec_hbias_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u32 value = !!SND_SOC_DAPM_EVENT_ON(event);
+
+ regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),
+ value << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
/* DAC */
SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
@@ -367,7 +387,8 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
/* Microphone Bias */
SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
- 0, NULL, 0),
+ 0, sun50i_codec_hbias_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Mic input path */
SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
@@ -471,17 +492,37 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
{ "EARPIECE", NULL, "Earpiece Amp" },
};
-static int sun50i_a64_codec_suspend(struct snd_soc_component *component)
+static int sun50i_a64_codec_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
{
- return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
- BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE),
- BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
-}
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int hbias;
+
+ switch (level) {
+ case SND_SOC_BIAS_OFF:
+ regmap_clear_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN));
+
+ regmap_set_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
+ BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regmap_clear_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
+ BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
+
+ hbias = snd_soc_dapm_get_pin_status(dapm, "HBIAS");
+ regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL,
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN),
+ BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) |
+ hbias << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN);
+ break;
+ default:
+ break;
+ }
-static int sun50i_a64_codec_resume(struct snd_soc_component *component)
-{
- return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
- BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0);
+ return 0;
}
static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
@@ -491,8 +532,9 @@ static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
.num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets),
.dapm_routes = sun50i_a64_codec_routes,
.num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes),
- .suspend = sun50i_a64_codec_suspend,
- .resume = sun50i_a64_codec_resume,
+ .set_bias_level = sun50i_a64_codec_set_bias_level,
+ .idle_bias_on = true,
+ .suspend_bias_off = true,
};
static const struct of_device_id sun50i_codec_analog_of_match[] = {
@@ -527,6 +569,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev)
BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN),
enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN);
+ /* Select sample interval of the ADC sample to 16ms */
+ regmap_update_bits(regmap, SUN50I_ADDA_MDET_CTRL,
+ 0x7 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |
+ 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF,
+ 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS |
+ 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF);
+
return devm_snd_soc_register_component(&pdev->dev,
&sun50i_codec_analog_cmpnt_drv,
NULL, 0);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7b45ddffe990..b5dafb749c3f 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -12,12 +12,16 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
+#include <linux/input.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/log2.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -118,6 +122,23 @@
#define SUN8I_ADC_VOL_CTRL 0x104
#define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8
#define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0
+#define SUN8I_HMIC_CTRL1 0x110
+#define SUN8I_HMIC_CTRL1_HMIC_M 12
+#define SUN8I_HMIC_CTRL1_HMIC_N 8
+#define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB 5
+#define SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN 4
+#define SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN 3
+#define SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN 0
+#define SUN8I_HMIC_CTRL2 0x114
+#define SUN8I_HMIC_CTRL2_HMIC_SAMPLE 14
+#define SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD 8
+#define SUN8I_HMIC_CTRL2_HMIC_SF 6
+#define SUN8I_HMIC_STS 0x118
+#define SUN8I_HMIC_STS_MDATA_DISCARD 13
+#define SUN8I_HMIC_STS_HMIC_DATA 8
+#define SUN8I_HMIC_STS_JACK_OUT_IRQ_ST 4
+#define SUN8I_HMIC_STS_JACK_IN_IRQ_ST 3
+#define SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST 0
#define SUN8I_DAC_DIG_CTRL 0x120
#define SUN8I_DAC_DIG_CTRL_ENDA 15
#define SUN8I_DAC_VOL_CTRL 0x124
@@ -143,6 +164,17 @@
#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4)
#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2)
#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK GENMASK(1, 0)
+#define SUN8I_HMIC_CTRL1_HMIC_M_MASK GENMASK(15, 12)
+#define SUN8I_HMIC_CTRL1_HMIC_N_MASK GENMASK(11, 8)
+#define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB_MASK GENMASK(6, 5)
+#define SUN8I_HMIC_CTRL2_HMIC_SAMPLE_MASK GENMASK(15, 14)
+#define SUN8I_HMIC_CTRL2_HMIC_SF_MASK GENMASK(7, 6)
+#define SUN8I_HMIC_STS_HMIC_DATA_MASK GENMASK(12, 8)
+
+#define SUN8I_CODEC_BUTTONS (SND_JACK_BTN_0|\
+ SND_JACK_BTN_1|\
+ SND_JACK_BTN_2|\
+ SND_JACK_BTN_3)
#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
@@ -177,15 +209,34 @@ struct sun8i_codec_aif {
};
struct sun8i_codec_quirks {
- bool legacy_widgets : 1;
- bool lrck_inversion : 1;
+ bool bus_clock : 1;
+ bool jack_detection : 1;
+ bool legacy_widgets : 1;
+ bool lrck_inversion : 1;
+};
+
+enum {
+ SUN8I_JACK_STATUS_DISCONNECTED,
+ SUN8I_JACK_STATUS_WAITING_HBIAS,
+ SUN8I_JACK_STATUS_CONNECTED,
};
struct sun8i_codec {
+ struct snd_soc_component *component;
struct regmap *regmap;
+ struct clk *clk_bus;
struct clk *clk_module;
const struct sun8i_codec_quirks *quirks;
struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS];
+ struct snd_soc_jack *jack;
+ struct delayed_work jack_work;
+ int jack_irq;
+ int jack_status;
+ int jack_type;
+ int jack_last_sample;
+ ktime_t jack_hbias_ready;
+ struct mutex jack_mutex;
+ int last_hmic_irq;
unsigned int sysclk_rate;
int sysclk_refcnt;
};
@@ -197,6 +248,14 @@ static int sun8i_codec_runtime_resume(struct device *dev)
struct sun8i_codec *scodec = dev_get_drvdata(dev);
int ret;
+ if (scodec->clk_bus) {
+ ret = clk_prepare_enable(scodec->clk_bus);
+ if (ret) {
+ dev_err(dev, "Failed to enable the bus clock\n");
+ return ret;
+ }
+ }
+
regcache_cache_only(scodec->regmap, false);
ret = regcache_sync(scodec->regmap);
@@ -215,6 +274,9 @@ static int sun8i_codec_runtime_suspend(struct device *dev)
regcache_cache_only(scodec->regmap, true);
regcache_mark_dirty(scodec->regmap);
+ if (scodec->clk_bus)
+ clk_disable_unprepare(scodec->clk_bus);
+
return 0;
}
@@ -1232,6 +1294,8 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
int ret;
+ scodec->component = component;
+
/* Add widgets for backward compatibility with old device trees. */
if (scodec->quirks->legacy_widgets) {
ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
@@ -1268,6 +1332,250 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component)
return 0;
}
+static void sun8i_codec_set_hmic_bias(struct sun8i_codec *scodec, bool enable)
+{
+ struct snd_soc_dapm_context *dapm = &scodec->component->card->dapm;
+ int irq_mask = BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN);
+
+ if (enable)
+ snd_soc_dapm_force_enable_pin(dapm, "HBIAS");
+ else
+ snd_soc_dapm_disable_pin(dapm, "HBIAS");
+
+ snd_soc_dapm_sync(dapm);
+
+ regmap_update_bits(scodec->regmap, SUN8I_HMIC_CTRL1,
+ irq_mask, enable ? irq_mask : 0);
+}
+
+static void sun8i_codec_jack_work(struct work_struct *work)
+{
+ struct sun8i_codec *scodec = container_of(work, struct sun8i_codec,
+ jack_work.work);
+ unsigned int mdata;
+ int type;
+
+ guard(mutex)(&scodec->jack_mutex);
+
+ if (scodec->jack_status == SUN8I_JACK_STATUS_DISCONNECTED) {
+ if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_IN_IRQ_ST)
+ return;
+
+ scodec->jack_last_sample = -1;
+
+ if (scodec->jack_type & SND_JACK_MICROPHONE) {
+ /*
+ * If we were in disconnected state, we enable HBIAS and
+ * wait 600ms before reading initial HDATA value.
+ */
+ scodec->jack_hbias_ready = ktime_add_ms(ktime_get(), 600);
+ sun8i_codec_set_hmic_bias(scodec, true);
+ queue_delayed_work(system_power_efficient_wq,
+ &scodec->jack_work,
+ msecs_to_jiffies(610));
+ scodec->jack_status = SUN8I_JACK_STATUS_WAITING_HBIAS;
+ } else {
+ snd_soc_jack_report(scodec->jack, SND_JACK_HEADPHONE,
+ scodec->jack_type);
+ scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED;
+ }
+ } else if (scodec->jack_status == SUN8I_JACK_STATUS_WAITING_HBIAS) {
+ /*
+ * If we're waiting for HBIAS to stabilize, and we get plug-out
+ * interrupt and nothing more for > 100ms, just cancel the
+ * initialization.
+ */
+ if (scodec->last_hmic_irq == SUN8I_HMIC_STS_JACK_OUT_IRQ_ST) {
+ scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED;
+ sun8i_codec_set_hmic_bias(scodec, false);
+ return;
+ }
+
+ /*
+ * If we're not done waiting for HBIAS to stabilize, wait more.
+ */
+ if (!ktime_after(ktime_get(), scodec->jack_hbias_ready)) {
+ s64 msecs = ktime_ms_delta(scodec->jack_hbias_ready,
+ ktime_get());
+
+ queue_delayed_work(system_power_efficient_wq,
+ &scodec->jack_work,
+ msecs_to_jiffies(msecs + 10));
+ return;
+ }
+
+ /*
+ * Everything is stabilized, determine jack type and report it.
+ */
+ regmap_read(scodec->regmap, SUN8I_HMIC_STS, &mdata);
+ mdata &= SUN8I_HMIC_STS_HMIC_DATA_MASK;
+ mdata >>= SUN8I_HMIC_STS_HMIC_DATA;
+
+ regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0);
+
+ type = mdata < 16 ? SND_JACK_HEADPHONE : SND_JACK_HEADSET;
+ if (type == SND_JACK_HEADPHONE)
+ sun8i_codec_set_hmic_bias(scodec, false);
+
+ snd_soc_jack_report(scodec->jack, type, scodec->jack_type);
+ scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED;
+ } else if (scodec->jack_status == SUN8I_JACK_STATUS_CONNECTED) {
+ if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_OUT_IRQ_ST)
+ return;
+
+ scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED;
+ if (scodec->jack_type & SND_JACK_MICROPHONE)
+ sun8i_codec_set_hmic_bias(scodec, false);
+
+ snd_soc_jack_report(scodec->jack, 0, scodec->jack_type);
+ }
+}
+
+static irqreturn_t sun8i_codec_jack_irq(int irq, void *dev_id)
+{
+ struct sun8i_codec *scodec = dev_id;
+ int type = SND_JACK_HEADSET;
+ unsigned int status, value;
+
+ guard(mutex)(&scodec->jack_mutex);
+
+ regmap_read(scodec->regmap, SUN8I_HMIC_STS, &status);
+ regmap_write(scodec->regmap, SUN8I_HMIC_STS, status);
+
+ /*
+ * De-bounce in/out interrupts via a delayed work re-scheduling to
+ * 100ms after each interrupt..
+ */
+ if (status & BIT(SUN8I_HMIC_STS_JACK_OUT_IRQ_ST)) {
+ /*
+ * Out interrupt has priority over in interrupt so that if
+ * we get both, we assume the disconnected state, which is
+ * safer.
+ */
+ scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_OUT_IRQ_ST;
+ mod_delayed_work(system_power_efficient_wq, &scodec->jack_work,
+ msecs_to_jiffies(100));
+ } else if (status & BIT(SUN8I_HMIC_STS_JACK_IN_IRQ_ST)) {
+ scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_IN_IRQ_ST;
+ mod_delayed_work(system_power_efficient_wq, &scodec->jack_work,
+ msecs_to_jiffies(100));
+ } else if (status & BIT(SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST)) {
+ /*
+ * Ignore data interrupts until jack status turns to connected
+ * state, which is after HMIC enable stabilization is completed.
+ * Until then tha data are bogus.
+ */
+ if (scodec->jack_status != SUN8I_JACK_STATUS_CONNECTED)
+ return IRQ_HANDLED;
+
+ value = (status & SUN8I_HMIC_STS_HMIC_DATA_MASK) >>
+ SUN8I_HMIC_STS_HMIC_DATA;
+
+ /*
+ * Assumes 60 mV per ADC LSB increment, 2V bias voltage, 2.2kOhm
+ * bias resistor.
+ */
+ if (value == 0)
+ type |= SND_JACK_BTN_0;
+ else if (value == 1)
+ type |= SND_JACK_BTN_3;
+ else if (value <= 3)
+ type |= SND_JACK_BTN_1;
+ else if (value <= 8)
+ type |= SND_JACK_BTN_2;
+
+ /*
+ * De-bounce. Only report button after two consecutive A/D
+ * samples are identical.
+ */
+ if (scodec->jack_last_sample >= 0 &&
+ scodec->jack_last_sample == value)
+ snd_soc_jack_report(scodec->jack, type,
+ scodec->jack_type);
+
+ scodec->jack_last_sample = value;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int sun8i_codec_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+ struct platform_device *pdev = to_platform_device(component->dev);
+ int ret;
+
+ if (!scodec->quirks->jack_detection)
+ return 0;
+
+ scodec->jack = jack;
+
+ scodec->jack_irq = platform_get_irq(pdev, 0);
+ if (scodec->jack_irq < 0)
+ return scodec->jack_irq;
+
+ /* Reserved value required for jack IRQs to trigger. */
+ regmap_write(scodec->regmap, SUN8I_HMIC_CTRL1,
+ 0xf << SUN8I_HMIC_CTRL1_HMIC_N |
+ 0x0 << SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB |
+ 0x4 << SUN8I_HMIC_CTRL1_HMIC_M);
+
+ /* Sample the ADC at 128 Hz; bypass smooth filter. */
+ regmap_write(scodec->regmap, SUN8I_HMIC_CTRL2,
+ 0x0 << SUN8I_HMIC_CTRL2_HMIC_SAMPLE |
+ 0x17 << SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD |
+ 0x0 << SUN8I_HMIC_CTRL2_HMIC_SF);
+
+ /* Do not discard any MDATA, enable user written MDATA threshold. */
+ regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0);
+
+ regmap_set_bits(scodec->regmap, SUN8I_HMIC_CTRL1,
+ BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) |
+ BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN));
+
+ ret = devm_request_threaded_irq(&pdev->dev, scodec->jack_irq,
+ NULL, sun8i_codec_jack_irq,
+ IRQF_ONESHOT,
+ dev_name(&pdev->dev), scodec);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void sun8i_codec_disable_jack_detect(struct snd_soc_component *component)
+{
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
+
+ if (!scodec->quirks->jack_detection)
+ return;
+
+ devm_free_irq(component->dev, scodec->jack_irq, scodec);
+
+ cancel_delayed_work_sync(&scodec->jack_work);
+
+ regmap_clear_bits(scodec->regmap, SUN8I_HMIC_CTRL1,
+ BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) |
+ BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN) |
+ BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN));
+
+ scodec->jack = NULL;
+}
+
+static int sun8i_codec_component_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ int ret = 0;
+
+ if (jack)
+ ret = sun8i_codec_enable_jack_detect(component, jack, data);
+ else
+ sun8i_codec_disable_jack_detect(component);
+
+ return ret;
+}
+
static const struct snd_soc_component_driver sun8i_soc_component = {
.controls = sun8i_codec_controls,
.num_controls = ARRAY_SIZE(sun8i_codec_controls),
@@ -1275,15 +1583,23 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
.num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
.dapm_routes = sun8i_codec_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
+ .set_jack = sun8i_codec_component_set_jack,
.probe = sun8i_codec_component_probe,
.idle_bias_on = 1,
+ .suspend_bias_off = 1,
.endianness = 1,
};
+static bool sun8i_codec_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == SUN8I_HMIC_STS;
+}
+
static const struct regmap_config sun8i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
+ .volatile_reg = sun8i_codec_volatile_reg,
.max_register = SUN8I_DAC_MXR_SRC,
.cache_type = REGCACHE_FLAT,
@@ -1299,6 +1615,20 @@ static int sun8i_codec_probe(struct platform_device *pdev)
if (!scodec)
return -ENOMEM;
+ scodec->quirks = of_device_get_match_data(&pdev->dev);
+ INIT_DELAYED_WORK(&scodec->jack_work, sun8i_codec_jack_work);
+ mutex_init(&scodec->jack_mutex);
+
+ platform_set_drvdata(pdev, scodec);
+
+ if (scodec->quirks->bus_clock) {
+ scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(scodec->clk_bus)) {
+ dev_err(&pdev->dev, "Failed to get the bus clock\n");
+ return PTR_ERR(scodec->clk_bus);
+ }
+ }
+
scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(scodec->clk_module)) {
dev_err(&pdev->dev, "Failed to get the module clock\n");
@@ -1311,17 +1641,14 @@ static int sun8i_codec_probe(struct platform_device *pdev)
return PTR_ERR(base);
}
- scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
- &sun8i_codec_regmap_config);
+ scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sun8i_codec_regmap_config);
if (IS_ERR(scodec->regmap)) {
dev_err(&pdev->dev, "Failed to create our regmap\n");
return PTR_ERR(scodec->regmap);
}
- scodec->quirks = of_device_get_match_data(&pdev->dev);
-
- platform_set_drvdata(pdev, scodec);
-
+ regcache_cache_only(scodec->regmap, true);
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = sun8i_codec_runtime_resume(&pdev->dev);
@@ -1357,11 +1684,14 @@ static void sun8i_codec_remove(struct platform_device *pdev)
}
static const struct sun8i_codec_quirks sun8i_a33_quirks = {
+ .bus_clock = true,
.legacy_widgets = true,
.lrck_inversion = true,
};
static const struct sun8i_codec_quirks sun50i_a64_quirks = {
+ .bus_clock = true,
+ .jack_detection = true,
};
static const struct of_device_id sun8i_codec_of_match[] = {