ASoC: adau1372: fixes after debugging custom board
authorMark Brown <broonie@kernel.org>
Fri, 25 Nov 2022 21:26:21 +0000 (21:26 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 25 Nov 2022 21:26:21 +0000 (21:26 +0000)
Merge series from Maarten Zanders <maarten.zanders@mind.be>:

A collection of fixes and improvements for the adau1372 driver.

264 files changed:
Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
Documentation/devicetree/bindings/sound/dmic-codec.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/dmic.txt [deleted file]
Documentation/devicetree/bindings/sound/fsl,micfil.yaml
Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
Documentation/devicetree/bindings/sound/fsl,sai.yaml
Documentation/devicetree/bindings/sound/ingenic,aic.yaml
Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
Documentation/devicetree/bindings/sound/mt8192-mt6359-rt1015-rt5682.yaml
Documentation/devicetree/bindings/sound/mvebu-audio.txt
Documentation/devicetree/bindings/sound/nau8315.txt
Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml
Documentation/devicetree/bindings/sound/rt5682.txt
Documentation/devicetree/bindings/sound/wlf,wm8961.yaml [new file with mode: 0644]
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/common-board-devices.h
arch/arm/mach-omap2/pdata-quirks.c
drivers/firmware/cirrus/Kconfig
drivers/firmware/cirrus/Makefile
drivers/firmware/cirrus/cs_dsp.c
drivers/i2c/i2c-core-base.c
drivers/soundwire/intel_init.c
include/linux/i2c.h
include/linux/soundwire/sdw_intel.h
include/sound/acp63_chip_offset_byte.h [moved from include/sound/acp62_chip_offset_byte.h with 65% similarity]
include/sound/hdaudio.h
include/sound/hdaudio_ext.h
include/sound/simple_card_utils.h
include/sound/soc-dapm.h
include/sound/soc-dpcm.h
include/sound/sof.h
include/sound/sof/ipc4/header.h
include/sound/tlv320aic3x.h [deleted file]
include/uapi/sound/snd_ar_tokens.h
include/uapi/sound/sof/tokens.h
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_stream.c
sound/hda/hdac_stream.c
sound/pci/hda/Kconfig
sound/pci/hda/cs35l41_hda.c
sound/pci/hda/hda_cs_dsp_ctl.c
sound/soc/amd/Kconfig
sound/soc/amd/acp-da7219-max98357a.c
sound/soc/amd/acp/acp-i2s.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-platform.c
sound/soc/amd/ps/acp63.h [moved from sound/soc/amd/ps/acp62.h with 79% similarity]
sound/soc/amd/ps/pci-ps.c
sound/soc/amd/ps/ps-mach.c
sound/soc/amd/ps/ps-pdm-dma.c
sound/soc/atmel/mchp-spdiftx.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1372.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau17x1.c
sound/soc/codecs/ak4458.c
sound/soc/codecs/cs35l36.c
sound/soc/codecs/cs42l83-i2c.c
sound/soc/codecs/cs42xx8-i2c.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/cs42xx8.h
sound/soc/codecs/da7219-aad.c
sound/soc/codecs/da7219.c
sound/soc/codecs/es8326.c
sound/soc/codecs/hda.c
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/jz4725b.c
sound/soc/codecs/lpass-tx-macro.c
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/max98396.c
sound/soc/codecs/nau8315.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1308-sdw.h
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt1316-sdw.h
sound/soc/codecs/rt1318-sdw.c [new file with mode: 0644]
sound/soc/codecs/rt1318-sdw.h [new file with mode: 0644]
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt5682s.c
sound/soc/codecs/rt5682s.h
sound/soc/codecs/simple-mux.c
sound/soc/codecs/src4xxx-i2c.c
sound/soc/codecs/tas2780.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/twl4030.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wsa883x.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_micfil.h
sound/soc/fsl/fsl_rpmsg.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_xcvr.c
sound/soc/fsl/fsl_xcvr.h
sound/soc/fsl/imx-audio-rpmsg.c
sound/soc/fsl/imx-pcm-rpmsg.c
sound/soc/fsl/imx-rpmsg.c
sound/soc/generic/audio-graph-card2-custom-sample.dtsi
sound/soc/generic/audio-graph-card2.c
sound/soc/generic/simple-card-utils.c
sound/soc/intel/Kconfig
sound/soc/intel/avs/apl.c
sound/soc/intel/avs/avs.h
sound/soc/intel/avs/board_selection.c
sound/soc/intel/avs/boards/Kconfig
sound/soc/intel/avs/boards/Makefile
sound/soc/intel/avs/boards/da7219.c
sound/soc/intel/avs/boards/hdaudio.c
sound/soc/intel/avs/boards/max98373.c
sound/soc/intel/avs/boards/max98927.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt298.c
sound/soc/intel/avs/boards/ssm4567.c
sound/soc/intel/avs/core.c
sound/soc/intel/avs/ipc.c
sound/soc/intel/avs/loader.c
sound/soc/intel/avs/messages.c
sound/soc/intel/avs/messages.h
sound/soc/intel/avs/pcm.c
sound/soc/intel/avs/skl.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw-rt5650.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_nau8824.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/kbl_da7219_max98357a.c
sound/soc/intel/boards/kbl_da7219_max98927.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/sof_cirrus_common.c
sound/soc/intel/boards/sof_da7219_max98373.c
sound/soc/intel/boards/sof_nau8825.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h [new file with mode: 0644]
sound/soc/intel/boards/sof_sdw_common.h
sound/soc/intel/boards/sof_sdw_rt1308.c
sound/soc/intel/boards/sof_sdw_rt1316.c
sound/soc/intel/boards/sof_sdw_rt1318.c [new file with mode: 0644]
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-mtl-match.c
sound/soc/intel/common/soc-acpi-intel-rpl-match.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl.c
sound/soc/jz4740/Kconfig
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/jz4740-i2s.h [deleted file]
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood.h
sound/soc/mediatek/common/mtk-btcvsd.c
sound/soc/mediatek/mt2701/mt2701-cs42448.c
sound/soc/mediatek/mt2701/mt2701-wm8960.c
sound/soc/mediatek/mt6797/mt6797-mt6351.c
sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
sound/soc/mediatek/mt8195/mt8195-mt6359.c
sound/soc/meson/axg-pdm.c
sound/soc/pxa/mmp-pcm.c
sound/soc/qcom/Kconfig
sound/soc/qcom/common.c
sound/soc/qcom/common.h
sound/soc/qcom/lpass-sc7180.c
sound/soc/qcom/qdsp6/audioreach.c
sound/soc/qcom/qdsp6/audioreach.h
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/qcom/qdsp6/q6apm.h
sound/soc/qcom/qdsp6/q6prm.c
sound/soc/qcom/qdsp6/topology.c
sound/soc/rockchip/rk3399_gru_sound.c
sound/soc/sh/rcar/core.c
sound/soc/soc-core.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-utils.c
sound/soc/sof/Kconfig
sound/soc/sof/Makefile
sound/soc/sof/amd/acp-loader.c
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/Makefile
sound/soc/sof/intel/apl.c
sound/soc/sof/intel/bdw.c
sound/soc/sof/intel/byt.c
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda-bus.c
sound/soc/sof/intel/hda-codec.c
sound/soc/sof/intel/hda-common-ops.c
sound/soc/sof/intel/hda-ctrl.c
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-ipc.c
sound/soc/sof/intel/hda-loader-skl.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-mlink.c [new file with mode: 0644]
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/intel/icl.c
sound/soc/sof/intel/mtl.c
sound/soc/sof/intel/mtl.h
sound/soc/sof/intel/pci-apl.c
sound/soc/sof/intel/pci-cnl.c
sound/soc/sof/intel/pci-icl.c
sound/soc/sof/intel/pci-mtl.c
sound/soc/sof/intel/pci-tgl.c
sound/soc/sof/intel/pci-tng.c
sound/soc/sof/intel/shim.h
sound/soc/sof/intel/tgl.c
sound/soc/sof/ipc.c
sound/soc/sof/ipc3-loader.c
sound/soc/sof/ipc3.c
sound/soc/sof/ipc4-loader.c
sound/soc/sof/ipc4-pcm.c
sound/soc/sof/ipc4-priv.h
sound/soc/sof/ipc4-topology.c
sound/soc/sof/ipc4.c
sound/soc/sof/loader.c
sound/soc/sof/ops.h
sound/soc/sof/sof-audio.c
sound/soc/sof/sof-audio.h
sound/soc/sof/sof-client-probes-ipc3.c [new file with mode: 0644]
sound/soc/sof/sof-client-probes-ipc4.c [new file with mode: 0644]
sound/soc/sof/sof-client-probes.c
sound/soc/sof/sof-client-probes.h
sound/soc/sof/sof-client.c
sound/soc/sof/sof-client.h
sound/soc/sof/sof-pci-dev.c
sound/soc/sof/sof-priv.h
sound/soc/sof/topology.c
sound/soc/sunxi/sun50i-dmic.c
sound/soc/tegra/tegra210_mbdrc.c
sound/soc/tegra/tegra210_mbdrc.h
sound/soc/ti/davinci-mcasp.c

index 2f12cab..0920f2f 100644 (file)
@@ -11,7 +11,12 @@ maintainers:
 
 properties:
   compatible:
-    const: allwinner,sun50i-h6-dmic
+    oneOf:
+      - items:
+          - enum:
+              - allwinner,sun20i-d1-dmic
+          - const: allwinner,sun50i-h6-dmic
+      - const: allwinner,sun50i-h6-dmic
 
   "#sound-dai-cells":
     const: 0
diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
new file mode 100644 (file)
index 0000000..bba27c9
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/dmic-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic PDM Digital microphone (DMIC) codec
+
+maintainers:
+  - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+
+allOf:
+  - $ref: name-prefix.yaml#
+
+properties:
+  compatible:
+    const: dmic-codec
+
+  '#sound-dai-cells':
+    const: 0
+
+  dmicen-gpios:
+    description: GPIO specifier for DMIC to control start and stop
+    maxItems: 1
+
+  num-channels:
+    description: Number of microphones on this DAI
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+    maximum: 8
+    default: 8
+
+  modeswitch-delay-ms:
+    description: Delay (in ms) to complete DMIC mode switch
+
+  wakeup-delay-ms:
+    description: Delay (in ms) after enabling the DMIC
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dmic {
+        compatible = "dmic-codec";
+        dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
+        num-channels = <1>;
+        wakeup-delay-ms = <50>;
+        modeswitch-delay-ms = <35>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt
deleted file mode 100644 (file)
index 32e8710..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Device-Tree bindings for Digital microphone (DMIC) codec
-
-This device support generic PDM digital microphone.
-
-Required properties:
-       - compatible: should be "dmic-codec".
-
-Optional properties:
-       - dmicen-gpios: GPIO specifier for dmic to control start and stop
-       - num-channels: Number of microphones on this DAI
-       - wakeup-delay-ms: Delay (in ms) after enabling the DMIC
-       - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
-
-Example node:
-
-       dmic_codec: dmic@0 {
-               compatible = "dmic-codec";
-               dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
-               num-channels = <1>;
-               wakeup-delay-ms <50>;
-               modeswitch-delay-ms <35>;
-       };
index 64d5775..4b99a18 100644 (file)
@@ -18,6 +18,7 @@ properties:
     enum:
       - fsl,imx8mm-micfil
       - fsl,imx8mp-micfil
+      - fsl,imx93-micfil
 
   reg:
     maxItems: 1
index d370c98..e847611 100644 (file)
@@ -11,8 +11,11 @@ maintainers:
 
 description: |
   fsl_rpmsg is a virtual audio device. Mapping to real hardware devices
-  are SAI, DMA controlled by Cortex M core. What we see from Linux
-  side is a device which provides audio service by rpmsg channel.
+  are SAI, MICFIL, DMA controlled by Cortex M core. What we see from
+  Linux side is a device which provides audio service by rpmsg channel.
+  We can create different sound cards which access different hardwares
+  such as SAI, MICFIL, .etc through building rpmsg channels between
+  Cortex-A and Cortex-M.
 
 properties:
   compatible:
@@ -85,6 +88,16 @@ properties:
       This is a boolean property. If present, the receiving function
       will be enabled.
 
+  fsl,rpmsg-channel-name:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: |
+      A string property to assign rpmsg channel this sound card sits on.
+      This property can be omitted if there is only one sound card and it sits
+      on "rpmsg-audio-channel".
+    enum:
+      - rpmsg-audio-channel
+      - rpmsg-micfil-channel
+
 required:
   - compatible
   - model
@@ -107,3 +120,22 @@ examples:
                  <&clk IMX8MN_AUDIO_PLL2_OUT>;
         clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
     };
+
+  - |
+    #include <dt-bindings/clock/imx8mm-clock.h>
+
+    rpmsg_micfil: audio-controller {
+        compatible = "fsl,imx8mm-rpmsg-audio";
+        model = "micfil-audio";
+        fsl,rpmsg-channel-name = "rpmsg-micfil-channel";
+        fsl,enable-lpa;
+        fsl,rpmsg-in;
+        clocks = <&clk IMX8MM_CLK_PDM_IPG>,
+                 <&clk IMX8MM_CLK_PDM_ROOT>,
+                 <&clk IMX8MM_CLK_SDMA3_ROOT>,
+                 <&clk IMX8MM_AUDIO_PLL1_OUT>,
+                 <&clk IMX8MM_AUDIO_PLL2_OUT>;
+        clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
+    };
+
+...
index 70c4111..022da1f 100644 (file)
@@ -18,14 +18,12 @@ description: |
 properties:
   compatible:
     oneOf:
-      - enum:
-          - fsl,vf610-sai
-          - fsl,imx6sx-sai
-          - fsl,imx6ul-sai
-          - fsl,imx7ulp-sai
-          - fsl,imx8mq-sai
-          - fsl,imx8qm-sai
-          - fsl,imx8ulp-sai
+      - items:
+          - enum:
+              - fsl,imx6ul-sai
+              - fsl,imx7d-sai
+          - const: fsl,imx6sx-sai
+
       - items:
           - enum:
               - fsl,imx8mm-sai
@@ -33,19 +31,18 @@ properties:
               - fsl,imx8mp-sai
           - const: fsl,imx8mq-sai
 
+      - items:
+          - enum:
+              - fsl,imx6sx-sai
+              - fsl,imx7ulp-sai
+              - fsl,imx8mq-sai
+              - fsl,imx8qm-sai
+              - fsl,imx8ulp-sai
+              - fsl,vf610-sai
+
   reg:
     maxItems: 1
 
-  interrupts:
-    items:
-      - description: receive and transmit interrupt
-
-  dmas:
-    maxItems: 2
-
-  dma-names:
-    maxItems: 2
-
   clocks:
     items:
       - description: The ipg clock for register access
@@ -67,7 +64,7 @@ properties:
           - const: mclk3
           - const: pll8k
           - const: pll11k
-        minItems: 4
+        minItems: 5
       - items:
           - const: bus
           - const: mclk1
@@ -77,19 +74,37 @@ properties:
           - const: pll11k
         minItems: 4
 
-  lsb-first:
-    description: |
-      Configures whether the LSB or the MSB is transmitted
-      first for the fifo data. If this property is absent,
-      the MSB is transmitted first as default, or the LSB
-      is transmitted first.
-    type: boolean
+  dmas:
+    maxItems: 2
+
+  dma-names:
+    maxItems: 2
+
+  interrupts:
+    items:
+      - description: receive and transmit interrupt
 
   big-endian:
     description: |
       required if all the SAI registers are big-endian rather than little-endian.
     type: boolean
 
+  fsl,dataline:
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    description: |
+      Configure the dataline. It has 3 value for each configuration
+    maxItems: 16
+    items:
+      items:
+        - description: format Default(0), I2S(1) or PDM(2)
+          enum: [0, 1, 2]
+        - description: dataline mask for 'rx'
+        - description: dataline mask for 'tx'
+
+  fsl,sai-mclk-direction-output:
+    description: SAI will output the SAI MCLK clock.
+    type: boolean
+
   fsl,sai-synchronous-rx:
     description: |
       SAI will work in the synchronous mode (sync Tx with Rx) which means
@@ -108,26 +123,18 @@ properties:
       of transmitter.
     type: boolean
 
-  fsl,dataline:
-    $ref: /schemas/types.yaml#/definitions/uint32-matrix
-    description: |
-      Configure the dataline. It has 3 value for each configuration
-    maxItems: 16
-    items:
-      items:
-        - description: format Default(0), I2S(1) or PDM(2)
-          enum: [0, 1, 2]
-        - description: dataline mask for 'rx'
-        - description: dataline mask for 'tx'
-
-  fsl,sai-mclk-direction-output:
-    description: SAI will output the SAI MCLK clock.
-    type: boolean
-
   fsl,shared-interrupt:
     description: Interrupt is shared with other modules.
     type: boolean
 
+  lsb-first:
+    description: |
+      Configures whether the LSB or the MSB is transmitted
+      first for the fifo data. If this property is absent,
+      the MSB is transmitted first as default, or the LSB
+      is transmitted first.
+    type: boolean
+
   "#sound-dai-cells":
     const: 0
     description: optional, some dts node didn't add it.
@@ -168,11 +175,11 @@ allOf:
 required:
   - compatible
   - reg
-  - interrupts
-  - dmas
-  - dma-names
   - clocks
   - clock-names
+  - dmas
+  - dma-names
+  - interrupts
 
 additionalProperties: false
 
index d607325..c4f9b3c 100644 (file)
@@ -37,15 +37,11 @@ properties:
     items:
       - description: AIC clock
       - description: I2S clock
-      - description: EXT clock
-      - description: PLL/2 clock
 
   clock-names:
     items:
       - const: aic
       - const: i2s
-      - const: ext
-      - const: pll half
 
   dmas:
     items:
@@ -82,10 +78,8 @@ examples:
       interrupts = <18>;
 
       clocks = <&cgu JZ4740_CLK_AIC>,
-               <&cgu JZ4740_CLK_I2S>,
-               <&cgu JZ4740_CLK_EXT>,
-               <&cgu JZ4740_CLK_PLL_HALF>;
-      clock-names = "aic", "i2s", "ext", "pll half";
+               <&cgu JZ4740_CLK_I2S>;
+      clock-names = "aic", "i2s";
 
       dmas = <&dmac 25 0xffffffff>, <&dmac 24 0xffffffff>;
       dma-names = "rx", "tx";
index 4fc5b04..9d31399 100644 (file)
@@ -21,6 +21,13 @@ properties:
     $ref: "/schemas/types.yaml#/definitions/phandle"
     description: The phandle of MT8186 ASoC platform.
 
+  dmic-gpios:
+    maxItems: 1
+    description:
+      dmic-gpios optional prop for switching between two DMICs.
+      Ex, the GPIO can control a MUX HW component to select
+      dmic clk and data form a Front or Rear dmic.
+
   headset-codec:
     type: object
     additionalProperties: false
@@ -63,14 +70,19 @@ required:
 
 examples:
   - |
+    #include <dt-bindings/gpio/gpio.h>
 
     sound: mt8186-sound {
         compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound";
         mediatek,platform = <&afe>;
         pinctrl-names = "aud_clk_mosi_off",
-                        "aud_clk_mosi_on";
+                        "aud_clk_mosi_on",
+                        "aud_gpio_dmic_sec";
         pinctrl-0 = <&aud_clk_mosi_off>;
         pinctrl-1 = <&aud_clk_mosi_on>;
+        pinctrl-2 = <&aud_gpio_dmic_sec>;
+
+        dmic-gpios = <&pio 23 GPIO_ACTIVE_HIGH>;
 
         headset-codec {
             sound-dai = <&rt5682s>;
index 478be7e..c6e614c 100644 (file)
@@ -34,7 +34,7 @@ properties:
 
     properties:
       sound-dai:
-        $ref: /schemas/types.yaml#/definitions/phandle
+        maxItems: 1
     required:
       - sound-dai
 
@@ -48,7 +48,6 @@ properties:
         maxItems: 2
         items:
           maxItems: 1
-        $ref: /schemas/types.yaml#/definitions/phandle-array
     required:
       - sound-dai
 
index cb8c07c..4f5dec5 100644 (file)
@@ -6,9 +6,14 @@ Required properties:
   "marvell,kirkwood-audio" for Kirkwood platforms
   "marvell,dove-audio" for Dove platforms
   "marvell,armada370-audio" for Armada 370 platforms
+  "marvell,armada-380-audio" for Armada 38x platforms
 
 - reg: physical base address of the controller and length of memory mapped
-  region.
+  region (named "i2s_regs").
+  With "marvell,armada-380-audio" two other regions are required:
+  first of those is dedicated for Audio PLL Configuration registers
+  (named "pll_regs") and the second one ("soc_ctrl") - for register
+  where one of exceptive I/O types (I2S or S/PDIF) is set.
 
 - interrupts:
   with "marvell,kirkwood-audio", the audio interrupt
@@ -23,6 +28,13 @@ Required properties:
        "internal" for the internal clock
        "extclk" for the external clock
 
+Optional properties:
+
+- spdif-mode:
+  Enable S/PDIF mode on Armada 38x SoC. Using this property
+  disables standard I2S I/O. Valid only with "marvell,armada-380-audio"
+  compatible string.
+
 Example:
 
 i2s1: audio-controller@b4000 {
index 6eaec46..1cd9451 100644 (file)
@@ -2,6 +2,7 @@ Nuvoton NAU8315 Mono Class-D Amplifier
 
 Required properties:
 - compatible   : "nuvoton,nau8315"
+                 "nuvoton,nau8318"
 
 Optional properties:
 - enable-gpios : GPIO specifier for the chip's device enable input(EN) pin.
@@ -16,3 +17,8 @@ nau8315 {
        compatible = "nuvoton,nau8315";
        enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
 };
+
+nau8318 {
+       compatible = "nuvoton,nau8318";
+       enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+};
index 1de11e7..1401667 100644 (file)
@@ -43,8 +43,7 @@ properties:
           - const: fsgen
 
   clock-output-names:
-    items:
-      - const: mclk
+    maxItems: 1
 
   power-domains:
     maxItems: 2
index de8297b..e647ba3 100644 (file)
@@ -43,8 +43,7 @@ properties:
           - const: fsgen
 
   clock-output-names:
-    items:
-      - const: mclk
+    maxItems: 1
 
   power-domains:
     maxItems: 2
index 9f473c0..c36caf9 100644 (file)
@@ -39,8 +39,7 @@ properties:
           - const: mclk
 
   clock-output-names:
-    items:
-      - const: fsgen
+    maxItems: 1
 
   power-domains:
     maxItems: 2
index 4959ad6..155c734 100644 (file)
@@ -38,8 +38,7 @@ properties:
       - const: fsgen
 
   clock-output-names:
-    items:
-      - const: mclk
+    maxItems: 1
 
   qcom,dmic-sample-rate:
     description: dmic sample rate
index 5d6ea66..1f75fee 100644 (file)
@@ -109,7 +109,7 @@ audio-codec@1{
        reg  = <1 0>;
        interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>;
        interrupt-names = "intr2"
-       reset-gpios = <&msmgpio 64 0>;
+       reset-gpios = <&msmgpio 64 GPIO_ACTIVE_LOW>;
        slim-ifc-dev  = <&wc9335_ifd>;
        clock-names = "mclk", "native";
        clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
index 6113f65..99f9c10 100644 (file)
@@ -23,7 +23,7 @@ properties:
     maxItems: 1
 
   powerdown-gpios:
-    description: GPIO spec for Powerdown/Shutdown line to use
+    description: GPIO spec for Powerdown/Shutdown line to use (pin SD_N)
     maxItems: 1
 
   vdd-supply:
@@ -47,6 +47,8 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/gpio/gpio.h>
+
     soundwire-controller@3250000 {
         #address-cells = <2>;
         #size-cells = <0>;
@@ -55,7 +57,7 @@ examples:
         speaker@0,1 {
             compatible = "sdw10217020200";
             reg = <0 1>;
-            powerdown-gpios = <&tlmm 1 0>;
+            powerdown-gpios = <&tlmm 1 GPIO_ACTIVE_LOW>;
             vdd-supply = <&vreg_s10b_1p8>;
             #thermal-sensor-cells = <0>;
             #sound-dai-cells = <0>;
@@ -64,7 +66,7 @@ examples:
         speaker@0,2 {
             compatible = "sdw10217020200";
             reg = <0 2>;
-            powerdown-gpios = <&tlmm 89 0>;
+            powerdown-gpios = <&tlmm 89 GPIO_ACTIVE_LOW>;
             vdd-supply = <&vreg_s10b_1p8>;
             #thermal-sensor-cells = <0>;
             #sound-dai-cells = <0>;
index ca5b898..dc41865 100644 (file)
@@ -87,11 +87,32 @@ properties:
     maxItems: 2
     description: Name given for DAI word clock and bit clock outputs.
 
+  "#sound-dai-cells":
+    const: 1
+
+  AVDD-supply:
+    description: Regulator supplying analog power through the AVDD pin.
+
+  MICVDD-supply:
+    description: Regulator supplying power for the microphone bias through the
+      MICVDD pin.
+
+  DBVDD-supply:
+    description: Regulator supplying I/O power through the DBVDD pin.
+
+  LDO1-IN-supply:
+    description: Regulator supplying power to the digital core and charge pump
+      through the LDO1_IN pin.
+
 additionalProperties: false
 
 required:
   - compatible
   - reg
+  - AVDD-supply
+  - MICVDD-supply
+  - DBVDD-supply
+  - LDO1-IN-supply
 
 examples:
   - |
@@ -117,5 +138,10 @@ examples:
 
             clocks = <&osc>;
             clock-names = "mclk";
+
+            AVDD-supply = <&avdd_reg>;
+            MICVDD-supply = <&micvdd_reg>;
+            DBVDD-supply = <&dbvdd_reg>;
+            LDO1-IN-supply = <&ldo1_in_reg>;
         };
     };
index c5f2b8f..5e1d08d 100644 (file)
@@ -8,6 +8,21 @@ Required properties:
 
 - reg : The I2C address of the device.
 
+- AVDD-supply: phandle to the regulator supplying analog power through the
+  AVDD pin
+
+- MICVDD-supply: phandle to the regulator supplying power for the microphone
+  bias through the MICVDD pin. Either MICVDD or VBAT should be present.
+
+- VBAT-supply: phandle to the regulator supplying battery power through the
+  VBAT pin. Either MICVDD or VBAT should be present.
+
+- DBVDD-supply: phandle to the regulator supplying I/O power through the DBVDD
+  pin.
+
+- LDO1-IN-supply: phandle to the regulator supplying power to the digital core
+  and charge pump through the LDO1_IN pin.
+
 Optional properties:
 
 - interrupts : The CODEC's interrupt output.
@@ -46,7 +61,7 @@ Optional properties:
 
 - realtek,dmic-clk-driving-high : Set the high driving of the DMIC clock out.
 
-- #sound-dai-cells: Should be set to '<0>'.
+- #sound-dai-cells: Should be set to '<1>'.
 
 Pins on the device (for linking into audio routes) for RT5682:
 
@@ -75,4 +90,9 @@ rt5682 {
 
        clocks = <&osc>;
        clock-names = "mclk";
+
+       AVDD-supply = <&avdd_reg>;
+       MICVDD-supply = <&micvdd_reg>;
+       DBVDD-supply = <&dbvdd_reg>;
+       LDO1-IN-supply = <&ldo1_in_reg>;
 };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8961.yaml
new file mode 100644 (file)
index 0000000..795d34e
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/wlf,wm8961.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wolfson WM8961 Ultra-Low Power Stereo CODEC
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+properties:
+  compatible:
+    const: wlf,wm8961
+
+  reg:
+    maxItems: 1
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          wm8961: codec@4a {
+                  compatible = "wlf,wm8961";
+                  reg = <0x4a>;
+                  #sound-dai-cells = <0>;
+          };
+    };
index 5e86145..8897364 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/mmc-omap.h>
 #include <linux/mfd/menelaus.h>
-#include <sound/tlv320aic3x.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -567,10 +566,6 @@ struct menelaus_platform_data n8x0_menelaus_platform_data = {
        .late_init = n8x0_menelaus_late_init,
 };
 
-struct aic3x_pdata n810_aic33_data = {
-       .gpio_reset = 118,
-};
-
 static int __init n8x0_late_initcall(void)
 {
        if (!board_caps)
index b23962c..69694af 100644 (file)
@@ -2,12 +2,10 @@
 #ifndef __OMAP_COMMON_BOARD_DEVICES__
 #define __OMAP_COMMON_BOARD_DEVICES__
 
-#include <sound/tlv320aic3x.h>
 #include <linux/mfd/menelaus.h>
 
 void *n8x0_legacy_init(void);
 
 extern struct menelaus_platform_data n8x0_menelaus_platform_data;
-extern struct aic3x_pdata n810_aic33_data;
 
 #endif /* __OMAP_COMMON_BOARD_DEVICES__ */
index 5b99d60..9deba79 100644 (file)
@@ -440,7 +440,6 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
 #ifdef CONFIG_MACH_NOKIA_N8X0
        OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
        OF_DEV_AUXDATA("menelaus", 0x72, "1-0072", &n8x0_menelaus_platform_data),
-       OF_DEV_AUXDATA("tlv320aic3x", 0x18, "2-0018", &n810_aic33_data),
 #endif
 #ifdef CONFIG_ARCH_OMAP3
        OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu",
index f9503cb..3ccbe14 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-config CS_DSP
+config FW_CS_DSP
        tristate
        default n
index f074e26..b91318c 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 #
-obj-$(CONFIG_CS_DSP)           += cs_dsp.o
+obj-$(CONFIG_FW_CS_DSP)                += cs_dsp.o
index 81cc3d0..f558b39 100644 (file)
@@ -369,7 +369,7 @@ const char *cs_dsp_mem_region_name(unsigned int type)
                return NULL;
        }
 }
-EXPORT_SYMBOL_GPL(cs_dsp_mem_region_name);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, FW_CS_DSP);
 
 #ifdef CONFIG_DEBUG_FS
 static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
@@ -480,7 +480,7 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
 
        dsp->debugfs_root = root;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
 
 /**
  * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs
@@ -492,17 +492,17 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
        debugfs_remove_recursive(dsp->debugfs_root);
        dsp->debugfs_root = NULL;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
 #else
 void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
 {
 }
-EXPORT_SYMBOL_GPL(cs_dsp_init_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP);
 
 void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp)
 {
 }
-EXPORT_SYMBOL_GPL(cs_dsp_cleanup_debugfs);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP);
 
 static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp,
                                                const char *s)
@@ -710,7 +710,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int
 
        return -ETIMEDOUT;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_acked_control);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_acked_control, FW_CS_DSP);
 
 static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
                                       unsigned int off, const void *buf, size_t len)
@@ -752,7 +752,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
  *
  * Must be called with pwr_lock held.
  *
- * Return: Zero for success, a negative number on error.
+ * Return: < 0 on error, 1 when the control value changed and 0 when it has not.
  */
 int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
                            unsigned int off, const void *buf, size_t len)
@@ -767,18 +767,25 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
        if (len + off * sizeof(u32) > ctl->len)
                return -EINVAL;
 
-       if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+       if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
                ret = -EPERM;
-       else if (buf != ctl->cache)
-               memcpy(ctl->cache + off * sizeof(u32), buf, len);
+       } else if (buf != ctl->cache) {
+               if (memcmp(ctl->cache + off * sizeof(u32), buf, len))
+                       memcpy(ctl->cache + off * sizeof(u32), buf, len);
+               else
+                       return 0;
+       }
 
        ctl->set = 1;
        if (ctl->enabled && ctl->dsp->running)
                ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
 
-       return ret;
+       if (ret < 0)
+               return ret;
+
+       return 1;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_write_ctrl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_ctrl, FW_CS_DSP);
 
 static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
                                      unsigned int off, void *buf, size_t len)
@@ -850,7 +857,7 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_coeff_read_ctrl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_read_ctrl, FW_CS_DSP);
 
 static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp)
 {
@@ -1493,7 +1500,7 @@ struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, in
 
        return rslt;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_get_ctl);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, FW_CS_DSP);
 
 static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp,
                                  const struct cs_dsp_alg_region *alg_region)
@@ -1583,7 +1590,7 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_find_alg_region);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, FW_CS_DSP);
 
 static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp,
                                                      int type, __be32 id,
@@ -2217,7 +2224,7 @@ int cs_dsp_adsp1_init(struct cs_dsp *dsp)
 
        return cs_dsp_common_init(dsp);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP);
 
 /**
  * cs_dsp_adsp1_power_up() - Load and start the named firmware
@@ -2309,7 +2316,7 @@ err_mutex:
        mutex_unlock(&dsp->pwr_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_up);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, FW_CS_DSP);
 
 /**
  * cs_dsp_adsp1_power_down() - Halts the DSP
@@ -2341,7 +2348,7 @@ void cs_dsp_adsp1_power_down(struct cs_dsp *dsp)
 
        mutex_unlock(&dsp->pwr_lock);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_adsp1_power_down);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, FW_CS_DSP);
 
 static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp)
 {
@@ -2493,7 +2500,7 @@ int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_set_dspclk);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, FW_CS_DSP);
 
 static void cs_dsp_stop_watchdog(struct cs_dsp *dsp)
 {
@@ -2583,7 +2590,7 @@ err_mutex:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_power_up);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, FW_CS_DSP);
 
 /**
  * cs_dsp_power_down() - Powers-down the DSP
@@ -2617,7 +2624,7 @@ void cs_dsp_power_down(struct cs_dsp *dsp)
 
        cs_dsp_dbg(dsp, "Shutdown complete\n");
 }
-EXPORT_SYMBOL_GPL(cs_dsp_power_down);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, FW_CS_DSP);
 
 static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp)
 {
@@ -2703,7 +2710,7 @@ err:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_run);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_run, FW_CS_DSP);
 
 /**
  * cs_dsp_stop() - Stops the firmware
@@ -2742,7 +2749,7 @@ void cs_dsp_stop(struct cs_dsp *dsp)
 
        cs_dsp_dbg(dsp, "Execution stopped\n");
 }
-EXPORT_SYMBOL_GPL(cs_dsp_stop);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, FW_CS_DSP);
 
 static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
 {
@@ -2804,7 +2811,7 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp)
 
        return cs_dsp_common_init(dsp);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_adsp2_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP);
 
 /**
  * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP
@@ -2818,7 +2825,7 @@ int cs_dsp_halo_init(struct cs_dsp *dsp)
 
        return cs_dsp_common_init(dsp);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_halo_init);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, FW_CS_DSP);
 
 /**
  * cs_dsp_remove() - Clean a cs_dsp before deletion
@@ -2838,7 +2845,7 @@ void cs_dsp_remove(struct cs_dsp *dsp)
                cs_dsp_free_ctl_blk(ctl);
        }
 }
-EXPORT_SYMBOL_GPL(cs_dsp_remove);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, FW_CS_DSP);
 
 /**
  * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory
@@ -2875,7 +2882,7 @@ int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int me
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_read_raw_data_block);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, FW_CS_DSP);
 
 /**
  * cs_dsp_read_data_word() - Reads a word from DSP memory
@@ -2899,7 +2906,7 @@ int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_add
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_read_data_word);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, FW_CS_DSP);
 
 /**
  * cs_dsp_write_data_word() - Writes a word to DSP memory
@@ -2925,7 +2932,7 @@ int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_ad
 
        return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
 }
-EXPORT_SYMBOL_GPL(cs_dsp_write_data_word);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, FW_CS_DSP);
 
 /**
  * cs_dsp_remove_padding() - Convert unpacked words to packed bytes
@@ -2949,7 +2956,7 @@ void cs_dsp_remove_padding(u32 *buf, int nwords)
                *pack_out++ = (u8)(word >> 16);
        }
 }
-EXPORT_SYMBOL_GPL(cs_dsp_remove_padding);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, FW_CS_DSP);
 
 /**
  * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt
@@ -3019,7 +3026,7 @@ void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp)
 error:
        mutex_unlock(&dsp->pwr_lock);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_adsp2_bus_error);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, FW_CS_DSP);
 
 /**
  * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt
@@ -3079,7 +3086,7 @@ void cs_dsp_halo_bus_error(struct cs_dsp *dsp)
 exit_unlock:
        mutex_unlock(&dsp->pwr_lock);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_halo_bus_error);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, FW_CS_DSP);
 
 /**
  * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry
@@ -3099,7 +3106,7 @@ void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp)
 
        mutex_unlock(&dsp->pwr_lock);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_halo_wdt_expire);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, FW_CS_DSP);
 
 static const struct cs_dsp_ops cs_dsp_adsp1_ops = {
        .validate_version = cs_dsp_validate_version,
@@ -3221,7 +3228,7 @@ int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_write);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, FW_CS_DSP);
 
 /**
  * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
@@ -3240,7 +3247,7 @@ int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
 
        return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
 }
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_flush);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, FW_CS_DSP);
 
 /**
  * cs_dsp_chunk_read() - Parse data from a DSP memory chunk
@@ -3282,7 +3289,7 @@ int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
 
        return result;
 }
-EXPORT_SYMBOL_GPL(cs_dsp_chunk_read);
+EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP);
 
 MODULE_DESCRIPTION("Cirrus Logic DSP Support");
 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
index b4edf10..9aa7b9d 100644 (file)
@@ -2236,6 +2236,20 @@ int i2c_get_device_id(const struct i2c_client *client,
 }
 EXPORT_SYMBOL_GPL(i2c_get_device_id);
 
+/**
+ * i2c_client_get_device_id - get the driver match table entry of a device
+ * @client: the device to query. The device must be bound to a driver
+ *
+ * Returns a pointer to the matching entry if found, NULL otherwise.
+ */
+const struct i2c_device_id *i2c_client_get_device_id(const struct i2c_client *client)
+{
+       const struct i2c_driver *drv = to_i2c_driver(client->dev.driver);
+
+       return i2c_match_id(drv->id_table, client);
+}
+EXPORT_SYMBOL_GPL(i2c_client_get_device_id);
+
 /* ----------------------------------------------------
  * the i2c address scanning function
  * Will not work for 10-bit addresses!
index d091513..d684292 100644 (file)
@@ -125,30 +125,6 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
        return 0;
 }
 
-#define HDA_DSP_REG_ADSPIC2             (0x10)
-#define HDA_DSP_REG_ADSPIS2             (0x14)
-#define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5)
-
-/**
- * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
- * @mmio_base: The mmio base of the control register
- * @enable: true if enable
- */
-void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
-{
-       u32 val;
-
-       val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
-
-       if (enable)
-               val |= HDA_DSP_REG_ADSPIC2_SNDW;
-       else
-               val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
-
-       writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
-}
-EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
-
 irqreturn_t sdw_intel_thread(int irq, void *dev_id)
 {
        struct sdw_intel_ctx *ctx = dev_id;
@@ -157,7 +133,6 @@ irqreturn_t sdw_intel_thread(int irq, void *dev_id)
        list_for_each_entry(link, &ctx->link_list, list)
                sdw_cdns_irq(irq, link->cdns);
 
-       sdw_intel_enable_irq(ctx->mmio_base, true);
        return IRQ_HANDLED;
 }
 EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
@@ -297,24 +272,12 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
 {
        struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle);
        struct sdw_intel_link_dev *ldev;
-       u32 caps;
        u32 link_mask;
        int i;
 
        if (!adev)
                return -EINVAL;
 
-       /* Check SNDWLCAP.LCOUNT */
-       caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP);
-       caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
-
-       /* Check HW supported vs property value */
-       if (caps < ctx->count) {
-               dev_err(&adev->dev,
-                       "BIOS master count is larger than hardware capabilities\n");
-               return -EINVAL;
-       }
-
        if (!ctx->ldev)
                return -EINVAL;
 
index f7c49bb..d84e0e9 100644 (file)
@@ -189,6 +189,7 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
                                              u8 *values);
 int i2c_get_device_id(const struct i2c_client *client,
                      struct i2c_device_identity *id);
+const struct i2c_device_id *i2c_client_get_device_id(const struct i2c_client *client);
 #endif /* I2C */
 
 /**
index 2e9fd91..d2f581f 100644 (file)
@@ -286,8 +286,6 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx);
 
 void sdw_intel_exit(struct sdw_intel_ctx *ctx);
 
-void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);
-
 irqreturn_t sdw_intel_thread(int irq, void *dev_id);
 
 #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE      BIT(1)
similarity index 65%
rename from include/sound/acp62_chip_offset_byte.h
rename to include/sound/acp63_chip_offset_byte.h
index f03992f..c9260e1 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * AMD ACP 6.2 Register Documentation
+ * AMD ACP 6.3 Register Documentation
  *
  * Copyright 2022 Advanced Micro Devices, Inc.
  */
 #define ACP_I2S_WAKE_EN                               0x000145C
 #define ACP_SW1_WAKE_EN                               0x0001460
 
+#define ACP_SW_I2S_ERROR_REASON                       0x00018B4
+#define ACP_SW_POS_TRACK_I2S_TX_CTRL                  0x00018B8
+#define ACP_SW_I2S_TX_DMA_POS                         0x00018BC
+#define ACP_SW_POS_TRACK_BT_TX_CTRL                   0x00018C0
+#define ACP_SW_BT_TX_DMA_POS                          0x00018C4
+#define ACP_SW_POS_TRACK_HS_TX_CTRL                   0x00018C8
+#define ACP_SW_HS_TX_DMA_POS                          0x00018CC
+#define ACP_SW_POS_TRACK_I2S_RX_CTRL                  0x00018D0
+#define ACP_SW_I2S_RX_DMA_POS                         0x00018D4
+#define ACP_SW_POS_TRACK_BT_RX_CTRL                   0x00018D8
+#define ACP_SW_BT_RX_DMA_POS                          0x00018DC
+#define ACP_SW_POS_TRACK_HS_RX_CTRL                   0x00018E0
+#define ACP_SW_HS_RX_DMA_POS                          0x00018E4
+#define ACP_ERROR_INTR_MASK1                          0X0001974
+#define ACP_ERROR_INTR_MASK2                          0X0001978
+#define ACP_ERROR_INTR_MASK3                          0X000197C
+
 /* Registers from ACP_P1_MISC block */
 #define ACP_EXTERNAL_INTR_ENB                         0x0001A00
 #define ACP_EXTERNAL_INTR_CNTL                        0x0001A04
 #define ACP_P1_SW_BT_RX_DMA_POS                       0x0001A9C
 #define ACP_P1_SW_POS_TRACK_HS_RX_CTRL                0x0001AA0
 #define ACP_P1_SW_HS_RX_DMA_POS                       0x0001AA4
+#define ACP_ERROR_INTR_MASK4                          0X0001AEC
+#define ACP_ERROR_INTR_MASK5                          0X0001AF0
 
 /* Registers from ACP_AUDIO_BUFFERS block */
 #define ACP_I2S_RX_RINGBUFADDR                        0x0002000
 #define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH             0x00020CC
 #define ACP_HS_TX_LINEARPOSITIONCNTR_LOW              0x00020D0
 #define ACP_HS_TX_INTR_WATERMARK_SIZE                 0x00020D4
+#define ACP_AUDIO_RX_RINGBUFADDR                   ACP_I2S_RX_RINGBUFADDR
+#define ACP_AUDIO_RX_RINGBUFSIZE                   ACP_I2S_RX_RINGBUFSIZE
+#define ACP_AUDIO_RX_LINKPOSITIONCNTR              ACP_I2S_RX_LINKPOSITIONCNTR
+#define ACP_AUDIO_RX_FIFOADDR                      ACP_I2S_RX_FIFOADDR
+#define ACP_AUDIO_RX_FIFOSIZE                      ACP_I2S_RX_FIFOSIZE
+#define ACP_AUDIO_RX_DMA_SIZE                      ACP_I2S_RX_DMA_SIZE
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_HIGH       ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_RX_LINEARPOSITIONCNTR_LOW        ACP_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_RX_INTR_WATERMARK_SIZE           ACP_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_AUDIO_TX_RINGBUFADDR                   ACP_I2S_TX_RINGBUFADDR
+#define ACP_AUDIO_TX_RINGBUFSIZE                   ACP_I2S_TX_RINGBUFSIZE
+#define ACP_AUDIO_TX_LINKPOSITIONCNTR              ACP_I2S_TX_LINKPOSITIONCNTR
+#define ACP_AUDIO_TX_FIFOADDR                      ACP_I2S_TX_FIFOADDR
+#define ACP_AUDIO_TX_FIFOSIZE                      ACP_I2S_TX_FIFOSIZE
+#define ACP_AUDIO_TX_DMA_SIZE                      ACP_I2S_TX_DMA_SIZE
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_HIGH       ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_AUDIO_TX_LINEARPOSITIONCNTR_LOW        ACP_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_AUDIO_TX_INTR_WATERMARK_SIZE           ACP_I2S_TX_INTR_WATERMARK_SIZE
 
 /* Registers from ACP_I2S_TDM block */
 #define ACP_I2STDM_IER                                0x0002400
 #define ACP_WOV_ERROR_STATUS_REGISTER                 0x0002C68
 #define ACP_PDM_CLKDIV                                0x0002C6C
 
+/* Registers from ACP_SW_SWCLK block */
+#define ACP_SW_EN                                     0x0003000
+#define ACP_SW_EN_STATUS                              0x0003004
+#define ACP_SW_FRAMESIZE                              0x0003008
+#define ACP_SW_SSP_COUNTER                            0x000300C
+#define ACP_SW_AUDIO_TX_EN                            0x0003010
+#define ACP_SW_AUDIO_TX_EN_STATUS                     0x0003014
+#define ACP_SW_AUDIO_TX_FRAME_FORMAT                  0x0003018
+#define ACP_SW_AUDIO_TX_SAMPLEINTERVAL                0x000301C
+#define ACP_SW_AUDIO_TX_HCTRL_DP0                     0x0003020
+#define ACP_SW_AUDIO_TX_HCTRL_DP1                     0x0003024
+#define ACP_SW_AUDIO_TX_HCTRL_DP2                     0x0003028
+#define ACP_SW_AUDIO_TX_HCTRL_DP3                     0x000302C
+#define ACP_SW_AUDIO_TX_OFFSET_DP0                    0x0003030
+#define ACP_SW_AUDIO_TX_OFFSET_DP1                    0x0003034
+#define ACP_SW_AUDIO_TX_OFFSET_DP2                    0x0003038
+#define ACP_SW_AUDIO_TX_OFFSET_DP3                    0x000303C
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP0            0x0003040
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP1            0x0003044
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP2            0x0003048
+#define ACP_SW_AUDIO_TX_CHANNEL_ENABLE_DP3            0x000304C
+#define ACP_SW_BT_TX_EN                               0x0003050
+#define ACP_SW_BT_TX_EN_STATUS                        0x0003054
+#define ACP_SW_BT_TX_FRAME_FORMAT                     0x0003058
+#define ACP_SW_BT_TX_SAMPLEINTERVAL                   0x000305C
+#define ACP_SW_BT_TX_HCTRL                            0x0003060
+#define ACP_SW_BT_TX_OFFSET                           0x0003064
+#define ACP_SW_BT_TX_CHANNEL_ENABLE_DP0               0x0003068
+#define ACP_SW_HEADSET_TX_EN                          0x000306C
+#define ACP_SW_HEADSET_TX_EN_STATUS                   0x0003070
+#define ACP_SW_HEADSET_TX_FRAME_FORMAT                0x0003074
+#define ACP_SW_HEADSET_TX_SAMPLEINTERVAL              0x0003078
+#define ACP_SW_HEADSET_TX_HCTRL                       0x000307C
+#define ACP_SW_HEADSET_TX_OFFSET                      0x0003080
+#define ACP_SW_HEADSET_TX_CHANNEL_ENABLE_DP0          0x0003084
+#define ACP_SW_AUDIO_RX_EN                            0x0003088
+#define ACP_SW_AUDIO_RX_EN_STATUS                     0x000308C
+#define ACP_SW_AUDIO_RX_FRAME_FORMAT                  0x0003090
+#define ACP_SW_AUDIO_RX_SAMPLEINTERVAL                0x0003094
+#define ACP_SW_AUDIO_RX_HCTRL_DP0                     0x0003098
+#define ACP_SW_AUDIO_RX_HCTRL_DP1                     0x000309C
+#define ACP_SW_AUDIO_RX_HCTRL_DP2                     0x0003100
+#define ACP_SW_AUDIO_RX_HCTRL_DP3                     0x0003104
+#define ACP_SW_AUDIO_RX_OFFSET_DP0                    0x0003108
+#define ACP_SW_AUDIO_RX_OFFSET_DP1                    0x000310C
+#define ACP_SW_AUDIO_RX_OFFSET_DP2                    0x0003110
+#define ACP_SW_AUDIO_RX_OFFSET_DP3                    0x0003114
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP0            0x0003118
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP1            0x000311C
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP2            0x0003120
+#define ACP_SW_AUDIO_RX_CHANNEL_ENABLE_DP3            0x0003124
+#define ACP_SW_BT_RX_EN                               0x0003128
+#define ACP_SW_BT_RX_EN_STATUS                        0x000312C
+#define ACP_SW_BT_RX_FRAME_FORMAT                     0x0003130
+#define ACP_SW_BT_RX_SAMPLEINTERVAL                   0x0003134
+#define ACP_SW_BT_RX_HCTRL                            0x0003138
+#define ACP_SW_BT_RX_OFFSET                           0x000313C
+#define ACP_SW_BT_RX_CHANNEL_ENABLE_DP0               0x0003140
+#define ACP_SW_HEADSET_RX_EN                          0x0003144
+#define ACP_SW_HEADSET_RX_EN_STATUS                   0x0003148
+#define ACP_SW_HEADSET_RX_FRAME_FORMAT                0x000314C
+#define ACP_SW_HEADSET_RX_SAMPLEINTERVAL              0x0003150
+#define ACP_SW_HEADSET_RX_HCTRL                       0x0003154
+#define ACP_SW_HEADSET_RX_OFFSET                      0x0003158
+#define ACP_SW_HEADSET_RX_CHANNEL_ENABLE_DP0          0x000315C
+#define ACP_SW_BPT_PORT_EN                            0x0003160
+#define ACP_SW_BPT_PORT_EN_STATUS                     0x0003164
+#define ACP_SW_BPT_PORT_FRAME_FORMAT                  0x0003168
+#define ACP_SW_BPT_PORT_SAMPLEINTERVAL                0x000316C
+#define ACP_SW_BPT_PORT_HCTRL                         0x0003170
+#define ACP_SW_BPT_PORT_OFFSET                        0x0003174
+#define ACP_SW_BPT_PORT_CHANNEL_ENABLE                0x0003178
+#define ACP_SW_BPT_PORT_FIRST_BYTE_ADDR               0x000317C
+#define ACP_SW_CLK_RESUME_CTRL                        0x0003180
+#define ACP_SW_CLK_RESUME_DELAY_CNTR                  0x0003184
+#define ACP_SW_BUS_RESET_CTRL                         0x0003188
+#define ACP_SW_PRBS_ERR_STATUS                        0x000318C
+#define SW_IMM_CMD_UPPER_WORD                         0x0003230
+#define SW_IMM_CMD_LOWER_QWORD                        0x0003234
+#define SW_IMM_RESP_UPPER_WORD                        0x0003238
+#define SW_IMM_RESP_LOWER_QWORD                       0x000323C
+#define SW_IMM_CMD_STS                                0x0003240
+#define SW_BRA_BASE_ADDRESS                           0x0003244
+#define SW_BRA_TRANSFER_SIZE                          0x0003248
+#define SW_BRA_DMA_BUSY                               0x000324C
+#define SW_BRA_RESP                                   0x0003250
+#define SW_BRA_RESP_FRAME_ADDR                        0x0003254
+#define SW_BRA_CURRENT_TRANSFER_SIZE                  0x0003258
+#define SW_STATE_CHANGE_STATUS_0TO7                   0x000325C
+#define SW_STATE_CHANGE_STATUS_8TO11                  0x0003260
+#define SW_STATE_CHANGE_STATUS_MASK_0TO7              0x0003264
+#define SW_STATE_CHANGE_STATUS_MASK_8TO11             0x0003268
+#define SW_CLK_FREQUENCY_CTRL                         0x000326C
+#define SW_ERROR_INTR_MASK                            0x0003270
+#define SW_PHY_TEST_MODE_DATA_OFF                     0x0003274
+
 /* Registers from ACP_P1_AUDIO_BUFFERS block */
 #define ACP_P1_I2S_RX_RINGBUFADDR                     0x0003A00
 #define ACP_P1_I2S_RX_RINGBUFSIZE                     0x0003A04
 #define ACP_P1_HS_TX_LINEARPOSITIONCNTR_HIGH          0x0003ACC
 #define ACP_P1_HS_TX_LINEARPOSITIONCNTR_LOW           0x0003AD0
 #define ACP_P1_HS_TX_INTR_WATERMARK_SIZE              0x0003AD4
+#define ACP_P1_AUDIO_RX_RINGBUFADDR                   ACP_P1_I2S_RX_RINGBUFADDR
+#define ACP_P1_AUDIO_RX_RINGBUFSIZE                   ACP_P1_I2S_RX_RINGBUFSIZE
+#define ACP_P1_AUDIO_RX_LINKPOSITIONCNTR              ACP_P1_I2S_RX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_RX_FIFOADDR                      ACP_P1_I2S_RX_FIFOADDR
+#define ACP_P1_AUDIO_RX_FIFOSIZE                      ACP_P1_I2S_RX_FIFOSIZE
+#define ACP_P1_AUDIO_RX_DMA_SIZE                      ACP_P1_I2S_RX_DMA_SIZE
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_HIGH       ACP_P1_I2S_RX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_RX_LINEARPOSITIONCNTR_LOW        ACP_P1_I2S_RX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_RX_INTR_WATERMARK_SIZE           ACP_P1_I2S_RX_INTR_WATERMARK_SIZE
+#define ACP_P1_AUDIO_TX_RINGBUFADDR                   ACP_P1_I2S_TX_RINGBUFADDR
+#define ACP_P1_AUDIO_TX_RINGBUFSIZE                   ACP_P1_I2S_TX_RINGBUFSIZE
+#define ACP_P1_AUDIO_TX_LINKPOSITIONCNTR              ACP_P1_I2S_TX_LINKPOSITIONCNTR
+#define ACP_P1_AUDIO_TX_FIFOADDR                      ACP_P1_I2S_TX_FIFOADDR
+#define ACP_P1_AUDIO_TX_FIFOSIZE                      ACP_P1_I2S_TX_FIFOSIZE
+#define ACP_P1_AUDIO_TX_DMA_SIZE                      ACP_P1_I2S_TX_DMA_SIZE
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_HIGH       ACP_P1_I2S_TX_LINEARPOSITIONCNTR_HIGH
+#define ACP_P1_AUDIO_TX_LINEARPOSITIONCNTR_LOW        ACP_P1_I2S_TX_LINEARPOSITIONCNTR_LOW
+#define ACP_P1_AUDIO_TX_INTR_WATERMARK_SIZE           ACP_P1_I2S_TX_INTR_WATERMARK_SIZE
+
+/* Registers from ACP_P1_SW_SWCLK block */
+#define ACP_P1_SW_EN                                  0x0003C00
+#define ACP_P1_SW_EN_STATUS                           0x0003C04
+#define ACP_P1_SW_FRAMESIZE                           0x0003C08
+#define ACP_P1_SW_SSP_COUNTER                         0x0003C0C
+#define ACP_P1_SW_BT_TX_EN                            0x0003C50
+#define ACP_P1_SW_BT_TX_EN_STATUS                     0x0003C54
+#define ACP_P1_SW_BT_TX_FRAME_FORMAT                  0x0003C58
+#define ACP_P1_SW_BT_TX_SAMPLEINTERVAL                0x0003C5C
+#define ACP_P1_SW_BT_TX_HCTRL                         0x0003C60
+#define ACP_P1_SW_BT_TX_OFFSET                        0x0003C64
+#define ACP_P1_SW_BT_TX_CHANNEL_ENABLE_DP0            0x0003C68
+#define ACP_P1_SW_BT_RX_EN                            0x0003D28
+#define ACP_P1_SW_BT_RX_EN_STATUS                     0x0003D2C
+#define ACP_P1_SW_BT_RX_FRAME_FORMAT                  0x0003D30
+#define ACP_P1_SW_BT_RX_SAMPLEINTERVAL                0x0003D34
+#define ACP_P1_SW_BT_RX_HCTRL                         0x0003D38
+#define ACP_P1_SW_BT_RX_OFFSET                        0x0003D3C
+#define ACP_P1_SW_BT_RX_CHANNEL_ENABLE_DP0            0x0003D40
+#define ACP_P1_SW_BPT_PORT_EN                         0x0003D60
+#define ACP_P1_SW_BPT_PORT_EN_STATUS                  0x0003D64
+#define ACP_P1_SW_BPT_PORT_FRAME_FORMAT               0x0003D68
+#define ACP_P1_SW_BPT_PORT_SAMPLEINTERVAL             0x0003D6C
+#define ACP_P1_SW_BPT_PORT_HCTRL                      0x0003D70
+#define ACP_P1_SW_BPT_PORT_OFFSET                     0x0003D74
+#define ACP_P1_SW_BPT_PORT_CHANNEL_ENABLE             0x0003D78
+#define ACP_P1_SW_BPT_PORT_FIRST_BYTE_ADDR            0x0003D7C
+#define ACP_P1_SW_CLK_RESUME_CTRL                     0x0003D80
+#define ACP_P1_SW_CLK_RESUME_DELAY_CNTR               0x0003D84
+#define ACP_P1_SW_BUS_RESET_CTRL                      0x0003D88
+#define ACP_P1_SW_PRBS_ERR_STATUS                     0x0003D8C
+
+/* Registers from ACP_P1_SW_ACLK block */
+#define P1_SW_CORB_BASE_ADDRESS                       0x0003E00
+#define P1_SW_CORB_WRITE_POINTER                      0x0003E04
+#define P1_SW_CORB_READ_POINTER                       0x0003E08
+#define P1_SW_CORB_CONTROL                            0x0003E0C
+#define P1_SW_CORB_SIZE                               0x0003E14
+#define P1_SW_RIRB_BASE_ADDRESS                       0x0003E18
+#define P1_SW_RIRB_WRITE_POINTER                      0x0003E1C
+#define P1_SW_RIRB_RESPONSE_INTERRUPT_COUNT           0x0003E20
+#define P1_SW_RIRB_CONTROL                            0x0003E24
+#define P1_SW_RIRB_SIZE                               0x0003E28
+#define P1_SW_RIRB_FIFO_MIN_THDL                      0x0003E2C
+#define P1_SW_IMM_CMD_UPPER_WORD                      0x0003E30
+#define P1_SW_IMM_CMD_LOWER_QWORD                     0x0003E34
+#define P1_SW_IMM_RESP_UPPER_WORD                     0x0003E38
+#define P1_SW_IMM_RESP_LOWER_QWORD                    0x0003E3C
+#define P1_SW_IMM_CMD_STS                             0x0003E40
+#define P1_SW_BRA_BASE_ADDRESS                        0x0003E44
+#define P1_SW_BRA_TRANSFER_SIZE                       0x0003E48
+#define P1_SW_BRA_DMA_BUSY                            0x0003E4C
+#define P1_SW_BRA_RESP                                0x0003E50
+#define P1_SW_BRA_RESP_FRAME_ADDR                     0x0003E54
+#define P1_SW_BRA_CURRENT_TRANSFER_SIZE               0x0003E58
+#define P1_SW_STATE_CHANGE_STATUS_0TO7                0x0003E5C
+#define P1_SW_STATE_CHANGE_STATUS_8TO11               0x0003E60
+#define P1_SW_STATE_CHANGE_STATUS_MASK_0TO7           0x0003E64
+#define P1_SW_STATE_CHANGE_STATUS_MASK_8TO11          0x0003E68
+#define P1_SW_CLK_FREQUENCY_CTRL                      0x0003E6C
+#define P1_SW_ERROR_INTR_MASK                         0x0003E70
+#define P1_SW_PHY_TEST_MODE_DATA_OFF                  0x0003E74
 
 /* Registers from ACP_SCRATCH block */
 #define ACP_SCRATCH_REG_0                             0x0010000
index 35778f9..a687253 100644 (file)
@@ -495,6 +495,13 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr)
        snd_hdac_chip_writeb(chip, reg, \
                             (snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val))
 
+/* update register macro */
+#define snd_hdac_updatel(addr, reg, mask, val)         \
+       writel(((readl(addr + reg) & ~(mask)) | (val)), addr + reg)
+
+#define snd_hdac_updatew(addr, reg, mask, val)         \
+       writew(((readw(addr + reg) & ~(mask)) | (val)), addr + reg)
+
 /*
  * HD-audio stream
  */
@@ -511,6 +518,13 @@ struct hdac_stream {
 
        void __iomem *sd_addr;  /* stream descriptor pointer */
 
+       void __iomem *spib_addr; /* software position in buffers stream pointer */
+       void __iomem *fifo_addr; /* software position Max fifos stream pointer */
+
+       void __iomem *dpibr_addr; /* DMA position in buffer resume pointer */
+       u32 dpib;               /* DMA position in buffer */
+       u32 lpib;               /* Linear position in buffer */
+
        u32 sd_int_sta_mask;    /* stream int status mask */
 
        /* pcm support */
@@ -575,6 +589,19 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
 int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
                                struct snd_pcm_substream *substream);
 
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *chip,
+                                  bool enable, int index);
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+                            struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+                                  struct hdac_stream *azx_dev);
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+                                bool enable, int index);
+int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev);
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+                             struct hdac_stream *azx_dev, u32 value);
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value);
+
 /*
  * macros for easy use
  */
index 83aed26..68ab892 100644 (file)
@@ -23,13 +23,10 @@ void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus);
 void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable);
 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable);
 
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
-                                bool enable, int index);
-
 int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus);
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr);
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
-                                               const char *codec_name);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+                                                        const char *codec_name);
 
 enum hdac_ext_stream_type {
        HDAC_EXT_STREAM_TYPE_COUPLED = 0,
@@ -43,11 +40,6 @@ enum hdac_ext_stream_type {
  * @hstream: hdac_stream
  * @pphc_addr: processing pipe host stream pointer
  * @pplc_addr: processing pipe link stream pointer
- * @spib_addr: software position in buffers stream pointer
- * @fifo_addr: software position Max fifos stream pointer
- * @dpibr_addr: DMA position in buffer resume pointer
- * @dpib: DMA position in buffer
- * @lpib: Linear position in buffer
  * @decoupled: stream host and link is decoupled
  * @link_locked: link is locked
  * @link_prepared: link is prepared
@@ -59,13 +51,11 @@ struct hdac_ext_stream {
        void __iomem *pphc_addr;
        void __iomem *pplc_addr;
 
-       void __iomem *spib_addr;
-       void __iomem *fifo_addr;
-
-       void __iomem *dpibr_addr;
+       u32 pphcllpl;
+       u32 pphcllpu;
+       u32 pphcldpl;
+       u32 pphcldpu;
 
-       u32 dpib;
-       u32 lpib;
        bool decoupled:1;
        bool link_locked:1;
        bool link_prepared;
@@ -80,7 +70,7 @@ struct hdac_ext_stream {
 int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
                                 int num_stream, int dir);
 void snd_hdac_ext_stream_free_all(struct hdac_bus *bus);
-void snd_hdac_link_free_all(struct hdac_bus *bus);
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus);
 struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
                                           struct snd_pcm_substream *substream,
                                           int type);
@@ -90,20 +80,10 @@ void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
 void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
                                struct hdac_ext_stream *azx_dev, bool decouple);
 
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
-                                struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
-                                      struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
-                               bool enable, int index);
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
-                               struct hdac_ext_stream *hext_stream, u32 value);
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value);
-
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream);
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream);
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream);
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream);
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
 
 struct hdac_ext_link {
        struct hdac_bus *bus;
@@ -117,29 +97,20 @@ struct hdac_ext_link {
        struct list_head list;
 };
 
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink);
 int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus);
 int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus);
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
-                                int stream);
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
-                                int stream);
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *hlink,
+                                        int stream);
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *hlink,
+                                          int stream);
 
-int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
-int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *hlink);
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink);
 
 void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
 
-/* update register macro */
-#define snd_hdac_updatel(addr, reg, mask, val)         \
-       writel(((readl(addr + reg) & ~(mask)) | (val)), \
-               addr + reg)
-
-#define snd_hdac_updatew(addr, reg, mask, val)         \
-       writew(((readw(addr + reg) & ~(mask)) | (val)), \
-               addr + reg)
-
 #define snd_hdac_adsp_writeb(chip, reg, value) \
        snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value)
 #define snd_hdac_adsp_readb(chip, reg) \
index 25e049f..38590f1 100644 (file)
@@ -173,8 +173,6 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
 
 void asoc_simple_clean_reference(struct snd_soc_card *card);
 
-void asoc_simple_convert_fixup(struct asoc_simple_data *data,
-                                     struct snd_pcm_hw_params *params);
 void asoc_simple_parse_convert(struct device_node *np, char *prefix,
                               struct asoc_simple_data *data);
 bool asoc_simple_is_convert_required(const struct asoc_simple_data *data);
index ebb8e7a..77495e5 100644 (file)
@@ -341,31 +341,27 @@ struct soc_enum;
 #define SND_SOC_DAPM_STREAM_STOP               0x2
 #define SND_SOC_DAPM_STREAM_SUSPEND            0x4
 #define SND_SOC_DAPM_STREAM_RESUME             0x8
-#define SND_SOC_DAPM_STREAM_PAUSE_PUSH 0x10
+#define SND_SOC_DAPM_STREAM_PAUSE_PUSH         0x10
 #define SND_SOC_DAPM_STREAM_PAUSE_RELEASE      0x20
 
 /* dapm event types */
-#define SND_SOC_DAPM_PRE_PMU   0x1     /* before widget power up */
-#define SND_SOC_DAPM_POST_PMU  0x2             /* after widget power up */
-#define SND_SOC_DAPM_PRE_PMD   0x4     /* before widget power down */
-#define SND_SOC_DAPM_POST_PMD  0x8             /* after widget power down */
-#define SND_SOC_DAPM_PRE_REG   0x10    /* before audio path setup */
-#define SND_SOC_DAPM_POST_REG  0x20    /* after audio path setup */
-#define SND_SOC_DAPM_WILL_PMU   0x40    /* called at start of sequence */
-#define SND_SOC_DAPM_WILL_PMD   0x80    /* called at start of sequence */
-#define SND_SOC_DAPM_PRE_POST_PMD \
-                               (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
-#define SND_SOC_DAPM_PRE_POST_PMU \
-                               (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
+#define SND_SOC_DAPM_PRE_PMU           0x1     /* before widget power up */
+#define SND_SOC_DAPM_POST_PMU          0x2     /* after  widget power up */
+#define SND_SOC_DAPM_PRE_PMD           0x4     /* before widget power down */
+#define SND_SOC_DAPM_POST_PMD          0x8     /* after  widget power down */
+#define SND_SOC_DAPM_PRE_REG           0x10    /* before audio path setup */
+#define SND_SOC_DAPM_POST_REG          0x20    /* after  audio path setup */
+#define SND_SOC_DAPM_WILL_PMU          0x40    /* called at start of sequence */
+#define SND_SOC_DAPM_WILL_PMD          0x80    /* called at start of sequence */
+#define SND_SOC_DAPM_PRE_POST_PMD      (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
+#define SND_SOC_DAPM_PRE_POST_PMU      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU)
 
 /* convenience event type detection */
-#define SND_SOC_DAPM_EVENT_ON(e)       \
-       (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
-#define SND_SOC_DAPM_EVENT_OFF(e)      \
-       (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
+#define SND_SOC_DAPM_EVENT_ON(e)       (e & (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU))
+#define SND_SOC_DAPM_EVENT_OFF(e)      (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
 
 /* regulator widget flags */
-#define SND_SOC_DAPM_REGULATOR_BYPASS     0x1     /* bypass when disabled */
+#define SND_SOC_DAPM_REGULATOR_BYPASS  0x1     /* bypass when disabled */
 
 struct snd_soc_dapm_widget;
 enum snd_soc_dapm_type;
@@ -396,18 +392,13 @@ enum snd_soc_bias_level {
        SND_SOC_BIAS_ON = 3,
 };
 
-int dapm_regulator_event(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol, int event);
-int dapm_clock_event(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol, int event);
-int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol, int event);
+int dapm_regulator_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_clock_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
+int dapm_pinctrl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event);
 
 /* dapm controls */
-int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
@@ -419,30 +410,24 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *uncontrol);
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
-       const struct snd_soc_dapm_widget *widget,
-       int num);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
-               struct snd_soc_dapm_context *dapm,
+       const struct snd_soc_dapm_widget *widget, int num);
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                const struct snd_soc_dapm_widget *widget);
-struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(
-               struct snd_soc_dapm_context *dapm,
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                const struct snd_soc_dapm_widget *widget);
-int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
-                                struct snd_soc_dai *dai);
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai);
 void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
 
 int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *dai);
+                           struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
 void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
-                      struct snd_soc_card *card,
-                      struct snd_soc_component *component);
+                      struct snd_soc_card *card, struct snd_soc_component *component);
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num);
 int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
@@ -450,49 +435,36 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
                             const struct snd_soc_dapm_route *route, int num);
 void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
-void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm);
 
 /* dapm events */
-void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
-       int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event);
 void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream);
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
 int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
-               struct snd_kcontrol *kcontrol, int connect,
-               struct snd_soc_dapm_update *update);
+               struct snd_kcontrol *kcontrol, int connect, struct snd_soc_dapm_update *update);
 int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
                struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
                struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
 extern struct attribute *soc_dapm_dev_attrs[];
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
-                               struct dentry *parent);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent);
 
 /* dapm audio pin control and status */
-int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
-                           const char *pin);
-int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
-                                    const char *pin);
-int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
-                            const char *pin);
-int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
-                                     const char *pin);
+int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
 int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
-int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
-                                const char *pin);
-int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
-                               const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
-                                 const char *pin);
-int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
-                                          const char *pin);
-int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
-                               const char *pin);
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin);
 unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 /* Mostly internal - should not normally be used */
@@ -501,40 +473,35 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
 /* dapm path query */
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        struct snd_soc_dapm_widget_list **list,
-       bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
-                                     enum snd_soc_dapm_direction));
+       bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, enum snd_soc_dapm_direction));
 void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list);
 
-struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
-       struct snd_kcontrol *kcontrol);
-
-struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
-               struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol *kcontrol);
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(struct snd_kcontrol *kcontrol);
 
-int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
-       enum snd_soc_bias_level level);
+int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level);
 
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
-       snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
-       snd_soc_dapm_demux,                     /* connects the input to one of multiple outputs */
-       snd_soc_dapm_mixer,                     /* mixes several analog signals together */
-       snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
-       snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
-       snd_soc_dapm_out_drv,                   /* output driver */
-       snd_soc_dapm_adc,                       /* analog to digital converter */
-       snd_soc_dapm_dac,                       /* digital to analog converter */
+       snd_soc_dapm_mux,               /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_demux,             /* connects the input to one of multiple outputs */
+       snd_soc_dapm_mixer,             /* mixes several analog signals together */
+       snd_soc_dapm_mixer_named_ctl,   /* mixer with named controls */
+       snd_soc_dapm_pga,               /* programmable gain/attenuation (volume) */
+       snd_soc_dapm_out_drv,           /* output driver */
+       snd_soc_dapm_adc,               /* analog to digital converter */
+       snd_soc_dapm_dac,               /* digital to analog converter */
        snd_soc_dapm_micbias,           /* microphone bias (power) - DEPRECATED: use snd_soc_dapm_supply */
-       snd_soc_dapm_mic,                       /* microphone */
-       snd_soc_dapm_hp,                        /* headphones */
-       snd_soc_dapm_spk,                       /* speaker */
-       snd_soc_dapm_line,                      /* line input/output */
+       snd_soc_dapm_mic,               /* microphone */
+       snd_soc_dapm_hp,                /* headphones */
+       snd_soc_dapm_spk,               /* speaker */
+       snd_soc_dapm_line,              /* line input/output */
        snd_soc_dapm_switch,            /* analog switch */
-       snd_soc_dapm_vmid,                      /* codec bias/vmid - to minimise pops */
-       snd_soc_dapm_pre,                       /* machine specific pre widget - exec first */
-       snd_soc_dapm_post,                      /* machine specific post widget - exec last */
+       snd_soc_dapm_vmid,              /* codec bias/vmid - to minimise pops */
+       snd_soc_dapm_pre,               /* machine specific pre widget - exec first */
+       snd_soc_dapm_post,              /* machine specific post widget - exec last */
        snd_soc_dapm_supply,            /* power/clock supply */
        snd_soc_dapm_pinctrl,           /* pinctrl */
        snd_soc_dapm_regulator_supply,  /* external regulator */
@@ -600,9 +567,9 @@ struct snd_soc_dapm_path {
        };
 
        /* status */
-       u32 connect:1;  /* source and sink widgets are connected */
-       u32 walking:1;  /* path is in the process of being walked */
-       u32 weak:1;     /* path ignored for power management */
+       u32 connect:1;          /* source and sink widgets are connected */
+       u32 walking:1;          /* path is in the process of being walked */
+       u32 weak:1;             /* path ignored for power management */
        u32 is_supply:1;        /* At least one of the connected widgets is a supply */
 
        int (*connected)(struct snd_soc_dapm_widget *source,
@@ -616,8 +583,8 @@ struct snd_soc_dapm_path {
 /* dapm widget */
 struct snd_soc_dapm_widget {
        enum snd_soc_dapm_type id;
-       const char *name;               /* widget name */
-       const char *sname;      /* stream name */
+       const char *name;                       /* widget name */
+       const char *sname;                      /* stream name */
        struct list_head list;
        struct snd_soc_dapm_context *dapm;
 
@@ -636,7 +603,7 @@ struct snd_soc_dapm_widget {
        unsigned char connected:1;              /* connected codec pin */
        unsigned char new:1;                    /* cnew complete */
        unsigned char force:1;                  /* force state */
-       unsigned char ignore_suspend:1;         /* kept enabled over suspend */
+       unsigned char ignore_suspend:1;         /* kept enabled over suspend */
        unsigned char new_power:1;              /* power from this run */
        unsigned char power_checked:1;          /* power checked this run */
        unsigned char is_supply:1;              /* Widget is a supply type widget */
@@ -680,27 +647,24 @@ struct snd_soc_dapm_update {
        bool has_second_set;
 };
 
-struct snd_soc_dapm_wcache {
-       struct snd_soc_dapm_widget *widget;
-};
-
 /* DAPM context */
 struct snd_soc_dapm_context {
        enum snd_soc_bias_level bias_level;
-       unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-       /* Go to BIAS_OFF in suspend if the DAPM context is idle */
-       unsigned int suspend_bias_off:1;
 
-       struct device *dev; /* from parent - for debug */
-       struct snd_soc_component *component; /* parent component */
-       struct snd_soc_card *card; /* parent card */
+       /* bit field */
+       unsigned int idle_bias_off:1;           /* Use BIAS_OFF instead of STANDBY */
+       unsigned int suspend_bias_off:1;        /* Use BIAS_OFF in suspend if the DAPM is idle */
+
+       struct device *dev;                     /* from parent - for debug */
+       struct snd_soc_component *component;    /* parent component */
+       struct snd_soc_card *card;              /* parent card */
 
        /* used during DAPM updates */
        enum snd_soc_bias_level target_bias_level;
        struct list_head list;
 
-       struct snd_soc_dapm_wcache path_sink_cache;
-       struct snd_soc_dapm_wcache path_source_cache;
+       struct snd_soc_dapm_widget *wcache_sink;
+       struct snd_soc_dapm_widget *wcache_source;
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_dapm;
@@ -767,11 +731,11 @@ enum snd_soc_dapm_direction {
 
 #define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x)
 
-#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
-#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
+#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
+#define SND_SOC_DAPM_EP_SINK   SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
 
 /**
- * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path - Iterates over all paths in the
  *   specified direction of a widget
  * @w: The widget
  * @dir: Whether to iterate over the paths where the specified widget is the
@@ -782,7 +746,7 @@ enum snd_soc_dapm_direction {
        list_for_each_entry(p, &w->edges[dir], list_node[dir])
 
 /**
- * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the
+ * snd_soc_dapm_widget_for_each_path_safe - Iterates over all paths in the
  *   specified direction of a widget
  * @w: The widget
  * @dir: Whether to iterate over the paths where the specified widget is the
@@ -790,7 +754,7 @@ enum snd_soc_dapm_direction {
  * @p: The path iterator variable
  * @next_p: Temporary storage for the next path
  *
- *  This function works like snd_soc_dapm_widget_for_each_sink_path, expect that
+ *  This function works like snd_soc_dapm_widget_for_each_path, expect that
  *  it is safe to remove the current path from the list while iterating
  */
 #define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \
index 5b689c6..2864aed 100644 (file)
@@ -78,8 +78,6 @@ struct snd_soc_dpcm {
        struct list_head list_be;
        struct list_head list_fe;
 
-       /* hw params for this link - may be different for each link */
-       struct snd_pcm_hw_params hw_params;
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_state;
 #endif
index 341fef1..266e663 100644 (file)
@@ -59,15 +59,11 @@ enum sof_ipc_type {
  * SOF Platform data.
  */
 struct snd_sof_pdata {
-       const struct firmware *fw;
        const char *name;
        const char *platform;
 
        struct device *dev;
 
-       /* indicate how many first bytes shouldn't be loaded into DSP memory. */
-       size_t fw_offset;
-
        /*
         * notification callback used if the hardware initialization
         * can take time or is handled in a workqueue. This callback
@@ -86,6 +82,9 @@ struct snd_sof_pdata {
        const char *tplg_filename_prefix;
        const char *tplg_filename;
 
+       /* loadable external libraries available under this directory */
+       const char *fw_lib_prefix;
+
        /* machine */
        struct platform_device *pdev_mach;
        const struct snd_soc_acpi_mach *machine;
@@ -131,8 +130,9 @@ struct sof_dev_desc {
        unsigned int ipc_supported_mask;
        enum sof_ipc_type ipc_default;
 
-       /* defaults paths for firmware and topology files */
+       /* defaults paths for firmware, library and topology files */
        const char *default_fw_path[SOF_IPC_TYPE_COUNT];
+       const char *default_lib_path[SOF_IPC_TYPE_COUNT];
        const char *default_tplg_path[SOF_IPC_TYPE_COUNT];
 
        /* default firmware name */
index 99efe0e..622193b 100644 (file)
@@ -185,6 +185,10 @@ enum sof_ipc4_pipeline_state {
 #define SOF_IPC4_GLB_PIPE_STATE_MASK           GENMASK(15, 0)
 #define SOF_IPC4_GLB_PIPE_STATE(x)             ((x) << SOF_IPC4_GLB_PIPE_STATE_SHIFT)
 
+/* load library ipc msg */
+#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT 16
+#define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(x)    ((x) << SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT)
+
 enum sof_ipc4_channel_config {
        /* one channel only. */
        SOF_IPC4_CHANNEL_CONFIG_MONO,
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
deleted file mode 100644 (file)
index b660a9e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Platform data for Texas Instruments TLV320AIC3x codec
- *
- * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
- */
-#ifndef __TLV320AIC3x_H__
-#define __TLV320AIC3x_H__
-
-/* GPIO API */
-enum {
-       AIC3X_GPIO1_FUNC_DISABLED               = 0,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
-       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
-       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
-       AIC3X_GPIO1_FUNC_INPUT                  = 8,
-       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
-       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
-       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
-       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
-};
-
-enum {
-       AIC3X_GPIO2_FUNC_DISABLED               = 0,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
-       AIC3X_GPIO2_FUNC_INPUT                  = 3,
-       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
-       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
-       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
-       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
-       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
-       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
-       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
-};
-
-enum aic3x_micbias_voltage {
-       AIC3X_MICBIAS_OFF = 0,
-       AIC3X_MICBIAS_2_0V = 1,
-       AIC3X_MICBIAS_2_5V = 2,
-       AIC3X_MICBIAS_AVDDV = 3,
-};
-
-struct aic3x_setup_data {
-       unsigned int gpio_func[2];
-};
-
-struct aic3x_pdata {
-       int gpio_reset; /* < 0 if not used */
-       struct aic3x_setup_data *setup;
-
-       /* Selects the micbias voltage */
-       enum aic3x_micbias_voltage micbias_vg;
-};
-
-#endif
index 440c072..b9b9093 100644 (file)
@@ -191,6 +191,33 @@ enum ar_event_types {
 #define AR_TKN_U32_MODULE_SRC_INSTANCE_ID      208
 #define AR_TKN_U32_MODULE_DST_INSTANCE_ID      209
 
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID1      210
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID1      211
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID1     212
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID2      213
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID2      214
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID2     215
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID3      216
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID3      217
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID3     218
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID4      219
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID4      220
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID4     221
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID5      222
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID5      223
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID5     224
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID6      225
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID6      226
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID6     227
+
+#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID7      228
+#define AR_TKN_U32_MODULE_DST_IN_PORT_ID7      229
+#define AR_TKN_U32_MODULE_DST_INSTANCE_ID7     230
 
 #define AR_TKN_U32_MODULE_HW_IF_IDX            250
 #define AR_TKN_U32_MODULE_HW_IF_TYPE           251
index 5caf75c..f187dfb 100644 (file)
 #define SOF_TKN_COMP_CPC                       406
 #define SOF_TKN_COMP_IS_PAGES                  409
 #define SOF_TKN_COMP_NUM_AUDIO_FORMATS         410
+#define SOF_TKN_COMP_NUM_SINK_PINS             411
+#define SOF_TKN_COMP_NUM_SOURCE_PINS           412
+/*
+ * The token for sink/source pin binding, it specifies the widget
+ * name that the sink/source pin is connected from/to.
+ */
+#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME    413
+#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME     414
+
 
 /* SSP */
 #define SOF_TKN_INTEL_SSP_CLKS_CONTROL         500
index 80876b9..6199bb6 100644 (file)
@@ -108,50 +108,48 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
 
 /**
- * snd_hdac_link_free_all- free hdac extended link objects
+ * snd_hdac_ext_link_free_all- free hdac extended link objects
  *
  * @bus: the pointer to HDAC bus object
  */
 
-void snd_hdac_link_free_all(struct hdac_bus *bus)
+void snd_hdac_ext_link_free_all(struct hdac_bus *bus)
 {
-       struct hdac_ext_link *l;
+       struct hdac_ext_link *hlink;
 
        while (!list_empty(&bus->hlink_list)) {
-               l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
-               list_del(&l->list);
-               kfree(l);
+               hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
+               list_del(&hlink->list);
+               kfree(hlink);
        }
 }
-EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all);
 
 /**
- * snd_hdac_ext_bus_link_at - get link at specified address
- * @bus: link's parent bus device
+ * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address
+ * @bus: hlink's parent bus device
  * @addr: codec device address
  *
- * Returns link object or NULL if matching link is not found.
+ * Returns hlink object or NULL if matching hlink is not found.
  */
-struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr)
 {
        struct hdac_ext_link *hlink;
-       int i;
 
        list_for_each_entry(hlink, &bus->hlink_list, list)
-               for (i = 0; i < HDA_MAX_CODECS; i++)
-                       if (hlink->lsdiid & (0x1 << addr))
-                               return hlink;
+               if (hlink->lsdiid & (0x1 << addr))
+                       return hlink;
        return NULL;
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_addr);
 
 /**
- * snd_hdac_ext_bus_get_link - get link based on codec name
+ * snd_hdac_ext_bus_get_hlink_by_name - get hlink based on codec name
  * @bus: the pointer to HDAC bus object
  * @codec_name: codec name
  */
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
-                                                const char *codec_name)
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus,
+                                                        const char *codec_name)
 {
        int bus_idx, addr;
 
@@ -162,11 +160,11 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
        if (addr < 0 || addr > 31)
                return NULL;
 
-       return snd_hdac_ext_bus_link_at(bus, addr);
+       return snd_hdac_ext_bus_get_hlink_by_addr(bus, addr);
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_name);
 
-static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
+static int check_hdac_link_power_active(struct hdac_ext_link *hlink, bool enable)
 {
        int timeout;
        u32 val;
@@ -176,7 +174,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
        timeout = 150;
 
        do {
-               val = readl(link->ml_addr + AZX_REG_ML_LCTL);
+               val = readl(hlink->ml_addr + AZX_REG_ML_LCTL);
                if (enable) {
                        if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT))
                                return 0;
@@ -192,26 +190,26 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
 
 /**
  * snd_hdac_ext_bus_link_power_up -power up hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
  */
-int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink)
 {
-       snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
+       snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
                         AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
 
-       return check_hdac_link_power_active(link, true);
+       return check_hdac_link_power_active(hlink, true);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up);
 
 /**
  * snd_hdac_ext_bus_link_power_down -power down hda link
- * @link: HD-audio extended link
+ * @hlink: HD-audio extended link
  */
-int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
+int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink)
 {
-       snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
+       snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0);
 
-       return check_hdac_link_power_active(link, false);
+       return check_hdac_link_power_active(hlink, false);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
 
@@ -225,9 +223,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
        int ret;
 
        list_for_each_entry(hlink, &bus->hlink_list, list) {
-               snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
-                                AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA);
-               ret = check_hdac_link_power_active(hlink, true);
+               ret = snd_hdac_ext_bus_link_power_up(hlink);
                if (ret < 0)
                        return ret;
        }
@@ -246,9 +242,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
        int ret;
 
        list_for_each_entry(hlink, &bus->hlink_list, list) {
-               snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
-                                AZX_ML_LCTL_SPA, 0);
-               ret = check_hdac_link_power_active(hlink, false);
+               ret = snd_hdac_ext_bus_link_power_down(hlink);
                if (ret < 0)
                        return ret;
        }
@@ -257,8 +251,32 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
 
+/**
+ * snd_hdac_ext_bus_link_set_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *link,
+                                        int stream)
+{
+       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_set_stream_id);
+
+/**
+ * snd_hdac_ext_bus_link_clear_stream_id - maps stream id to link output
+ * @link: HD-audio ext link to set up
+ * @stream: stream id
+ */
+void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *link,
+                                          int stream)
+{
+       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_clear_stream_id);
+
 int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
-                               struct hdac_ext_link *link)
+                               struct hdac_ext_link *hlink)
 {
        unsigned long codec_mask;
        int ret = 0;
@@ -269,18 +287,18 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
         * if we move from 0 to 1, count will be 1 so power up this link
         * as well, also check the dma status and trigger that
         */
-       if (++link->ref_count == 1) {
+       if (++hlink->ref_count == 1) {
                if (!bus->cmd_dma_state) {
                        snd_hdac_bus_init_cmd_io(bus);
                        bus->cmd_dma_state = true;
                }
 
-               ret = snd_hdac_ext_bus_link_power_up(link);
+               ret = snd_hdac_ext_bus_link_power_up(hlink);
 
                /*
                 * clear the register to invalidate all the output streams
                 */
-               snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV,
+               snd_hdac_updatew(hlink->ml_addr, AZX_REG_ML_LOSIDV,
                                 AZX_ML_LOSIDV_STREAM_MASK, 0);
                /*
                 *  wait for 521usec for codec to report status
@@ -300,10 +318,10 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
 
 int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
-                               struct hdac_ext_link *link)
+                             struct hdac_ext_link *hlink)
 {
        int ret = 0;
-       struct hdac_ext_link *hlink;
+       struct hdac_ext_link *hlink_tmp;
        bool link_up = false;
 
        mutex_lock(&bus->lock);
@@ -312,15 +330,15 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
         * if we move from 1 to 0, count will be 0
         * so power down this link as well
         */
-       if (--link->ref_count == 0) {
-               ret = snd_hdac_ext_bus_link_power_down(link);
+       if (--hlink->ref_count == 0) {
+               ret = snd_hdac_ext_bus_link_power_down(hlink);
 
                /*
                 * now check if all links are off, if so turn off
                 * cmd dma as well
                 */
-               list_for_each_entry(hlink, &bus->hlink_list, list) {
-                       if (hlink->ref_count) {
+               list_for_each_entry(hlink_tmp, &bus->hlink_list, list) {
+                       if (hlink_tmp->ref_count) {
                                link_up = true;
                                break;
                        }
@@ -341,7 +359,7 @@ static void hdac_ext_codec_link_up(struct hdac_device *codec)
 {
        const char *devname = dev_name(&codec->dev);
        struct hdac_ext_link *hlink =
-               snd_hdac_ext_bus_get_link(codec->bus, devname);
+               snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
 
        if (hlink)
                snd_hdac_ext_bus_link_get(codec->bus, hlink);
@@ -351,7 +369,7 @@ static void hdac_ext_codec_link_down(struct hdac_device *codec)
 {
        const char *devname = dev_name(&codec->dev);
        struct hdac_ext_link *hlink =
-               snd_hdac_ext_bus_get_link(codec->bus, devname);
+               snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname);
 
        if (hlink)
                snd_hdac_ext_bus_link_put(codec->bus, hlink);
index 70f3ad7..2a071a0 100644 (file)
@@ -39,20 +39,6 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
                                AZX_PPLC_INTERVAL * idx;
        }
 
-       if (bus->spbcap) {
-               hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
-                                       AZX_SPB_INTERVAL * idx +
-                                       AZX_SPB_SPIB;
-
-               hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
-                                       AZX_SPB_INTERVAL * idx +
-                                       AZX_SPB_MAXFIFO;
-       }
-
-       if (bus->drsmcap)
-               hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
-                                       AZX_DRSM_INTERVAL * idx;
-
        hext_stream->decoupled = false;
        snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag);
 }
@@ -140,36 +126,36 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
 
 /**
- * snd_hdac_ext_link_stream_start - start a stream
+ * snd_hdac_ext_stream_start - start a stream
  * @hext_stream: HD-audio ext core stream to start
  */
-void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream)
 {
        snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
                         AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN);
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_start);
 
 /**
- * snd_hdac_ext_link_stream_clear - stop a stream DMA
+ * snd_hdac_ext_stream_clear - stop a stream DMA
  * @hext_stream: HD-audio ext core stream to stop
  */
-void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream)
 {
        snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0);
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_clear);
 
 /**
- * snd_hdac_ext_link_stream_reset - reset a stream
+ * snd_hdac_ext_stream_reset - reset a stream
  * @hext_stream: HD-audio ext core stream to reset
  */
-void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
+void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream)
 {
        unsigned char val;
        int timeout;
 
-       snd_hdac_ext_link_stream_clear(hext_stream);
+       snd_hdac_ext_stream_clear(hext_stream);
 
        snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
                         AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST);
@@ -196,20 +182,20 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream)
        } while (--timeout);
 
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_reset);
 
 /**
- * snd_hdac_ext_link_stream_setup -  set up the SD for streaming
+ * snd_hdac_ext_stream_setup -  set up the SD for streaming
  * @hext_stream: HD-audio ext core stream to set up
  * @fmt: stream format
  */
-int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
+int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
 {
        struct hdac_stream *hstream = &hext_stream->hstream;
        unsigned int val;
 
        /* make sure the run bit is zero for SD */
-       snd_hdac_ext_link_stream_clear(hext_stream);
+       snd_hdac_ext_stream_clear(hext_stream);
        /* program the stream_tag */
        val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL);
        val = (val & ~AZX_PPLCCTL_STRM_MASK) |
@@ -221,35 +207,11 @@ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup);
-
-/**
- * snd_hdac_ext_link_set_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
-                                    int stream)
-{
-       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id);
-
-/**
- * snd_hdac_ext_link_clear_stream_id - maps stream id to link output
- * @link: HD-audio ext link to set up
- * @stream: stream id
- */
-void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
-                                int stream)
-{
-       snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_setup);
 
 static struct hdac_ext_stream *
-hdac_ext_link_stream_assign(struct hdac_bus *bus,
-                           struct snd_pcm_substream *substream)
+hdac_ext_link_dma_stream_assign(struct hdac_bus *bus,
+                               struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *res = NULL;
        struct hdac_stream *hstream = NULL;
@@ -284,8 +246,8 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus,
 }
 
 static struct hdac_ext_stream *
-hdac_ext_host_stream_assign(struct hdac_bus *bus,
-                           struct snd_pcm_substream *substream)
+hdac_ext_host_dma_stream_assign(struct hdac_bus *bus,
+                               struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *res = NULL;
        struct hdac_stream *hstream = NULL;
@@ -353,10 +315,10 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
                return hext_stream;
 
        case HDAC_EXT_STREAM_TYPE_HOST:
-               return hdac_ext_host_stream_assign(bus, substream);
+               return hdac_ext_host_dma_stream_assign(bus, substream);
 
        case HDAC_EXT_STREAM_TYPE_LINK:
-               return hdac_ext_link_stream_assign(bus, substream);
+               return hdac_ext_link_dma_stream_assign(bus, substream);
 
        default:
                return NULL;
@@ -405,128 +367,3 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
 
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
-
-/**
- * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable SPIB
- * @index: stream index for which SPIB need to be enabled
- */
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
-                                bool enable, int index)
-{
-       u32 mask = 0;
-
-       if (!bus->spbcap) {
-               dev_err(bus->dev, "Address of SPB capability is NULL\n");
-               return;
-       }
-
-       mask |= (1 << index);
-
-       if (enable)
-               snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
-       else
-               snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
-
-/**
- * snd_hdac_ext_stream_set_spib - sets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: spib value to set
- */
-int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
-                                struct hdac_ext_stream *hext_stream, u32 value)
-{
-
-       if (!bus->spbcap) {
-               dev_err(bus->dev, "Address of SPB capability is NULL\n");
-               return -EINVAL;
-       }
-
-       writel(value, hext_stream->spib_addr);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
-
-/**
- * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- *
- * Return maxfifo for the stream
- */
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
-                                struct hdac_ext_stream *hext_stream)
-{
-
-       if (!bus->spbcap) {
-               dev_err(bus->dev, "Address of SPB capability is NULL\n");
-               return -EINVAL;
-       }
-
-       return readl(hext_stream->fifo_addr);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
-
-/**
- * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
- * @bus: HD-audio core bus
- * @enable: flag to enable/disable DRSM
- * @index: stream index for which DRSM need to be enabled
- */
-void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
-                               bool enable, int index)
-{
-       u32 mask = 0;
-
-       if (!bus->drsmcap) {
-               dev_err(bus->dev, "Address of DRSM capability is NULL\n");
-               return;
-       }
-
-       mask |= (1 << index);
-
-       if (enable)
-               snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
-       else
-               snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
-
-/**
- * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
- * @bus: HD-audio core bus
- * @hext_stream: hdac_ext_stream
- * @value: dpib value to set
- */
-int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
-                                 struct hdac_ext_stream *hext_stream, u32 value)
-{
-
-       if (!bus->drsmcap) {
-               dev_err(bus->dev, "Address of DRSM capability is NULL\n");
-               return -EINVAL;
-       }
-
-       writel(value, hext_stream->dpibr_addr);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
-
-/**
- * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
- * @hext_stream: hdac_ext_stream
- * @value: lpib value to set
- */
-int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value)
-{
-       snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
index 1b8be39..3b250ee 100644 (file)
@@ -103,6 +103,20 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
        azx_dev->stream_tag = tag;
        snd_hdac_dsp_lock_init(azx_dev);
        list_add_tail(&azx_dev->list, &bus->stream_list);
+
+       if (bus->spbcap) {
+               azx_dev->spib_addr = bus->spbcap + AZX_SPB_BASE +
+                                       AZX_SPB_INTERVAL * idx +
+                                       AZX_SPB_SPIB;
+
+               azx_dev->fifo_addr = bus->spbcap + AZX_SPB_BASE +
+                                       AZX_SPB_INTERVAL * idx +
+                                       AZX_SPB_MAXFIFO;
+       }
+
+       if (bus->drsmcap)
+               azx_dev->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE +
+                                       AZX_DRSM_INTERVAL * idx;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_stream_init);
 
@@ -718,6 +732,150 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
 }
 EXPORT_SYMBOL_GPL(snd_hdac_stream_sync);
 
+/**
+ * snd_hdac_stream_spbcap_enable - enable SPIB for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable SPIB
+ * @index: stream index for which SPIB need to be enabled
+ */
+void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus,
+                                  bool enable, int index)
+{
+       u32 mask = 0;
+
+       if (!bus->spbcap) {
+               dev_err(bus->dev, "Address of SPB capability is NULL\n");
+               return;
+       }
+
+       mask |= (1 << index);
+
+       if (enable)
+               snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask);
+       else
+               snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable);
+
+/**
+ * snd_hdac_stream_set_spib - sets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: spib value to set
+ */
+int snd_hdac_stream_set_spib(struct hdac_bus *bus,
+                            struct hdac_stream *azx_dev, u32 value)
+{
+       if (!bus->spbcap) {
+               dev_err(bus->dev, "Address of SPB capability is NULL\n");
+               return -EINVAL;
+       }
+
+       writel(value, azx_dev->spib_addr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib);
+
+/**
+ * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ *
+ * Return maxfifo for the stream
+ */
+int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
+                                  struct hdac_stream *azx_dev)
+{
+       if (!bus->spbcap) {
+               dev_err(bus->dev, "Address of SPB capability is NULL\n");
+               return -EINVAL;
+       }
+
+       return readl(azx_dev->fifo_addr);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo);
+
+/**
+ * snd_hdac_stream_drsm_enable - enable DMA resume for a stream
+ * @bus: HD-audio core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_stream_drsm_enable(struct hdac_bus *bus,
+                                bool enable, int index)
+{
+       u32 mask = 0;
+
+       if (!bus->drsmcap) {
+               dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+               return;
+       }
+
+       mask |= (1 << index);
+
+       if (enable)
+               snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask);
+       else
+               snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable);
+
+/*
+ * snd_hdac_stream_wait_drsm - wait for HW to clear RSM for a stream
+ * @azx_dev: HD-audio core stream to await RSM for
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+int snd_hdac_stream_wait_drsm(struct hdac_stream *azx_dev)
+{
+       struct hdac_bus *bus = azx_dev->bus;
+       u32 mask, reg;
+       int ret;
+
+       mask = 1 << azx_dev->index;
+
+       ret = read_poll_timeout(snd_hdac_reg_readl, reg, !(reg & mask), 250, 2000, false, bus,
+                               bus->drsmcap + AZX_REG_DRSM_CTL);
+       if (ret)
+               dev_dbg(bus->dev, "polling RSM 0x%08x failed: %d\n", mask, ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_wait_drsm);
+
+/**
+ * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream
+ * @bus: HD-audio core bus
+ * @azx_dev: hdac_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_stream_set_dpibr(struct hdac_bus *bus,
+                             struct hdac_stream *azx_dev, u32 value)
+{
+       if (!bus->drsmcap) {
+               dev_err(bus->dev, "Address of DRSM capability is NULL\n");
+               return -EINVAL;
+       }
+
+       writel(value, azx_dev->dpibr_addr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr);
+
+/**
+ * snd_hdac_stream_set_lpib - sets the lpib value of a stream
+ * @azx_dev: hdac_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value)
+{
+       snd_hdac_stream_writel(azx_dev, SD_LPIB, value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib);
+
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 /**
  * snd_hdac_dsp_prepare - prepare for DSP loading
index a8e8cf9..06d304d 100644 (file)
@@ -98,7 +98,7 @@ config SND_HDA_SCODEC_CS35L41
 
 config SND_HDA_CS_DSP_CONTROLS
        tristate
-       select CS_DSP
+       select FW_CS_DSP
 
 config SND_HDA_SCODEC_CS35L41_I2C
        tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
index e5f0549..91842c0 100644 (file)
@@ -1545,3 +1545,4 @@ MODULE_DESCRIPTION("CS35L41 HDA Driver");
 MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
 MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
index 1622a22..5433f62 100644 (file)
@@ -249,3 +249,4 @@ EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS);
 MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library");
 MODULE_AUTHOR("Stefan Binding, <sbinding@opensource.cirrus.com>");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
index 1507862..c88ebd8 100644 (file)
@@ -129,10 +129,10 @@ config SND_SOC_AMD_RPL_ACP6x
           If unsure select "N".
 
 config SND_SOC_AMD_PS
-        tristate "AMD Audio Coprocessor-v6.2 Pink Sardine support"
+        tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
         depends on X86 && PCI && ACPI
         help
-          This option enables Audio Coprocessor i.e ACP v6.2 support on
+          This option enables Audio Coprocessor i.e ACP v6.3 support on
           AMD Pink sardine platform. By enabling this flag build will be
           triggered for ACP PCI driver, ACP PDM DMA driver.
           Say m if you have such a device.
index ef1b4ce..375417b 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "acp.h"
 #include "../codecs/da7219.h"
-#include "../codecs/da7219-aad.h"
 #include "../codecs/rt5682.h"
 
 #define CZ_PLAT_CLK 48000000
@@ -82,7 +81,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, &cz_jack);
+       snd_soc_component_set_jack(component, &cz_jack, NULL);
 
        return 0;
 }
index ac41657..09b6511 100644 (file)
@@ -51,7 +51,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
        struct acp_stream *stream;
-       int slot_len;
+       int slot_len, no_of_slots;
 
        switch (slot_width) {
        case SLOT_WIDTH_8:
@@ -71,6 +71,20 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
                return -EINVAL;
        }
 
+       switch (slots) {
+       case 1 ... 7:
+               no_of_slots = slots;
+               break;
+       case 8:
+               no_of_slots = 0;
+               break;
+       default:
+               dev_err(dev, "Unsupported slots %d\n", slots);
+               return -EINVAL;
+       }
+
+       slots = no_of_slots;
+
        spin_lock_irq(&adata->acp_lock);
        list_for_each_entry(stream, &adata->stream_list, list) {
                if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
index 4c69cb6..a78cf29 100644 (file)
@@ -167,11 +167,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
                                      &constraints_channels);
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                      &constraints_rates);
-       if (!drvdata->soc_mclk) {
-               ret = acp_clk_enable(drvdata);
-               if (ret < 0) {
-                       dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
-                       return ret;
+
+       if (strcmp(codec_dai->name, "rt5682s-aif1") && strcmp(codec_dai->name, "rt5682s-aif2")) {
+               if (!drvdata->soc_mclk) {
+                       ret = acp_clk_enable(drvdata);
+                       if (ret < 0) {
+                               dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+                               return ret;
+                       }
                }
        }
 
@@ -280,7 +283,6 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
 
 static const struct snd_soc_ops acp_card_rt5682s_ops = {
        .startup = acp_card_hs_startup,
-       .shutdown = acp_card_shutdown,
 };
 
 static const unsigned int dmic_channels[] = {
@@ -570,6 +572,52 @@ SND_SOC_DAILINK_DEF(sof_dmic,
 SND_SOC_DAILINK_DEF(pdm_dmic,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic")));
 
+static int acp_rtk_set_bias_level(struct snd_soc_card *card,
+                                 struct snd_soc_dapm_context *dapm,
+                                 enum snd_soc_bias_level level)
+{
+       struct snd_soc_component *component = dapm->component;
+       struct acp_card_drvdata *drvdata = card->drvdata;
+       int ret = 0;
+
+       if (!component)
+               return 0;
+
+       if (strncmp(component->name, "i2c-RTL5682", 11) &&
+           strncmp(component->name, "i2c-10EC1019", 12))
+               return 0;
+
+       /*
+        * For Realtek's codec and amplifier components,
+        * the lrck and bclk must be enabled brfore their all dapms be powered on,
+        * and must be disabled after their all dapms be powered down
+        * to avoid any pop.
+        */
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
+                       clk_set_rate(drvdata->wclk, 48000);
+                       clk_set_rate(drvdata->bclk, 48000 * 64);
+
+                       /* Increase bclk's enable_count */
+                       ret = clk_prepare_enable(drvdata->bclk);
+                       if (ret < 0)
+                               dev_err(component->dev, "Failed to enable bclk %d\n", ret);
+               } else {
+                       /*
+                        * Decrease bclk's enable_count.
+                        * While the enable_count is 0, the bclk would be closed.
+                        */
+                       clk_disable_unprepare(drvdata->bclk);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
 int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *links;
@@ -730,6 +778,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
 
        card->dai_link = links;
        card->num_links = num_links;
+       card->set_bias_level = acp_rtk_set_bias_level;
 
        return 0;
 }
@@ -907,6 +956,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
 
        card->dai_link = links;
        card->num_links = num_links;
+       card->set_bias_level = acp_rtk_set_bias_level;
 
        return 0;
 }
index 85a81ad..447612a 100644 (file)
@@ -184,10 +184,6 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
 
        stream->substream = substream;
 
-       spin_lock_irq(&adata->acp_lock);
-       list_add_tail(&stream->list, &adata->stream_list);
-       spin_unlock_irq(&adata->acp_lock);
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                runtime->hw = acp_pcm_hardware_playback;
        else
@@ -203,6 +199,10 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
 
        writel(1, ACP_EXTERNAL_INTR_ENB(adata));
 
+       spin_lock_irq(&adata->acp_lock);
+       list_add_tail(&stream->list, &adata->stream_list);
+       spin_unlock_irq(&adata->acp_lock);
+
        return ret;
 }
 
similarity index 79%
rename from sound/soc/amd/ps/acp62.h
rename to sound/soc/amd/ps/acp63.h
index 8b30aef..5e7f9c1 100644 (file)
@@ -5,13 +5,13 @@
  * Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.
  */
 
-#include <sound/acp62_chip_offset_byte.h>
+#include <sound/acp63_chip_offset_byte.h>
 
 #define ACP_DEVICE_ID 0x15E2
-#define ACP6x_REG_START                0x1240000
-#define ACP6x_REG_END          0x1250200
-#define ACP6x_DEVS             3
-#define ACP6x_PDM_MODE         1
+#define ACP63_REG_START                0x1240000
+#define ACP63_REG_END          0x1250200
+#define ACP63_DEVS             3
+#define ACP63_PDM_MODE         1
 
 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK  0x00010001
 #define ACP_PGFSM_CNTL_POWER_ON_MASK   1
@@ -78,21 +78,28 @@ struct pdm_stream_instance {
        u16 channels;
        dma_addr_t dma_addr;
        u64 bytescount;
-       void __iomem *acp62_base;
+       void __iomem *acp63_base;
 };
 
 struct pdm_dev_data {
        u32 pdm_irq;
-       void __iomem *acp62_base;
+       void __iomem *acp63_base;
        struct snd_pcm_substream *capture_stream;
 };
 
-static inline u32 acp62_readl(void __iomem *base_addr)
+static inline u32 acp63_readl(void __iomem *base_addr)
 {
        return readl(base_addr);
 }
 
-static inline void acp62_writel(u32 val, void __iomem *base_addr)
+static inline void acp63_writel(u32 val, void __iomem *base_addr)
 {
        writel(val, base_addr);
 }
+
+struct acp63_dev_data {
+       void __iomem *acp63_base;
+       struct resource *res;
+       bool acp63_audio_mode;
+       struct platform_device *pdev[ACP63_DEVS];
+};
index dff2e23..489f01a 100644 (file)
 #include <sound/pcm_params.h>
 #include <linux/pm_runtime.h>
 
-#include "acp62.h"
+#include "acp63.h"
 
-struct acp62_dev_data {
-       void __iomem *acp62_base;
-       struct resource *res;
-       bool acp62_audio_mode;
-       struct platform_device *pdev[ACP6x_DEVS];
-};
-
-static int acp62_power_on(void __iomem *acp_base)
+static int acp63_power_on(void __iomem *acp_base)
 {
        u32 val;
        int timeout;
 
-       val = acp62_readl(acp_base + ACP_PGFSM_STATUS);
+       val = acp63_readl(acp_base + ACP_PGFSM_STATUS);
 
        if (!val)
                return val;
 
        if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
-               acp62_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+               acp63_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
        timeout = 0;
        while (++timeout < 500) {
-               val = acp62_readl(acp_base + ACP_PGFSM_STATUS);
+               val = acp63_readl(acp_base + ACP_PGFSM_STATUS);
                if (!val)
                        return 0;
                udelay(1);
@@ -46,23 +39,23 @@ static int acp62_power_on(void __iomem *acp_base)
        return -ETIMEDOUT;
 }
 
-static int acp62_reset(void __iomem *acp_base)
+static int acp63_reset(void __iomem *acp_base)
 {
        u32 val;
        int timeout;
 
-       acp62_writel(1, acp_base + ACP_SOFT_RESET);
+       acp63_writel(1, acp_base + ACP_SOFT_RESET);
        timeout = 0;
        while (++timeout < 500) {
-               val = acp62_readl(acp_base + ACP_SOFT_RESET);
+               val = acp63_readl(acp_base + ACP_SOFT_RESET);
                if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
                        break;
                cpu_relax();
        }
-       acp62_writel(0, acp_base + ACP_SOFT_RESET);
+       acp63_writel(0, acp_base + ACP_SOFT_RESET);
        timeout = 0;
        while (++timeout < 500) {
-               val = acp62_readl(acp_base + ACP_SOFT_RESET);
+               val = acp63_readl(acp_base + ACP_SOFT_RESET);
                if (!val)
                        return 0;
                cpu_relax();
@@ -70,57 +63,57 @@ static int acp62_reset(void __iomem *acp_base)
        return -ETIMEDOUT;
 }
 
-static void acp62_enable_interrupts(void __iomem *acp_base)
+static void acp63_enable_interrupts(void __iomem *acp_base)
 {
-       acp62_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
+       acp63_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
 }
 
-static void acp62_disable_interrupts(void __iomem *acp_base)
+static void acp63_disable_interrupts(void __iomem *acp_base)
 {
-       acp62_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
+       acp63_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
                     ACP_EXTERNAL_INTR_STAT);
-       acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
-       acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
+       acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
+       acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
 }
 
-static int acp62_init(void __iomem *acp_base, struct device *dev)
+static int acp63_init(void __iomem *acp_base, struct device *dev)
 {
        int ret;
 
-       ret = acp62_power_on(acp_base);
+       ret = acp63_power_on(acp_base);
        if (ret) {
                dev_err(dev, "ACP power on failed\n");
                return ret;
        }
-       acp62_writel(0x01, acp_base + ACP_CONTROL);
-       ret = acp62_reset(acp_base);
+       acp63_writel(0x01, acp_base + ACP_CONTROL);
+       ret = acp63_reset(acp_base);
        if (ret) {
                dev_err(dev, "ACP reset failed\n");
                return ret;
        }
-       acp62_writel(0x03, acp_base + ACP_CLKMUX_SEL);
-       acp62_enable_interrupts(acp_base);
+       acp63_writel(0x03, acp_base + ACP_CLKMUX_SEL);
+       acp63_enable_interrupts(acp_base);
        return 0;
 }
 
-static int acp62_deinit(void __iomem *acp_base, struct device *dev)
+static int acp63_deinit(void __iomem *acp_base, struct device *dev)
 {
        int ret;
 
-       acp62_disable_interrupts(acp_base);
-       ret = acp62_reset(acp_base);
+       acp63_disable_interrupts(acp_base);
+       ret = acp63_reset(acp_base);
        if (ret) {
                dev_err(dev, "ACP reset failed\n");
                return ret;
        }
-       acp62_writel(0, acp_base + ACP_CLKMUX_SEL);
-       acp62_writel(0, acp_base + ACP_CONTROL);
+       acp63_writel(0, acp_base + ACP_CLKMUX_SEL);
+       acp63_writel(0, acp_base + ACP_CONTROL);
        return 0;
 }
 
-static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
+static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
 {
-       struct acp62_dev_data *adata;
+       struct acp63_dev_data *adata;
        struct pdm_dev_data *ps_pdm_data;
        u32 val;
 
@@ -128,10 +121,10 @@ static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
        if (!adata)
                return IRQ_NONE;
 
-       val = acp62_readl(adata->acp62_base + ACP_EXTERNAL_INTR_STAT);
+       val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
        if (val & BIT(PDM_DMA_STAT)) {
                ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev);
-               acp62_writel(BIT(PDM_DMA_STAT), adata->acp62_base + ACP_EXTERNAL_INTR_STAT);
+               acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
                if (ps_pdm_data->capture_stream)
                        snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
                return IRQ_HANDLED;
@@ -139,11 +132,11 @@ static irqreturn_t acp62_irq_handler(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static int snd_acp62_probe(struct pci_dev *pci,
+static int snd_acp63_probe(struct pci_dev *pci,
                           const struct pci_device_id *pci_id)
 {
-       struct acp62_dev_data *adata;
-       struct platform_device_info pdevinfo[ACP6x_DEVS];
+       struct acp63_dev_data *adata;
+       struct platform_device_info pdevinfo[ACP63_DEVS];
        int index, ret;
        int val = 0x00;
        struct acpi_device *adev;
@@ -157,7 +150,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
        case 0x63:
                break;
        default:
-               dev_dbg(&pci->dev, "acp62 pci device not found\n");
+               dev_dbg(&pci->dev, "acp63 pci device not found\n");
                return -ENODEV;
        }
        if (pci_enable_device(pci)) {
@@ -170,7 +163,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
                dev_err(&pci->dev, "pci_request_regions failed\n");
                goto disable_pci;
        }
-       adata = devm_kzalloc(&pci->dev, sizeof(struct acp62_dev_data),
+       adata = devm_kzalloc(&pci->dev, sizeof(struct acp63_dev_data),
                             GFP_KERNEL);
        if (!adata) {
                ret = -ENOMEM;
@@ -178,18 +171,18 @@ static int snd_acp62_probe(struct pci_dev *pci,
        }
 
        addr = pci_resource_start(pci, 0);
-       adata->acp62_base = devm_ioremap(&pci->dev, addr,
+       adata->acp63_base = devm_ioremap(&pci->dev, addr,
                                         pci_resource_len(pci, 0));
-       if (!adata->acp62_base) {
+       if (!adata->acp63_base) {
                ret = -ENOMEM;
                goto release_regions;
        }
        pci_set_master(pci);
        pci_set_drvdata(pci, adata);
-       ret = acp62_init(adata->acp62_base, &pci->dev);
+       ret = acp63_init(adata->acp63_base, &pci->dev);
        if (ret)
                goto release_regions;
-       val = acp62_readl(adata->acp62_base + ACP_PIN_CONFIG);
+       val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG);
        switch (val) {
        case ACP_CONFIG_0:
        case ACP_CONFIG_1:
@@ -219,8 +212,8 @@ static int snd_acp62_probe(struct pci_dev *pci,
                        adata->res->name = "acp_iomem";
                        adata->res->flags = IORESOURCE_MEM;
                        adata->res->start = addr;
-                       adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START);
-                       adata->acp62_audio_mode = ACP6x_PDM_MODE;
+                       adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START);
+                       adata->acp63_audio_mode = ACP63_PDM_MODE;
 
                        memset(&pdevinfo, 0, sizeof(pdevinfo));
                        pdevinfo[0].name = "acp_ps_pdm_dma";
@@ -237,7 +230,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
                        pdevinfo[2].id = 0;
                        pdevinfo[2].parent = &pci->dev;
 
-                       for (index = 0; index < ACP6x_DEVS; index++) {
+                       for (index = 0; index < ACP63_DEVS; index++) {
                                adata->pdev[index] =
                                        platform_device_register_full(&pdevinfo[index]);
 
@@ -248,7 +241,7 @@ static int snd_acp62_probe(struct pci_dev *pci,
                                        ret = PTR_ERR(adata->pdev[index]);
                                        goto unregister_devs;
                                }
-                               ret = devm_request_irq(&pci->dev, pci->irq, acp62_irq_handler,
+                               ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler,
                                                       irqflags, "ACP_PCI_IRQ", adata);
                                if (ret) {
                                        dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
@@ -267,7 +260,7 @@ unregister_devs:
        for (--index; index >= 0; index--)
                platform_device_unregister(adata->pdev[index]);
 de_init:
-       if (acp62_deinit(adata->acp62_base, &pci->dev))
+       if (acp63_deinit(adata->acp63_base, &pci->dev))
                dev_err(&pci->dev, "ACP de-init failed\n");
 release_regions:
        pci_release_regions(pci);
@@ -277,46 +270,46 @@ disable_pci:
        return ret;
 }
 
-static int __maybe_unused snd_acp62_suspend(struct device *dev)
+static int __maybe_unused snd_acp63_suspend(struct device *dev)
 {
-       struct acp62_dev_data *adata;
+       struct acp63_dev_data *adata;
        int ret;
 
        adata = dev_get_drvdata(dev);
-       ret = acp62_deinit(adata->acp62_base, dev);
+       ret = acp63_deinit(adata->acp63_base, dev);
        if (ret)
                dev_err(dev, "ACP de-init failed\n");
        return ret;
 }
 
-static int __maybe_unused snd_acp62_resume(struct device *dev)
+static int __maybe_unused snd_acp63_resume(struct device *dev)
 {
-       struct acp62_dev_data *adata;
+       struct acp63_dev_data *adata;
        int ret;
 
        adata = dev_get_drvdata(dev);
-       ret = acp62_init(adata->acp62_base, dev);
+       ret = acp63_init(adata->acp63_base, dev);
        if (ret)
                dev_err(dev, "ACP init failed\n");
        return ret;
 }
 
-static const struct dev_pm_ops acp62_pm_ops = {
-       SET_RUNTIME_PM_OPS(snd_acp62_suspend, snd_acp62_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(snd_acp62_suspend, snd_acp62_resume)
+static const struct dev_pm_ops acp63_pm_ops = {
+       SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume)
 };
 
-static void snd_acp62_remove(struct pci_dev *pci)
+static void snd_acp63_remove(struct pci_dev *pci)
 {
-       struct acp62_dev_data *adata;
+       struct acp63_dev_data *adata;
        int ret, index;
 
        adata = pci_get_drvdata(pci);
-       if (adata->acp62_audio_mode == ACP6x_PDM_MODE) {
-               for (index = 0; index < ACP6x_DEVS; index++)
+       if (adata->acp63_audio_mode == ACP63_PDM_MODE) {
+               for (index = 0; index < ACP63_DEVS; index++)
                        platform_device_unregister(adata->pdev[index]);
        }
-       ret = acp62_deinit(adata->acp62_base, &pci->dev);
+       ret = acp63_deinit(adata->acp63_base, &pci->dev);
        if (ret)
                dev_err(&pci->dev, "ACP de-init failed\n");
        pm_runtime_forbid(&pci->dev);
@@ -325,25 +318,25 @@ static void snd_acp62_remove(struct pci_dev *pci)
        pci_disable_device(pci);
 }
 
-static const struct pci_device_id snd_acp62_ids[] = {
+static const struct pci_device_id snd_acp63_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
        .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
        .class_mask = 0xffffff },
        { 0, },
 };
-MODULE_DEVICE_TABLE(pci, snd_acp62_ids);
+MODULE_DEVICE_TABLE(pci, snd_acp63_ids);
 
-static struct pci_driver ps_acp62_driver  = {
+static struct pci_driver ps_acp63_driver  = {
        .name = KBUILD_MODNAME,
-       .id_table = snd_acp62_ids,
-       .probe = snd_acp62_probe,
-       .remove = snd_acp62_remove,
+       .id_table = snd_acp63_ids,
+       .probe = snd_acp63_probe,
+       .remove = snd_acp63_remove,
        .driver = {
-               .pm = &acp62_pm_ops,
+               .pm = &acp63_pm_ops,
        }
 };
 
-module_pci_driver(ps_acp62_driver);
+module_pci_driver(ps_acp63_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 MODULE_AUTHOR("Syed.SabaKareem@amd.com");
index b3e9709..3ffbe4f 100644 (file)
 #include <linux/io.h>
 #include <linux/dmi.h>
 
-#include "acp62.h"
+#include "acp63.h"
 
 #define DRV_NAME "acp_ps_mach"
 
-SND_SOC_DAILINK_DEF(acp62_pdm,
+SND_SOC_DAILINK_DEF(acp63_pdm,
                    DAILINK_COMP_ARRAY(COMP_CPU("acp_ps_pdm_dma.0")));
 
 SND_SOC_DAILINK_DEF(dmic_codec,
@@ -27,31 +27,31 @@ SND_SOC_DAILINK_DEF(dmic_codec,
 SND_SOC_DAILINK_DEF(pdm_platform,
                    DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_ps_pdm_dma.0")));
 
-static struct snd_soc_dai_link acp62_dai_pdm[] = {
+static struct snd_soc_dai_link acp63_dai_pdm[] = {
        {
-               .name = "acp62-dmic-capture",
+               .name = "acp63-dmic-capture",
                .stream_name = "DMIC capture",
                .capture_only = 1,
-               SND_SOC_DAILINK_REG(acp62_pdm, dmic_codec, pdm_platform),
+               SND_SOC_DAILINK_REG(acp63_pdm, dmic_codec, pdm_platform),
        },
 };
 
-static struct snd_soc_card acp62_card = {
-       .name = "acp62",
+static struct snd_soc_card acp63_card = {
+       .name = "acp63",
        .owner = THIS_MODULE,
-       .dai_link = acp62_dai_pdm,
+       .dai_link = acp63_dai_pdm,
        .num_links = 1,
 };
 
-static int acp62_probe(struct platform_device *pdev)
+static int acp63_probe(struct platform_device *pdev)
 {
-       struct acp62_pdm *machine = NULL;
+       struct acp63_pdm *machine = NULL;
        struct snd_soc_card *card;
        int ret;
 
-       platform_set_drvdata(pdev, &acp62_card);
+       platform_set_drvdata(pdev, &acp63_card);
        card = platform_get_drvdata(pdev);
-       acp62_card.dev = &pdev->dev;
+       acp63_card.dev = &pdev->dev;
 
        snd_soc_card_set_drvdata(card, machine);
        ret = devm_snd_soc_register_card(&pdev->dev, card);
@@ -64,15 +64,15 @@ static int acp62_probe(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver acp62_mach_driver = {
+static struct platform_driver acp63_mach_driver = {
        .driver = {
                .name = "acp_ps_mach",
                .pm = &snd_soc_pm_ops,
        },
-       .probe = acp62_probe,
+       .probe = acp63_probe,
 };
 
-module_platform_driver(acp62_mach_driver);
+module_platform_driver(acp63_mach_driver);
 
 MODULE_AUTHOR("Syed.SabaKareem@amd.com");
 MODULE_LICENSE("GPL v2");
index b207b72..eea71a9 100644 (file)
 #include <sound/soc-dai.h>
 #include <linux/pm_runtime.h>
 
-#include "acp62.h"
+#include "acp63.h"
 
 #define DRV_NAME "acp_ps_pdm_dma"
 
-static const struct snd_pcm_hardware acp62_pdm_hardware_capture = {
+static const struct snd_pcm_hardware acp63_pdm_hardware_capture = {
        .info = SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP |
@@ -37,61 +37,61 @@ static const struct snd_pcm_hardware acp62_pdm_hardware_capture = {
        .periods_max = CAPTURE_MAX_NUM_PERIODS,
 };
 
-static void acp62_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size,
+static void acp63_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size,
                                       u32 watermark_size, void __iomem *acp_base)
 {
-       acp62_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR);
-       acp62_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE);
-       acp62_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
-       acp62_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL);
+       acp63_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR);
+       acp63_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE);
+       acp63_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+       acp63_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL);
 }
 
-static void acp62_enable_pdm_clock(void __iomem *acp_base)
+static void acp63_enable_pdm_clock(void __iomem *acp_base)
 {
        u32 pdm_clk_enable, pdm_ctrl;
 
        pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK;
        pdm_ctrl = 0x00;
 
-       acp62_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
-       pdm_ctrl = acp62_readl(acp_base + ACP_WOV_MISC_CTRL);
+       acp63_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
+       pdm_ctrl = acp63_readl(acp_base + ACP_WOV_MISC_CTRL);
        pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
-       acp62_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
+       acp63_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
 }
 
-static void acp62_enable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_enable_pdm_interrupts(void __iomem *acp_base)
 {
        u32 ext_int_ctrl;
 
-       ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+       ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
        ext_int_ctrl |= PDM_DMA_INTR_MASK;
-       acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+       acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
 }
 
-static void acp62_disable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_disable_pdm_interrupts(void __iomem *acp_base)
 {
        u32 ext_int_ctrl;
 
-       ext_int_ctrl = acp62_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+       ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
        ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
-       acp62_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+       acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
 }
 
-static bool acp62_check_pdm_dma_status(void __iomem *acp_base)
+static bool acp63_check_pdm_dma_status(void __iomem *acp_base)
 {
        bool pdm_dma_status;
        u32 pdm_enable, pdm_dma_enable;
 
        pdm_dma_status = false;
-       pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE);
-       pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+       pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE);
+       pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
        if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & ACP_PDM_DMA_EN_STATUS))
                pdm_dma_status = true;
 
        return pdm_dma_status;
 }
 
-static int acp62_start_pdm_dma(void __iomem *acp_base)
+static int acp63_start_pdm_dma(void __iomem *acp_base)
 {
        u32 pdm_enable;
        u32 pdm_dma_enable;
@@ -100,12 +100,12 @@ static int acp62_start_pdm_dma(void __iomem *acp_base)
        pdm_enable = 0x01;
        pdm_dma_enable  = 0x01;
 
-       acp62_enable_pdm_clock(acp_base);
-       acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
-       acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+       acp63_enable_pdm_clock(acp_base);
+       acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
+       acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
        timeout = 0;
        while (++timeout < ACP_COUNTER) {
-               pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+               pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
                if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS)
                        return 0;
                udelay(DELAY_US);
@@ -113,7 +113,7 @@ static int acp62_start_pdm_dma(void __iomem *acp_base)
        return -ETIMEDOUT;
 }
 
-static int acp62_stop_pdm_dma(void __iomem *acp_base)
+static int acp63_stop_pdm_dma(void __iomem *acp_base)
 {
        u32 pdm_enable, pdm_dma_enable;
        int timeout;
@@ -121,14 +121,14 @@ static int acp62_stop_pdm_dma(void __iomem *acp_base)
        pdm_enable = 0x00;
        pdm_dma_enable  = 0x00;
 
-       pdm_enable = acp62_readl(acp_base + ACP_WOV_PDM_ENABLE);
-       pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+       pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE);
+       pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
        if (pdm_dma_enable & 0x01) {
                pdm_dma_enable = 0x02;
-               acp62_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
+               acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE);
                timeout = 0;
                while (++timeout < ACP_COUNTER) {
-                       pdm_dma_enable = acp62_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
+                       pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE);
                        if ((pdm_dma_enable & 0x02) == 0x00)
                                break;
                        udelay(DELAY_US);
@@ -138,13 +138,13 @@ static int acp62_stop_pdm_dma(void __iomem *acp_base)
        }
        if (pdm_enable == ACP_PDM_ENABLE) {
                pdm_enable = ACP_PDM_DISABLE;
-               acp62_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
+               acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE);
        }
-       acp62_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
+       acp63_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH);
        return 0;
 }
 
-static void acp62_config_dma(struct pdm_stream_instance *rtd, int direction)
+static void acp63_config_dma(struct pdm_stream_instance *rtd, int direction)
 {
        u16 page_idx;
        u32 low, high, val;
@@ -154,24 +154,24 @@ static void acp62_config_dma(struct pdm_stream_instance *rtd, int direction)
        val = PDM_PTE_OFFSET;
 
        /* Group Enable */
-       acp62_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp62_base +
+       acp63_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp63_base +
                     ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
-       acp62_writel(PAGE_SIZE_4K_ENABLE, rtd->acp62_base +
+       acp63_writel(PAGE_SIZE_4K_ENABLE, rtd->acp63_base +
                     ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
        for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
                /* Load the low address of page int ACP SRAM through SRBM */
                low = lower_32_bits(addr);
                high = upper_32_bits(addr);
 
-               acp62_writel(low, rtd->acp62_base + ACP_SCRATCH_REG_0 + val);
+               acp63_writel(low, rtd->acp63_base + ACP_SCRATCH_REG_0 + val);
                high |= BIT(31);
-               acp62_writel(high, rtd->acp62_base + ACP_SCRATCH_REG_0 + val + 4);
+               acp63_writel(high, rtd->acp63_base + ACP_SCRATCH_REG_0 + val + 4);
                val += 8;
                addr += PAGE_SIZE;
        }
 }
 
-static int acp62_pdm_dma_open(struct snd_soc_component *component,
+static int acp63_pdm_dma_open(struct snd_soc_component *component,
                              struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
@@ -186,7 +186,7 @@ static int acp62_pdm_dma_open(struct snd_soc_component *component,
                return -EINVAL;
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               runtime->hw = acp62_pdm_hardware_capture;
+               runtime->hw = acp63_pdm_hardware_capture;
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
@@ -196,17 +196,17 @@ static int acp62_pdm_dma_open(struct snd_soc_component *component,
                return ret;
        }
 
-       acp62_enable_pdm_interrupts(adata->acp62_base);
+       acp63_enable_pdm_interrupts(adata->acp63_base);
 
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                adata->capture_stream = substream;
 
-       pdm_data->acp62_base = adata->acp62_base;
+       pdm_data->acp63_base = adata->acp63_base;
        runtime->private_data = pdm_data;
        return ret;
 }
 
-static int acp62_pdm_dma_hw_params(struct snd_soc_component *component,
+static int acp63_pdm_dma_hw_params(struct snd_soc_component *component,
                                   struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params)
 {
@@ -220,26 +220,26 @@ static int acp62_pdm_dma_hw_params(struct snd_soc_component *component,
        period_bytes = params_period_bytes(params);
        rtd->dma_addr = substream->runtime->dma_addr;
        rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
-       acp62_config_dma(rtd, substream->stream);
-       acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size,
-                                  period_bytes, rtd->acp62_base);
+       acp63_config_dma(rtd, substream->stream);
+       acp63_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, size,
+                                  period_bytes, rtd->acp63_base);
        return 0;
 }
 
-static u64 acp62_pdm_get_byte_count(struct pdm_stream_instance *rtd,
+static u64 acp63_pdm_get_byte_count(struct pdm_stream_instance *rtd,
                                    int direction)
 {
        u32 high, low;
        u64 byte_count;
 
-       high = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
+       high = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
        byte_count = high;
-       low = acp62_readl(rtd->acp62_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
+       low = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
        byte_count = (byte_count << 32) | low;
        return byte_count;
 }
 
-static snd_pcm_uframes_t acp62_pdm_dma_pointer(struct snd_soc_component *comp,
+static snd_pcm_uframes_t acp63_pdm_dma_pointer(struct snd_soc_component *comp,
                                               struct snd_pcm_substream *stream)
 {
        struct pdm_stream_instance *rtd;
@@ -249,14 +249,14 @@ static snd_pcm_uframes_t acp62_pdm_dma_pointer(struct snd_soc_component *comp,
        rtd = stream->runtime->private_data;
        buffersize = frames_to_bytes(stream->runtime,
                                     stream->runtime->buffer_size);
-       bytescount = acp62_pdm_get_byte_count(rtd, stream->stream);
+       bytescount = acp63_pdm_get_byte_count(rtd, stream->stream);
        if (bytescount > rtd->bytescount)
                bytescount -= rtd->bytescount;
        pos = do_div(bytescount, buffersize);
        return bytes_to_frames(stream->runtime, pos);
 }
 
-static int acp62_pdm_dma_new(struct snd_soc_component *component,
+static int acp63_pdm_dma_new(struct snd_soc_component *component,
                             struct snd_soc_pcm_runtime *rtd)
 {
        struct device *parent = component->dev->parent;
@@ -266,19 +266,19 @@ static int acp62_pdm_dma_new(struct snd_soc_component *component,
        return 0;
 }
 
-static int acp62_pdm_dma_close(struct snd_soc_component *component,
+static int acp63_pdm_dma_close(struct snd_soc_component *component,
                               struct snd_pcm_substream *substream)
 {
        struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       acp62_disable_pdm_interrupts(adata->acp62_base);
+       acp63_disable_pdm_interrupts(adata->acp63_base);
        adata->capture_stream = NULL;
        kfree(runtime->private_data);
        return 0;
 }
 
-static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
+static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream,
                                 int cmd, struct snd_soc_dai *dai)
 {
        struct pdm_stream_instance *rtd;
@@ -299,20 +299,20 @@ static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               acp62_writel(ch_mask, rtd->acp62_base + ACP_WOV_PDM_NO_OF_CHANNELS);
-               acp62_writel(PDM_DECIMATION_FACTOR, rtd->acp62_base +
+               acp63_writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+               acp63_writel(PDM_DECIMATION_FACTOR, rtd->acp63_base +
                             ACP_WOV_PDM_DECIMATION_FACTOR);
-               rtd->bytescount = acp62_pdm_get_byte_count(rtd, substream->stream);
-               pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base);
+               rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream);
+               pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
                if (!pdm_status)
-                       ret = acp62_start_pdm_dma(rtd->acp62_base);
+                       ret = acp63_start_pdm_dma(rtd->acp63_base);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pdm_status = acp62_check_pdm_dma_status(rtd->acp62_base);
+               pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base);
                if (pdm_status)
-                       ret = acp62_stop_pdm_dma(rtd->acp62_base);
+                       ret = acp63_stop_pdm_dma(rtd->acp63_base);
                break;
        default:
                ret = -EINVAL;
@@ -321,11 +321,11 @@ static int acp62_pdm_dai_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static const struct snd_soc_dai_ops acp62_pdm_dai_ops = {
-       .trigger   = acp62_pdm_dai_trigger,
+static const struct snd_soc_dai_ops acp63_pdm_dai_ops = {
+       .trigger   = acp63_pdm_dai_trigger,
 };
 
-static struct snd_soc_dai_driver acp62_pdm_dai_driver = {
+static struct snd_soc_dai_driver acp63_pdm_dai_driver = {
        .name = "acp_ps_pdm_dma.0",
        .capture = {
                .rates = SNDRV_PCM_RATE_48000,
@@ -335,19 +335,19 @@ static struct snd_soc_dai_driver acp62_pdm_dai_driver = {
                .rate_min = 48000,
                .rate_max = 48000,
        },
-       .ops = &acp62_pdm_dai_ops,
+       .ops = &acp63_pdm_dai_ops,
 };
 
-static const struct snd_soc_component_driver acp62_pdm_component = {
+static const struct snd_soc_component_driver acp63_pdm_component = {
        .name           = DRV_NAME,
-       .open           = acp62_pdm_dma_open,
-       .close          = acp62_pdm_dma_close,
-       .hw_params      = acp62_pdm_dma_hw_params,
-       .pointer        = acp62_pdm_dma_pointer,
-       .pcm_construct  = acp62_pdm_dma_new,
+       .open           = acp63_pdm_dma_open,
+       .close          = acp63_pdm_dma_close,
+       .hw_params      = acp63_pdm_dma_hw_params,
+       .pointer        = acp63_pdm_dma_pointer,
+       .pcm_construct  = acp63_pdm_dma_new,
 };
 
-static int acp62_pdm_audio_probe(struct platform_device *pdev)
+static int acp63_pdm_audio_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct pdm_dev_data *adata;
@@ -363,16 +363,16 @@ static int acp62_pdm_audio_probe(struct platform_device *pdev)
        if (!adata)
                return -ENOMEM;
 
-       adata->acp62_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!adata->acp62_base)
+       adata->acp63_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!adata->acp63_base)
                return -ENOMEM;
 
        adata->capture_stream = NULL;
 
        dev_set_drvdata(&pdev->dev, adata);
        status = devm_snd_soc_register_component(&pdev->dev,
-                                                &acp62_pdm_component,
-                                                &acp62_pdm_dai_driver, 1);
+                                                &acp63_pdm_component,
+                                                &acp63_pdm_dai_driver, 1);
        if (status) {
                dev_err(&pdev->dev, "Fail to register acp pdm dai\n");
 
@@ -385,13 +385,13 @@ static int acp62_pdm_audio_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int acp62_pdm_audio_remove(struct platform_device *pdev)
+static int acp63_pdm_audio_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
        return 0;
 }
 
-static int __maybe_unused acp62_pdm_resume(struct device *dev)
+static int __maybe_unused acp63_pdm_resume(struct device *dev)
 {
        struct pdm_dev_data *adata;
        struct snd_pcm_runtime *runtime;
@@ -404,47 +404,47 @@ static int __maybe_unused acp62_pdm_resume(struct device *dev)
                rtd = runtime->private_data;
                period_bytes = frames_to_bytes(runtime, runtime->period_size);
                buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
-               acp62_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
-               acp62_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
-                                          period_bytes, adata->acp62_base);
+               acp63_config_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+               acp63_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
+                                          period_bytes, adata->acp63_base);
        }
-       acp62_enable_pdm_interrupts(adata->acp62_base);
+       acp63_enable_pdm_interrupts(adata->acp63_base);
        return 0;
 }
 
-static int __maybe_unused acp62_pdm_suspend(struct device *dev)
+static int __maybe_unused acp63_pdm_suspend(struct device *dev)
 {
        struct pdm_dev_data *adata;
 
        adata = dev_get_drvdata(dev);
-       acp62_disable_pdm_interrupts(adata->acp62_base);
+       acp63_disable_pdm_interrupts(adata->acp63_base);
        return 0;
 }
 
-static int __maybe_unused acp62_pdm_runtime_resume(struct device *dev)
+static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev)
 {
        struct pdm_dev_data *adata;
 
        adata = dev_get_drvdata(dev);
-       acp62_enable_pdm_interrupts(adata->acp62_base);
+       acp63_enable_pdm_interrupts(adata->acp63_base);
        return 0;
 }
 
-static const struct dev_pm_ops acp62_pdm_pm_ops = {
-       SET_RUNTIME_PM_OPS(acp62_pdm_suspend, acp62_pdm_runtime_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(acp62_pdm_suspend, acp62_pdm_resume)
+static const struct dev_pm_ops acp63_pdm_pm_ops = {
+       SET_RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume)
 };
 
-static struct platform_driver acp62_pdm_dma_driver = {
-       .probe = acp62_pdm_audio_probe,
-       .remove = acp62_pdm_audio_remove,
+static struct platform_driver acp63_pdm_dma_driver = {
+       .probe = acp63_pdm_audio_probe,
+       .remove = acp63_pdm_audio_remove,
        .driver = {
                .name = "acp_ps_pdm_dma",
-               .pm = &acp62_pdm_pm_ops,
+               .pm = &acp63_pdm_pm_ops,
        },
 };
 
-module_platform_driver(acp62_pdm_dma_driver);
+module_platform_driver(acp63_pdm_dma_driver);
 
 MODULE_AUTHOR("Syed.SabaKareem@amd.com");
 MODULE_DESCRIPTION("AMD PINK SARDINE PDM Driver");
index ab2d7a7..dc96a6f 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/spinlock.h>
 
 #include <sound/asoundef.h>
@@ -175,6 +176,7 @@ static const struct regmap_config mchp_spdiftx_regmap_config = {
        .readable_reg = mchp_spdiftx_readable_reg,
        .writeable_reg = mchp_spdiftx_writeable_reg,
        .precious_reg = mchp_spdiftx_precious_reg,
+       .cache_type = REGCACHE_FLAT,
 };
 
 #define SPDIFTX_GCLK_RATIO     128
@@ -196,7 +198,7 @@ struct mchp_spdiftx_dev {
        struct clk                              *pclk;
        struct clk                              *gclk;
        unsigned int                            fmt;
-       unsigned int                            gclk_enabled:1;
+       unsigned int                            suspend_irq;
 };
 
 static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev)
@@ -317,16 +319,25 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd,
        running = !!(mr & SPDIFTX_MR_TXEN_ENABLE);
 
        switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
+               regmap_write(dev->regmap, SPDIFTX_IER, dev->suspend_irq |
+                            SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
+               dev->suspend_irq = 0;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (!running) {
                        mr &= ~SPDIFTX_MR_TXEN_MASK;
                        mr |= SPDIFTX_MR_TXEN_ENABLE;
                }
                break;
-       case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               regmap_read(dev->regmap, SPDIFTX_IMR, &dev->suspend_irq);
+               fallthrough;
+       case SNDRV_PCM_TRIGGER_STOP:
+               regmap_write(dev->regmap, SPDIFTX_IDR, dev->suspend_irq |
+                            SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                if (running) {
                        mr &= ~SPDIFTX_MR_TXEN_MASK;
@@ -355,6 +366,7 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
        struct mchp_spdiftx_mixer_control *ctrl = &dev->control;
        u32 mr;
        unsigned int bps = params_physical_width(params) / 8;
+       unsigned char aes3;
        int ret;
 
        dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
@@ -440,55 +452,54 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
 
        mr |= SPDIFTX_MR_BPS(bps);
 
-       spin_lock_irqsave(&ctrl->lock, flags);
-       ctrl->ch_stat[3] &= ~IEC958_AES3_CON_FS;
        switch (params_rate(params)) {
        case 22050:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_22050;
+               aes3 = IEC958_AES3_CON_FS_22050;
                break;
        case 24000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_24000;
+               aes3 = IEC958_AES3_CON_FS_24000;
                break;
        case 32000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_32000;
+               aes3 = IEC958_AES3_CON_FS_32000;
                break;
        case 44100:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_44100;
+               aes3 = IEC958_AES3_CON_FS_44100;
                break;
        case 48000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_48000;
+               aes3 = IEC958_AES3_CON_FS_48000;
                break;
        case 88200:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_88200;
+               aes3 = IEC958_AES3_CON_FS_88200;
                break;
        case 96000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_96000;
+               aes3 = IEC958_AES3_CON_FS_96000;
                break;
        case 176400:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_176400;
+               aes3 = IEC958_AES3_CON_FS_176400;
                break;
        case 192000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_192000;
+               aes3 = IEC958_AES3_CON_FS_192000;
                break;
        case 8000:
        case 11025:
        case 16000:
        case 64000:
-               ctrl->ch_stat[3] |= IEC958_AES3_CON_FS_NOTID;
+               aes3 = IEC958_AES3_CON_FS_NOTID;
                break;
        default:
                dev_err(dev->dev, "unsupported sample frequency: %u\n",
                        params_rate(params));
-               spin_unlock_irqrestore(&ctrl->lock, flags);
                return -EINVAL;
        }
+       spin_lock_irqsave(&ctrl->lock, flags);
+       ctrl->ch_stat[3] &= ~IEC958_AES3_CON_FS;
+       ctrl->ch_stat[3] |= aes3;
        mchp_spdiftx_channel_status_write(dev);
        spin_unlock_irqrestore(&ctrl->lock, flags);
 
-       if (dev->gclk_enabled) {
-               clk_disable_unprepare(dev->gclk);
-               dev->gclk_enabled = 0;
-       }
+       /* GCLK is enabled by runtime PM. */
+       clk_disable_unprepare(dev->gclk);
+
        ret = clk_set_rate(dev->gclk, params_rate(params) *
                                      SPDIFTX_GCLK_RATIO);
        if (ret) {
@@ -502,14 +513,10 @@ static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
                dev_err(dev->dev, "unable to enable gclk: %d\n", ret);
                return ret;
        }
-       dev->gclk_enabled = 1;
+
        dev_dbg(dev->dev, "%s(): GCLK set to %d\n", __func__,
                params_rate(params) * SPDIFTX_GCLK_RATIO);
 
-       /* Enable interrupts */
-       regmap_write(dev->regmap, SPDIFTX_IER,
-                    SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
-
        regmap_write(dev->regmap, SPDIFTX_MR, mr);
 
        return 0;
@@ -520,13 +527,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream,
 {
        struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
 
-       regmap_write(dev->regmap, SPDIFTX_IDR,
-                    SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR);
-       if (dev->gclk_enabled) {
-               clk_disable_unprepare(dev->gclk);
-               dev->gclk_enabled = 0;
-       }
-
        return regmap_write(dev->regmap, SPDIFTX_CR,
                            SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR);
 }
@@ -708,17 +708,9 @@ static struct snd_kcontrol_new mchp_spdiftx_ctrls[] = {
 static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
 {
        struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
-       int ret;
 
        snd_soc_dai_init_dma_data(dai, &dev->playback, NULL);
 
-       ret = clk_prepare_enable(dev->pclk);
-       if (ret) {
-               dev_err(dev->dev,
-                       "failed to enable the peripheral clock: %d\n", ret);
-               return ret;
-       }
-
        /* Add controls */
        snd_soc_add_dai_controls(dai, mchp_spdiftx_ctrls,
                                 ARRAY_SIZE(mchp_spdiftx_ctrls));
@@ -726,19 +718,9 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
-static int mchp_spdiftx_dai_remove(struct snd_soc_dai *dai)
-{
-       struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       clk_disable_unprepare(dev->pclk);
-
-       return 0;
-}
-
 static struct snd_soc_dai_driver mchp_spdiftx_dai = {
        .name = "mchp-spdiftx",
        .probe  = mchp_spdiftx_dai_probe,
-       .remove = mchp_spdiftx_dai_remove,
        .playback = {
                .stream_name = "S/PDIF Playback",
                .channels_min = 1,
@@ -762,6 +744,55 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids);
 
+static int mchp_spdiftx_runtime_suspend(struct device *dev)
+{
+       struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev);
+
+       regcache_cache_only(spdiftx->regmap, true);
+
+       clk_disable_unprepare(spdiftx->gclk);
+       clk_disable_unprepare(spdiftx->pclk);
+
+       return 0;
+}
+
+static int mchp_spdiftx_runtime_resume(struct device *dev)
+{
+       struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(spdiftx->pclk);
+       if (ret) {
+               dev_err(spdiftx->dev,
+                       "failed to enable the peripheral clock: %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(spdiftx->gclk);
+       if (ret) {
+               dev_err(spdiftx->dev,
+                       "failed to enable generic clock: %d\n", ret);
+               goto disable_pclk;
+       }
+
+       regcache_cache_only(spdiftx->regmap, false);
+       regcache_mark_dirty(spdiftx->regmap);
+       ret = regcache_sync(spdiftx->regmap);
+       if (ret) {
+               regcache_cache_only(spdiftx->regmap, true);
+               clk_disable_unprepare(spdiftx->gclk);
+disable_pclk:
+               clk_disable_unprepare(spdiftx->pclk);
+       }
+
+       return ret;
+}
+
+static const struct dev_pm_ops mchp_spdiftx_pm_ops = {
+       SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+       RUNTIME_PM_OPS(mchp_spdiftx_runtime_suspend, mchp_spdiftx_runtime_resume,
+                      NULL)
+};
+
 static int mchp_spdiftx_probe(struct platform_device *pdev)
 {
        struct mchp_spdiftx_dev *dev;
@@ -826,29 +857,59 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
        dev->regmap = regmap;
        platform_set_drvdata(pdev, dev);
 
+       pm_runtime_enable(dev->dev);
+       if (!pm_runtime_enabled(dev->dev)) {
+               err = mchp_spdiftx_runtime_resume(dev->dev);
+               if (err)
+                       return err;
+       }
+
        dev->playback.addr = (dma_addr_t)mem->start + SPDIFTX_CDR;
        dev->playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
        if (err) {
                dev_err(&pdev->dev, "failed to register PMC: %d\n", err);
-               return err;
+               goto pm_runtime_suspend;
        }
 
        err = devm_snd_soc_register_component(&pdev->dev,
                                              &mchp_spdiftx_component,
                                              &mchp_spdiftx_dai, 1);
-       if (err)
+       if (err) {
                dev_err(&pdev->dev, "failed to register component: %d\n", err);
+               goto pm_runtime_suspend;
+       }
+
+       return 0;
+
+pm_runtime_suspend:
+       if (!pm_runtime_status_suspended(dev->dev))
+               mchp_spdiftx_runtime_suspend(dev->dev);
+       pm_runtime_disable(dev->dev);
 
        return err;
 }
 
+static int mchp_spdiftx_remove(struct platform_device *pdev)
+{
+       struct mchp_spdiftx_dev *dev = platform_get_drvdata(pdev);
+
+       if (!pm_runtime_status_suspended(dev->dev))
+               mchp_spdiftx_runtime_suspend(dev->dev);
+
+       pm_runtime_disable(dev->dev);
+
+       return 0;
+}
+
 static struct platform_driver mchp_spdiftx_driver = {
        .probe  = mchp_spdiftx_probe,
+       .remove = mchp_spdiftx_remove,
        .driver = {
                .name   = "mchp_spdiftx",
                .of_match_table = of_match_ptr(mchp_spdiftx_dt_ids),
+               .pm = pm_ptr(&mchp_spdiftx_pm_ops)
        },
 };
 
index 7022e62..0f9d714 100644 (file)
@@ -199,6 +199,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_RT715_SDCA_SDW
        imply SND_SOC_RT1308_SDW
        imply SND_SOC_RT1316_SDW
+       imply SND_SOC_RT1318_SDW
        imply SND_SOC_RT9120
        imply SND_SOC_SDW_MOCKUP
        imply SND_SOC_SGTL5000
@@ -348,7 +349,7 @@ config SND_SOC_WM_HUBS
 
 config SND_SOC_WM_ADSP
        tristate
-       select CS_DSP
+       select FW_CS_DSP
        select SND_SOC_COMPRESS
        default y if SND_SOC_MADERA=y
        default y if SND_SOC_CS47L24=y
@@ -1311,6 +1312,11 @@ config SND_SOC_RT1316_SDW
        depends on SOUNDWIRE
        select REGMAP_SOUNDWIRE
 
+config SND_SOC_RT1318_SDW
+       tristate "Realtek RT1318 Codec - SDW"
+       depends on SOUNDWIRE
+       select REGMAP_SOUNDWIRE
+
 config SND_SOC_RT5514
        tristate
        depends on I2C
@@ -1930,7 +1936,7 @@ config SND_SOC_WM8960
        depends on I2C
 
 config SND_SOC_WM8961
-       tristate
+       tristate "Wolfson Microelectronics WM8961 CODEC"
        depends on I2C
 
 config SND_SOC_WM8962
index 9170ee1..71d3ce5 100644 (file)
@@ -196,6 +196,7 @@ snd-soc-rt1305-objs := rt1305.o
 snd-soc-rt1308-objs := rt1308.o
 snd-soc-rt1308-sdw-objs := rt1308-sdw.o
 snd-soc-rt1316-sdw-objs := rt1316-sdw.o
+snd-soc-rt1318-sdw-objs := rt1318-sdw.o
 snd-soc-rt274-objs := rt274.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt298-objs := rt298.o
@@ -551,6 +552,7 @@ obj-$(CONFIG_SND_SOC_RT1305)        += snd-soc-rt1305.o
 obj-$(CONFIG_SND_SOC_RT1308)   += snd-soc-rt1308.o
 obj-$(CONFIG_SND_SOC_RT1308_SDW)       += snd-soc-rt1308-sdw.o
 obj-$(CONFIG_SND_SOC_RT1316_SDW)       += snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318_SDW)       += snd-soc-rt1318-sdw.o
 obj-$(CONFIG_SND_SOC_RT274)    += snd-soc-rt274.o
 obj-$(CONFIG_SND_SOC_RT286)    += snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)    += snd-soc-rt298.o
index c5e0f10..d9bde7e 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
-#include <linux/gcd.h>
 #include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 7f832d0..37e178e 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include <linux/gcd.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
index c0f44ec..634d4db 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <linux/gcd.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
index 1db7355..8c69c8c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
@@ -46,6 +47,7 @@ struct ak4458_priv {
        struct device *dev;
        struct regmap *regmap;
        struct gpio_desc *reset_gpiod;
+       struct reset_control *reset;
        struct gpio_desc *mute_gpiod;
        int digfil;     /* SSLOW, SD, SLOW bits */
        int fs;         /* sampling rate */
@@ -633,6 +635,12 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
        if (ak4458->reset_gpiod) {
                gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
                usleep_range(1000, 2000);
+       } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+               if (active)
+                       reset_control_assert(ak4458->reset);
+               else
+                       reset_control_deassert(ak4458->reset);
+               usleep_range(1000, 2000);
        }
 }
 
@@ -668,7 +676,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
        if (ak4458->mute_gpiod)
                gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
 
-       ak4458_reset(ak4458, true);
        ak4458_reset(ak4458, false);
 
        regcache_cache_only(ak4458->regmap, false);
@@ -748,6 +755,10 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
 
        ak4458->drvdata = of_device_get_match_data(&i2c->dev);
 
+       ak4458->reset = devm_reset_control_get_optional_shared(ak4458->dev, NULL);
+       if (IS_ERR(ak4458->reset))
+               return PTR_ERR(ak4458->reset);
+
        ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
                                                      GPIOD_OUT_LOW);
        if (IS_ERR(ak4458->reset_gpiod))
index 31ae752..a078dd4 100644 (file)
@@ -918,8 +918,8 @@ static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                fs1 = CS35L36_FS1_DEFAULT_VAL;
                fs2 = CS35L36_FS2_DEFAULT_VAL;
        } else {
-               fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
-               fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4;
+               fs1 = 3 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
+               fs2 = 5 * DIV_ROUND_UP(CS35L36_FS_NOM_6MHZ * 4, freq) + 4;
        }
 
        regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL,
index f90d439..37629eb 100644 (file)
@@ -145,7 +145,7 @@ static const struct reg_default cs42l83_reg_defaults[] = {
  * This is all the same as for CS42L42 but we
  * replace the on-reset register defaults.
  */
-const struct regmap_config cs42l83_regmap = {
+static const struct regmap_config cs42l83_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index bd80e9f..052ffb7 100644 (file)
 
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
 
 #include "cs42xx8.h"
 
+static const struct of_device_id cs42xx8_of_match[];
+
 static int cs42xx8_i2c_probe(struct i2c_client *i2c)
 {
-       int ret = cs42xx8_probe(&i2c->dev,
-                       devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+       int ret;
+       struct cs42xx8_driver_data *drvdata;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(cs42xx8_of_match, &i2c->dev);
+       if (!of_id) {
+               dev_err(&i2c->dev, "failed to find driver data\n");
+               return -EINVAL;
+       }
+
+       drvdata = (struct cs42xx8_driver_data *)of_id->data;
+
+       ret = cs42xx8_probe(&i2c->dev,
+               devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config), drvdata);
        if (ret)
                return ret;
 
@@ -35,7 +50,14 @@ static void cs42xx8_i2c_remove(struct i2c_client *i2c)
        pm_runtime_disable(&i2c->dev);
 }
 
-static struct i2c_device_id cs42xx8_i2c_id[] = {
+static const struct of_device_id cs42xx8_of_match[] = {
+       { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+       { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+
+static const struct i2c_device_id cs42xx8_i2c_id[] = {
        {"cs42448", (kernel_ulong_t)&cs42448_data},
        {"cs42888", (kernel_ulong_t)&cs42888_data},
        {}
index d14eb2f..4558ec3 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
@@ -511,17 +510,8 @@ const struct cs42xx8_driver_data cs42888_data = {
 };
 EXPORT_SYMBOL_GPL(cs42888_data);
 
-const struct of_device_id cs42xx8_of_match[] = {
-       { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
-       { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
-EXPORT_SYMBOL_GPL(cs42xx8_of_match);
-
-int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)
 {
-       const struct of_device_id *of_id;
        struct cs42xx8_priv *cs42xx8;
        int ret, val, i;
 
@@ -535,17 +525,11 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
        if (cs42xx8 == NULL)
                return -ENOMEM;
 
-       cs42xx8->regmap = regmap;
        dev_set_drvdata(dev, cs42xx8);
 
-       of_id = of_match_device(cs42xx8_of_match, dev);
-       if (of_id)
-               cs42xx8->drvdata = of_id->data;
+       cs42xx8->regmap = regmap;
 
-       if (!cs42xx8->drvdata) {
-               dev_err(dev, "failed to find driver data\n");
-               return -EINVAL;
-       }
+       cs42xx8->drvdata = drvdata;
 
        cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
                                                        GPIOD_OUT_HIGH);
index d36c61b..342389e 100644 (file)
@@ -22,8 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm;
 extern const struct cs42xx8_driver_data cs42448_data;
 extern const struct cs42xx8_driver_data cs42888_data;
 extern const struct regmap_config cs42xx8_regmap_config;
-extern const struct of_device_id cs42xx8_of_match[];
-int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata);
 
 /* CS42888 register map */
 #define CS42XX8_CHIPID                         0x01    /* Chip ID */
index bba73c4..9bf8d73 100644 (file)
@@ -43,7 +43,6 @@ void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jac
                            DA7219_ACCDET_EN_MASK,
                            (jack ? DA7219_ACCDET_EN_MASK : 0));
 }
-EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
 
 /*
  * Button/HPTest work
@@ -930,7 +929,6 @@ int da7219_aad_init(struct snd_soc_component *component)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(da7219_aad_init);
 
 void da7219_aad_exit(struct snd_soc_component *component)
 {
@@ -948,7 +946,6 @@ void da7219_aad_exit(struct snd_soc_component *component)
        cancel_work_sync(&da7219_aad->btn_det_work);
        cancel_work_sync(&da7219_aad->hptest_work);
 }
-EXPORT_SYMBOL_GPL(da7219_aad_exit);
 
 /*
  * AAD related I2C probe handling
@@ -972,7 +969,6 @@ int da7219_aad_probe(struct i2c_client *i2c)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(da7219_aad_probe);
 
 MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
index 4746c87..7468ee4 100644 (file)
@@ -2633,11 +2633,20 @@ static int da7219_resume(struct snd_soc_component *component)
 #define da7219_resume NULL
 #endif
 
+static int da7219_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack,
+                          void *data)
+{
+       da7219_aad_jack_det(component, jack);
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver soc_component_dev_da7219 = {
        .probe                  = da7219_probe,
        .remove                 = da7219_remove,
        .suspend                = da7219_suspend,
        .resume                 = da7219_resume,
+       .set_jack               = da7219_set_jack,
        .set_bias_level         = da7219_set_bias_level,
        .controls               = da7219_snd_controls,
        .num_controls           = ARRAY_SIZE(da7219_snd_controls),
index 87c1cc1..9ddf6a3 100755 (executable)
@@ -814,8 +814,7 @@ static const struct snd_soc_component_driver soc_component_dev_es8326 = {
        .endianness             = 1,
 };
 
-static int es8326_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static int es8326_i2c_probe(struct i2c_client *i2c)
 {
        struct es8326_priv *es8326;
        int ret;
@@ -895,7 +894,7 @@ static struct i2c_driver es8326_i2c_driver = {
                .acpi_match_table = ACPI_PTR(es8326_acpi_match),
                .of_match_table = of_match_ptr(es8326_of_match),
        },
-       .probe = es8326_i2c_probe,
+       .probe_new = es8326_i2c_probe,
        .id_table = es8326_i2c_id,
 };
 module_i2c_driver(es8326_i2c_driver);
index 61e8e9b..4b8ec6f 100644 (file)
@@ -130,10 +130,8 @@ static void hda_codec_unregister_dais(struct hda_codec *codec,
                        if (strcmp(dai->driver->name, pcm->name))
                                continue;
 
-                       if (dai->playback_widget)
-                               snd_soc_dapm_free_widget(dai->playback_widget);
-                       if (dai->capture_widget)
-                               snd_soc_dapm_free_widget(dai->capture_widget);
+                       snd_soc_dapm_free_widget(dai->playback_widget);
+                       snd_soc_dapm_free_widget(dai->capture_widget);
                        snd_soc_unregister_dai(dai);
                        break;
                }
@@ -181,7 +179,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
                !pm_runtime_status_suspended(&hdev->dev));
 #endif
 
-       hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+       hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
        if (!hlink) {
                dev_err(&hdev->dev, "hdac link not found\n");
                return -EIO;
@@ -213,7 +211,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
 
        patch = (hda_codec_patch_t)codec->preset->driver_data;
        if (!patch) {
-               dev_err(&hdev->dev, "no patch specified?\n");
+               dev_err(&hdev->dev, "no patch specified\n");
                ret = -EINVAL;
                goto err;
        }
@@ -289,7 +287,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
        if (hda_codec_is_display(codec))
                snd_hdac_display_power(bus, hdev->addr, false);
 
-       hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+       hlink = snd_hdac_ext_bus_get_hlink_by_addr(bus, hdev->addr);
        if (hlink)
                snd_hdac_ext_bus_link_put(bus, hlink);
        /*
index 8af434e..be66853 100644 (file)
@@ -400,7 +400,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
        hda_codec_patch_t patch;
        int ret;
 
-       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+       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");
                return -EIO;
@@ -516,7 +516,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
        struct hda_codec *codec = hda_pvt->codec;
        struct hdac_ext_link *hlink = NULL;
 
-       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+       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");
                return;
@@ -584,7 +584,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
        int ret;
 
        /* hold the ref while we probe */
-       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+       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");
                return -EIO;
index cb23650..ed4f7cd 100644 (file)
@@ -1967,7 +1967,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
         * hold the ref while we probe, also no need to drop the ref on
         * exit, we call pm_runtime_suspend() so that will do for us
         */
-       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+       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");
                return -EIO;
@@ -2144,7 +2144,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
        const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
 
        /* hold the ref while we probe */
-       hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+       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");
                return -EIO;
@@ -2244,7 +2244,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
        snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
                                                        AC_PWRST_D3);
 
-       hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+       hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
        if (!hlink) {
                dev_err(dev, "hdac link not found\n");
                return -EIO;
@@ -2270,7 +2270,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
        if (!bus)
                return 0;
 
-       hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+       hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, dev_name(dev));
        if (!hlink) {
                dev_err(dev, "hdac link not found\n");
                return -EIO;
index 71ea576..39cebaa 100644 (file)
@@ -136,6 +136,24 @@ enum {
 #define REG_CGR3_GO1L_OFFSET           0
 #define REG_CGR3_GO1L_MASK             (0x1f << REG_CGR3_GO1L_OFFSET)
 
+#define REG_CGR4_GO2R_OFFSET           0
+#define REG_CGR4_GO2R_MASK             (0x1f << REG_CGR4_GO2R_OFFSET)
+
+#define REG_CGR5_GO2L_OFFSET           0
+#define REG_CGR5_GO2L_MASK             (0x1f << REG_CGR5_GO2L_OFFSET)
+
+#define REG_CGR6_GO3R_OFFSET           0
+#define REG_CGR6_GO3R_MASK             (0x1f << REG_CGR6_GO3R_OFFSET)
+
+#define REG_CGR7_GO3L_OFFSET           0
+#define REG_CGR7_GO3L_MASK             (0x1f << REG_CGR7_GO3L_OFFSET)
+
+#define REG_CGR8_GOR_OFFSET            0
+#define REG_CGR8_GOR_MASK              (0x1f << REG_CGR8_GOR_OFFSET)
+
+#define REG_CGR9_GOL_OFFSET            0
+#define REG_CGR9_GOL_MASK              (0x1f << REG_CGR9_GOL_OFFSET)
+
 #define REG_CGR10_GIL_OFFSET           0
 #define REG_CGR10_GIR_OFFSET           4
 
@@ -147,9 +165,28 @@ struct jz_icdc {
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv,     0, 150, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv,
+        0, 11, TLV_DB_SCALE_ITEM(-2250,   0, 0),
+       12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv,
+        0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0),
+       12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0),
+       24, 31, TLV_DB_SCALE_ITEM(  100,  50, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
+
+static const char * const jz4725b_mic_mode_texts[] = {
+       "Single Ended", "Differential",
+};
+
+static const struct soc_enum jz4725b_mic_mode_enum =
+       SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET,
+                       2, jz4725b_mic_mode_texts);
 
 static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
-       SOC_DOUBLE_TLV("Master Playback Volume",
+       SOC_DOUBLE_TLV("DAC Playback Volume",
                       JZ4725B_CODEC_REG_CGR1,
                       REG_CGR1_GODL_OFFSET,
                       REG_CGR1_GODR_OFFSET,
@@ -159,8 +196,29 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
                       REG_CGR10_GIL_OFFSET,
                       REG_CGR10_GIR_OFFSET,
                       0xf, 0, jz4725b_adc_tlv),
-
-       SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
+       SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume",
+                        JZ4725B_CODEC_REG_CGR3,
+                        JZ4725B_CODEC_REG_CGR2,
+                        REG_CGR2_GO1R_OFFSET,
+                        0x1f, 1, jz4725b_mix_tlv),
+       SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume",
+                        JZ4725B_CODEC_REG_CGR5,
+                        JZ4725B_CODEC_REG_CGR4,
+                        REG_CGR4_GO2R_OFFSET,
+                        0x1f, 1, jz4725b_mix_tlv),
+       SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume",
+                        JZ4725B_CODEC_REG_CGR7,
+                        JZ4725B_CODEC_REG_CGR6,
+                        REG_CGR6_GO3R_OFFSET,
+                        0x1f, 1, jz4725b_mix_tlv),
+
+       SOC_DOUBLE_R_TLV("Master Playback Volume",
+                        JZ4725B_CODEC_REG_CGR9,
+                        JZ4725B_CODEC_REG_CGR8,
+                        REG_CGR8_GOR_OFFSET,
+                        0x1f, 1, jz4725b_out_tlv),
+
+       SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1,
                   REG_CR1_DAC_MUTE_OFFSET, 1, 1),
 
        SOC_SINGLE("Deemphasize Filter Playback Switch",
@@ -170,6 +228,13 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
        SOC_SINGLE("High-Pass Filter Capture Switch",
                   JZ4725B_CODEC_REG_CR2,
                   REG_CR2_ADC_HPF_OFFSET, 1, 0),
+
+       SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum),
+
+       SOC_SINGLE_TLV("Mic1 Boost Capture Volume",
+                      JZ4725B_CODEC_REG_PMR2,
+                      REG_PMR2_GIM_OFFSET,
+                      1, 0, jz4725b_mic_boost_tlv),
 };
 
 static const char * const jz4725b_codec_adc_src_texts[] = {
@@ -186,8 +251,12 @@ static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
        SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
 
 static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
+       SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1,
                        REG_CR1_BYPASS_OFFSET, 1, 0),
+       SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+                       REG_CR3_SIDETONE1_OFFSET, 1, 0),
+       SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
+                       REG_CR3_SIDETONE2_OFFSET, 1, 0),
 };
 
 static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
@@ -282,7 +351,9 @@ static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
        {"Line In", NULL, "LLINEIN"},
        {"Line In", NULL, "RLINEIN"},
 
-       {"Mixer", "Line In Bypass", "Line In"},
+       {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"},
+       {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"},
+       {"Mixer", "Line In Bypass Playback Switch", "Line In"},
        {"DAC to Mixer", NULL, "DAC"},
        {"Mixer", NULL, "DAC to Mixer"},
 
index ee15cf6..2ef62d6 100644 (file)
@@ -46,6 +46,7 @@
 #define CDC_TX_TOP_CSR_SWR_AMIC1_CTL   (0x00D4)
 #define CDC_TX_INP_MUX_ADC_MUXn_CFG0(n)        (0x0100 + 0x8 * n)
 #define CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK GENMASK(3, 0)
+#define CDC_TX_MACRO_DMIC_MUX_SEL_MASK GENMASK(7, 4)
 #define CDC_TX_INP_MUX_ADC_MUX0_CFG0   (0x0100)
 #define CDC_TX_INP_MUX_ADC_MUXn_CFG1(n)        (0x0104 + 0x8 * n)
 #define CDC_TX_INP_MUX_ADC_MUX0_CFG1   (0x0104)
@@ -774,7 +775,10 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
        }
 
        if (val != 0) {
-               if (val < 5) {
+               if (widget->shift) { /* MSM DMIC */
+                       snd_soc_component_write_field(component, mic_sel_reg,
+                                                     CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+               } else if (val < 5) {
                        snd_soc_component_write_field(component, mic_sel_reg,
                                                      CDC_TXn_ADC_DMIC_SEL_MASK, 0);
                } else {
@@ -1272,6 +1276,52 @@ static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6"
 static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
                        snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
 
+static const char * const dmic_mux_text[] = {
+       "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
+       "DMIC4", "DMIC5", "DMIC6", "DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+                       4, dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(tx_dmic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+                       4, dmic_mux_text);
+
+static const struct snd_kcontrol_new tx_dmic0_mux = SOC_DAPM_ENUM_EXT("tx_dmic0", tx_dmic0_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic1_mux = SOC_DAPM_ENUM_EXT("tx_dmic1", tx_dmic1_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic2_mux = SOC_DAPM_ENUM_EXT("tx_dmic2", tx_dmic2_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic3_mux = SOC_DAPM_ENUM_EXT("tx_dmic3", tx_dmic3_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic4_mux = SOC_DAPM_ENUM_EXT("tx_dmic4", tx_dmic4_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic5_mux = SOC_DAPM_ENUM_EXT("tx_dmic5", tx_dmic5_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic6_mux = SOC_DAPM_ENUM_EXT("tx_dmic6", tx_dmic6_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_dmic7_mux = SOC_DAPM_ENUM_EXT("tx_dmic7", tx_dmic7_enum,
+                       snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
 static const char * const dec_mode_mux_text[] = {
        "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
 };
@@ -1380,6 +1430,15 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
        SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
 
+       SND_SOC_DAPM_MUX("TX DMIC MUX0", SND_SOC_NOPM, 4, 0, &tx_dmic0_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX1", SND_SOC_NOPM, 4, 0, &tx_dmic1_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX2", SND_SOC_NOPM, 4, 0, &tx_dmic2_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX3", SND_SOC_NOPM, 4, 0, &tx_dmic3_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX4", SND_SOC_NOPM, 4, 0, &tx_dmic4_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX5", SND_SOC_NOPM, 4, 0, &tx_dmic5_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX6", SND_SOC_NOPM, 4, 0, &tx_dmic6_mux),
+       SND_SOC_DAPM_MUX("TX DMIC MUX7", SND_SOC_NOPM, 4, 0, &tx_dmic7_mux),
+
        SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
        SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
        SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
@@ -1392,6 +1451,14 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
        SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
        SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+       SND_SOC_DAPM_INPUT("TX DMIC0"),
+       SND_SOC_DAPM_INPUT("TX DMIC1"),
+       SND_SOC_DAPM_INPUT("TX DMIC2"),
+       SND_SOC_DAPM_INPUT("TX DMIC3"),
+       SND_SOC_DAPM_INPUT("TX DMIC4"),
+       SND_SOC_DAPM_INPUT("TX DMIC5"),
+       SND_SOC_DAPM_INPUT("TX DMIC6"),
+       SND_SOC_DAPM_INPUT("TX DMIC7"),
 
        SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
                           TX_MACRO_DEC0, 0,
@@ -1495,6 +1562,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX DEC6 MUX", NULL, "TX_MCLK"},
        {"TX DEC7 MUX", NULL, "TX_MCLK"},
 
+       {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"},
+       {"TX DMIC MUX0", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX0", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX0", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX0", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX0", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX0", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX0", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
+
        {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
        {"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
@@ -1510,6 +1587,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
+       {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
+
        {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
        {"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
@@ -1525,6 +1612,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
+       {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
+
        {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
        {"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
@@ -1540,6 +1637,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
+       {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
+
        {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
        {"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
@@ -1555,6 +1662,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
+       {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
+
        {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
        {"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
@@ -1570,6 +1687,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
+       {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
+
        {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
        {"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
@@ -1585,6 +1712,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
+       {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
+
        {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
        {"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
@@ -1600,6 +1737,16 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
        {"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
        {"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
 
+       {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
+       {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
+       {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
+       {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
+       {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
+       {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
+       {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
+       {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
+       {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
+
        {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
        {"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
        {"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
index 5e0abef..5cfe96f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of_clk.h>
@@ -2350,14 +2351,15 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
 {
        struct device *dev = wsa->dev;
        const char *parent_clk_name;
-       const char *clk_name = "mclk";
        struct clk_hw *hw;
        struct clk_init_data init;
        int ret;
 
        parent_clk_name = __clk_get_name(wsa->npl);
 
-       init.name = clk_name;
+       init.name = "mclk";
+       of_property_read_string(dev_of_node(dev), "clock-output-names",
+                               &init.name);
        init.ops = &swclk_gate_ops;
        init.flags = 0;
        init.parent_names = &parent_clk_name;
index a7b6a23..db3de41 100644 (file)
@@ -1731,9 +1731,9 @@ static void max98396_supply_disable(void *r)
        regulator_disable((struct regulator *) r);
 }
 
-static int max98396_i2c_probe(struct i2c_client *i2c,
-                             const struct i2c_device_id *id)
+static int max98396_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        struct max98396_priv *max98396 = NULL;
        int i, ret, reg;
 
@@ -1907,7 +1907,7 @@ static struct i2c_driver max98396_i2c_driver = {
                .acpi_match_table = ACPI_PTR(max98396_acpi_match),
                .pm = &max98396_pm,
        },
-       .probe = max98396_i2c_probe,
+       .probe_new = max98396_i2c_probe,
        .id_table = max98396_i2c_id,
 };
 
index ad4dce9..1257426 100644 (file)
@@ -137,6 +137,7 @@ static int nau8315_platform_probe(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static const struct of_device_id nau8315_device_id[] = {
        { .compatible = "nuvoton,nau8315" },
+       { .compatible = "nuvoton,nau8318" },
        {}
 };
 MODULE_DEVICE_TABLE(of, nau8315_device_id);
@@ -145,6 +146,7 @@ MODULE_DEVICE_TABLE(of, nau8315_device_id);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id nau8315_acpi_match[] = {
        { "NVTN2010", 0 },
+       { "NVTN2012", 0},
        {},
 };
 MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match);
index 3eac7c9..4bffa9c 100644 (file)
@@ -1686,6 +1686,9 @@ static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
 
        /* Enable internal VCO needed for interruptions */
        nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+       /* Raise up the internal clock for jack detection */
+       regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+                          NAU8825_CLK_MCLK_SRC_MASK, 0);
 
        /* Enable ADC needed for interruptions */
        regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
@@ -1733,6 +1736,121 @@ static int nau8825_button_decode(int value)
        return buttons;
 }
 
+static int nau8825_high_imped_detection(struct nau8825 *nau8825)
+{
+       struct regmap *regmap = nau8825->regmap;
+       struct snd_soc_dapm_context *dapm = nau8825->dapm;
+       unsigned int adc_mg1, adc_mg2;
+
+       /* Initial phase */
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                          NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+                          NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2);
+       regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+                          NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+       regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0x6);
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                          NAU8825_MICBIAS_LOWNOISE_MASK | NAU8825_MICBIAS_VOLTAGE_MASK,
+                          NAU8825_MICBIAS_LOWNOISE_EN);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                          NAU8825_SAR_INPUT_MASK | NAU8825_SAR_TRACKING_GAIN_MASK |
+                          NAU8825_SAR_HV_SEL_MASK | NAU8825_SAR_RES_SEL_MASK |
+                          NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+                          NAU8825_SAR_HV_SEL_VDDMIC | NAU8825_SAR_RES_SEL_70K);
+
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+       snd_soc_dapm_force_enable_pin(dapm, "SAR");
+       snd_soc_dapm_sync(dapm);
+
+       /* Configure settings for first reading of SARADC */
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                          NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+                          NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND2);
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                          NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                          NAU8825_MICBIAS_JKR2);
+       regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg1);
+
+       /* Configure settings for second reading of SARADC */
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                          NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                          NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+                          NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+                          NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                          NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+                          NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1);
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                          NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                          NAU8825_MICBIAS_JKSLV);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                          NAU8825_SAR_INPUT_MASK, NAU8825_SAR_INPUT_JKSLV);
+       regmap_read(regmap, NAU8825_REG_SARDOUT_RAM_STATUS, &adc_mg2);
+
+       /* Disable phase */
+       snd_soc_dapm_disable_pin(dapm, "SAR");
+       snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+       snd_soc_dapm_sync(dapm);
+
+       regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                          NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_LOWNOISE_MASK |
+                          NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage);
+       regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                          NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 | NAU8825_SPKR_DWN1R |
+                          NAU8825_SPKR_DWN1L, NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2 |
+                          NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+       regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_1,
+                          NAU8825_TESTDACIN_MASK, NAU8825_TESTDACIN_GND);
+       regmap_write(regmap, NAU8825_REG_TRIM_SETTINGS, 0);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                          NAU8825_SAR_TRACKING_GAIN_MASK | NAU8825_SAR_HV_SEL_MASK,
+                          nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT);
+       regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                          NAU8825_SAR_COMPARE_TIME_MASK | NAU8825_SAR_SAMPLING_TIME_MASK,
+                          (nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT) |
+                          (nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT));
+       dev_dbg(nau8825->dev, "adc_mg1:%x, adc_mg2:%x\n", adc_mg1, adc_mg2);
+
+       /* Confirmation phase */
+       if (adc_mg1 > adc_mg2) {
+               dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n");
+
+               /* Unground MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                                  NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+                                  NAU8825_SPKR_ENGND2);
+               /* Attach 2kOhm Resistor from MICBIAS to MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                                  NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                                  NAU8825_MICBIAS_JKR2);
+               /* Attach SARADC to MICGND1 */
+               regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                                  NAU8825_SAR_INPUT_MASK,
+                                  NAU8825_SAR_INPUT_JKR2);
+       } else if (adc_mg1 < adc_mg2) {
+               dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
+
+               /* Unground MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+                                  NAU8825_SPKR_ENGND1 | NAU8825_SPKR_ENGND2,
+                                  NAU8825_SPKR_ENGND1);
+               /* Attach 2kOhm Resistor from MICBIAS to MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+                                  NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+                                  NAU8825_MICBIAS_JKSLV);
+               /* Attach SARADC to MICGND2 */
+               regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+                                  NAU8825_SAR_INPUT_MASK,
+                                  NAU8825_SAR_INPUT_JKSLV);
+       } else {
+               dev_err(nau8825->dev, "Jack broken.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nau8825_jack_insert(struct nau8825 *nau8825)
 {
        struct regmap *regmap = nau8825->regmap;
@@ -1794,12 +1912,23 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
                snd_soc_dapm_sync(dapm);
                break;
        case 3:
-               /* detect error case */
-               dev_err(nau8825->dev, "detection error; disable mic function\n");
-               type = SND_JACK_HEADPHONE;
+               /* Detection failure case */
+               dev_warn(nau8825->dev,
+                        "Detection failure. Try the manually mechanism for jack type checking.\n");
+               if (!nau8825_high_imped_detection(nau8825)) {
+                       type = SND_JACK_HEADSET;
+                       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+                       snd_soc_dapm_force_enable_pin(dapm, "SAR");
+                       snd_soc_dapm_sync(dapm);
+               } else
+                       type = SND_JACK_HEADPHONE;
                break;
        }
 
+       /* Update to the default divider of internal clock for power saving */
+       regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+                          NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+
        /* Leaving HPOL/R grounded after jack insert by default. They will be
         * ungrounded as part of the widget power up sequence at the beginning
         * of playback to reduce pop.
index d84191a..0c3a446 100644 (file)
 /* HSD_CTRL (0xc) */
 #define NAU8825_HSD_AUTO_MODE  (1 << 6)
 /* 0 - open, 1 - short to GND */
+#define NAU8825_SPKR_ENGND1    (1 << 3)
+#define NAU8825_SPKR_ENGND2    (1 << 2)
 #define NAU8825_SPKR_DWN1R     (1 << 1)
 #define NAU8825_SPKR_DWN1L     (1 << 0)
 
 #define NAU8825_SAR_INPUT_JKR2 (0 << 11)
 #define NAU8825_SAR_TRACKING_GAIN_SFT  8
 #define NAU8825_SAR_TRACKING_GAIN_MASK (0x7 << NAU8825_SAR_TRACKING_GAIN_SFT)
+#define NAU8825_SAR_HV_SEL_SFT         7
+#define NAU8825_SAR_HV_SEL_MASK                (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_MICBIAS     (0 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_HV_SEL_VDDMIC      (1 << NAU8825_SAR_HV_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SFT                4
+#define NAU8825_SAR_RES_SEL_MASK       (0x7 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_35K                (0 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_70K                (1 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_170K       (2 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_360K       (3 << NAU8825_SAR_RES_SEL_SFT)
+#define NAU8825_SAR_RES_SEL_SHORTED    (4 << NAU8825_SAR_RES_SEL_SFT)
 #define NAU8825_SAR_COMPARE_TIME_SFT   2
 #define NAU8825_SAR_COMPARE_TIME_MASK  (3 << 2)
 #define NAU8825_SAR_SAMPLING_TIME_SFT  0
 #define NAU8825_BIAS_VMID_SEL_SFT      4
 #define NAU8825_BIAS_VMID_SEL_MASK     (3 << NAU8825_BIAS_VMID_SEL_SFT)
 
+/* ANALOG_CONTROL_1 (0x69) */
+#define NAU8825_TESTDACIN_SFT          14
+#define NAU8825_TESTDACIN_MASK         (0x3 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_HIGH         (1 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_LOW          (2 << NAU8825_TESTDACIN_SFT)
+#define NAU8825_TESTDACIN_GND          (3 << NAU8825_TESTDACIN_SFT)
+
 /* ANALOG_CONTROL_2 (0x6a) */
 #define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12)
 #define NAU8825_DAC_CAPACITOR_MSB (1 << 1)
 /* MIC_BIAS (0x74) */
 #define NAU8825_MICBIAS_JKSLV  (1 << 14)
 #define NAU8825_MICBIAS_JKR2   (1 << 12)
+#define NAU8825_MICBIAS_LOWNOISE_SFT   10
+#define NAU8825_MICBIAS_LOWNOISE_MASK  (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
+#define NAU8825_MICBIAS_LOWNOISE_EN    (0x1 << NAU8825_MICBIAS_LOWNOISE_SFT)
 #define NAU8825_MICBIAS_POWERUP_SFT    8
 #define NAU8825_MICBIAS_VOLTAGE_SFT    0
 #define NAU8825_MICBIAS_VOLTAGE_MASK   0x7
index f99aed3..7f42482 100644 (file)
@@ -197,6 +197,17 @@ static void rt1308_apply_calib_params(struct rt1308_sdw_priv *rt1308)
                efuse_c_btl_l, efuse_c_btl_r);
 }
 
+static void rt1308_apply_bq_params(struct rt1308_sdw_priv *rt1308)
+{
+       unsigned int i, reg, data;
+
+       for (i = 0; i < rt1308->bq_params_cnt; i += 3) {
+               reg = rt1308->bq_params[i] | (rt1308->bq_params[i + 1] << 8);
+               data = rt1308->bq_params[i + 2];
+               regmap_write(rt1308->regmap, reg, data);
+       }
+}
+
 static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
 {
        struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
@@ -619,14 +630,42 @@ static const struct sdw_slave_ops rt1308_slave_ops = {
        .bus_config = rt1308_bus_config,
 };
 
+static int rt1308_sdw_parse_dt(struct rt1308_sdw_priv *rt1308, struct device *dev)
+{
+       int ret = 0;
+
+       device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1308->bq_params_cnt);
+       if (rt1308->bq_params_cnt) {
+               rt1308->bq_params = devm_kzalloc(dev, rt1308->bq_params_cnt, GFP_KERNEL);
+               if (!rt1308->bq_params) {
+                       dev_err(dev, "Could not allocate bq_params memory\n");
+                       ret = -ENOMEM;
+               } else {
+                       ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1308->bq_params, rt1308->bq_params_cnt);
+                       if (ret < 0)
+                               dev_err(dev, "Could not read list of realtek,bq-params\n");
+               }
+       }
+
+       dev_dbg(dev, "bq_params_cnt=%d\n", rt1308->bq_params_cnt);
+       return ret;
+}
+
 static int rt1308_sdw_component_probe(struct snd_soc_component *component)
 {
+       struct rt1308_sdw_priv *rt1308 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       rt1308->component = component;
+       rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
 
+       /* apply BQ params */
+       rt1308_apply_bq_params(rt1308);
+
        return 0;
 }
 
index 62ce277..1eaaef9 100644 (file)
@@ -166,6 +166,8 @@ struct rt1308_sdw_priv {
        int rx_mask;
        int slots;
        int hw_ver;
+       unsigned char *bq_params;
+       unsigned int bq_params_cnt;
 };
 
 struct sdw_stream_data {
index ed0a114..2db7ee6 100644 (file)
@@ -254,6 +254,17 @@ static int rt1316_read_prop(struct sdw_slave *slave)
        return 0;
 }
 
+static void rt1316_apply_bq_params(struct rt1316_sdw_priv *rt1316)
+{
+       unsigned int i, reg, data;
+
+       for (i = 0; i < rt1316->bq_params_cnt; i += 3) {
+               reg = rt1316->bq_params[i] | (rt1316->bq_params[i + 1] << 8);
+               data = rt1316->bq_params[i + 2];
+               regmap_write(rt1316->regmap, reg, data);
+       }
+}
+
 static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
 {
        struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
@@ -590,14 +601,42 @@ static struct sdw_slave_ops rt1316_slave_ops = {
        .update_status = rt1316_update_status,
 };
 
+static int rt1316_sdw_parse_dt(struct rt1316_sdw_priv *rt1316, struct device *dev)
+{
+       int ret = 0;
+
+       device_property_read_u32(dev, "realtek,bq-params-cnt", &rt1316->bq_params_cnt);
+       if (rt1316->bq_params_cnt) {
+               rt1316->bq_params = devm_kzalloc(dev, rt1316->bq_params_cnt, GFP_KERNEL);
+               if (!rt1316->bq_params) {
+                       dev_err(dev, "Could not allocate bq_params memory\n");
+                       ret = -ENOMEM;
+               } else {
+                       ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1316->bq_params, rt1316->bq_params_cnt);
+                       if (ret < 0)
+                               dev_err(dev, "Could not read list of realtek,bq-params\n");
+               }
+       }
+
+       dev_dbg(dev, "bq_params_cnt=%d\n", rt1316->bq_params_cnt);
+       return ret;
+}
+
 static int rt1316_sdw_component_probe(struct snd_soc_component *component)
 {
+       struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       rt1316->component = component;
+       rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
 
+       /* apply BQ params */
+       rt1316_apply_bq_params(rt1316);
+
        return 0;
 }
 
index cbcdaa8..57dbd49 100644 (file)
@@ -46,6 +46,8 @@ struct rt1316_sdw_priv {
        struct sdw_bus_params params;
        bool hw_init;
        bool first_hw_init;
+       unsigned char *bq_params;
+       unsigned int bq_params_cnt;
 };
 
 struct sdw_stream_data {
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
new file mode 100644 (file)
index 0000000..f85f5ab
--- /dev/null
@@ -0,0 +1,884 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318-sdw.c -- rt1318 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2022 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include "rt1318-sdw.h"
+
+static const struct reg_sequence rt1318_blind_write[] = {
+       { 0xc001, 0x43 },
+       { 0xc003, 0xa2 },
+       { 0xc004, 0x44 },
+       { 0xc005, 0x44 },
+       { 0xc006, 0x33 },
+       { 0xc007, 0x64 },
+       { 0xc320, 0x20 },
+       { 0xf203, 0x18 },
+       { 0xf211, 0x00 },
+       { 0xf212, 0x26 },
+       { 0xf20d, 0x17 },
+       { 0xf214, 0x06 },
+       { 0xf20e, 0x00 },
+       { 0xf223, 0x7f },
+       { 0xf224, 0xdb },
+       { 0xf225, 0xee },
+       { 0xf226, 0x3f },
+       { 0xf227, 0x0f },
+       { 0xf21a, 0x78 },
+       { 0xf242, 0x3c },
+       { 0xc321, 0x0b },
+       { 0xc200, 0xd8 },
+       { 0xc201, 0x27 },
+       { 0xc202, 0x0f },
+       { 0xf800, 0x20 },
+       { 0xdf00, 0x10 },
+       { 0xdf5f, 0x01 },
+       { 0xdf60, 0xa7 },
+       { 0xc400, 0x0e },
+       { 0xc401, 0x43 },
+       { 0xc402, 0xe0 },
+       { 0xc403, 0x00 },
+       { 0xc404, 0x4c },
+       { 0xc407, 0x02 },
+       { 0xc408, 0x3f },
+       { 0xc300, 0x01 },
+       { 0xc206, 0x78 },
+       { 0xc203, 0x84 },
+       { 0xc120, 0xc0 },
+       { 0xc121, 0x03 },
+       { 0xe000, 0x88 },
+       { 0xc321, 0x09 },
+       { 0xc322, 0x01 },
+       { 0xe706, 0x0f },
+       { 0xe707, 0x30 },
+       { 0xe806, 0x0f },
+       { 0xe807, 0x30 },
+       { 0xed00, 0xb0 },
+       { 0xce04, 0x02 },
+       { 0xce05, 0x63 },
+       { 0xce06, 0x68 },
+       { 0xce07, 0x07 },
+       { 0xcf04, 0x02 },
+       { 0xcf05, 0x63 },
+       { 0xcf06, 0x68 },
+       { 0xcf07, 0x07 },
+       { 0xce60, 0xe3 },
+       { 0xc130, 0x51 },
+       { 0xf102, 0x00 },
+       { 0xf103, 0x00 },
+       { 0xf104, 0xf5 },
+       { 0xf105, 0x06 },
+       { 0xf109, 0x9b },
+       { 0xf10a, 0x0b },
+       { 0xf10b, 0x4c },
+       { 0xf10b, 0x5c },
+       { 0xf102, 0x00 },
+       { 0xf103, 0x00 },
+       { 0xf104, 0xf5 },
+       { 0xf105, 0x0b },
+       { 0xf109, 0x03 },
+       { 0xf10a, 0x0b },
+       { 0xf10b, 0x4c },
+       { 0xf10b, 0x5c },
+       { 0xf102, 0x00 },
+       { 0xf103, 0x00 },
+       { 0xf104, 0xf5 },
+       { 0xf105, 0x0c },
+       { 0xf109, 0x7f },
+       { 0xf10a, 0x0b },
+       { 0xf10b, 0x4c },
+       { 0xf10b, 0x5c },
+
+       { 0xe604, 0x00 },
+       { 0xdb00, 0x0c },
+       { 0xdd00, 0x0c },
+       { 0xdc19, 0x00 },
+       { 0xdc1a, 0xff },
+       { 0xdc1b, 0xff },
+       { 0xdc1c, 0xff },
+       { 0xdc1d, 0x00 },
+       { 0xdc1e, 0x00 },
+       { 0xdc1f, 0x00 },
+       { 0xdc20, 0xff },
+       { 0xde19, 0x00 },
+       { 0xde1a, 0xff },
+       { 0xde1b, 0xff },
+       { 0xde1c, 0xff },
+       { 0xde1d, 0x00 },
+       { 0xde1e, 0x00 },
+       { 0xde1f, 0x00 },
+       { 0xde20, 0xff },
+       { 0xdb32, 0x00 },
+       { 0xdd32, 0x00 },
+       { 0xdb33, 0x0a },
+       { 0xdd33, 0x0a },
+       { 0xdb34, 0x1a },
+       { 0xdd34, 0x1a },
+       { 0xdb17, 0xef },
+       { 0xdd17, 0xef },
+       { 0xdba7, 0x00 },
+       { 0xdba8, 0x64 },
+       { 0xdda7, 0x00 },
+       { 0xdda8, 0x64 },
+       { 0xdb19, 0x40 },
+       { 0xdd19, 0x40 },
+       { 0xdb00, 0x4c },
+       { 0xdb01, 0x79 },
+       { 0xdd01, 0x79 },
+       { 0xdb04, 0x05 },
+       { 0xdb05, 0x03 },
+       { 0xdd04, 0x05 },
+       { 0xdd05, 0x03 },
+       { 0xdbbb, 0x09 },
+       { 0xdbbc, 0x30 },
+       { 0xdbbd, 0xf0 },
+       { 0xdbbe, 0xf1 },
+       { 0xddbb, 0x09 },
+       { 0xddbc, 0x30 },
+       { 0xddbd, 0xf0 },
+       { 0xddbe, 0xf1 },
+       { 0xdb01, 0x79 },
+       { 0xdd01, 0x79 },
+       { 0xdc52, 0xef },
+       { 0xde52, 0xef },
+       { 0x2f55, 0x22 },
+};
+
+static const struct reg_default rt1318_reg_defaults[] = {
+       { 0x3000, 0x00 },
+       { 0x3004, 0x01 },
+       { 0x3005, 0x23 },
+       { 0x3202, 0x00 },
+       { 0x3203, 0x01 },
+       { 0x3206, 0x00 },
+       { 0xc000, 0x00 },
+       { 0xc001, 0x43 },
+       { 0xc003, 0x22 },
+       { 0xc004, 0x44 },
+       { 0xc005, 0x44 },
+       { 0xc006, 0x33 },
+       { 0xc007, 0x64 },
+       { 0xc008, 0x05 },
+       { 0xc00a, 0xfc },
+       { 0xc00b, 0x0f },
+       { 0xc00c, 0x0e },
+       { 0xc00d, 0xef },
+       { 0xc00e, 0xe5 },
+       { 0xc00f, 0xff },
+       { 0xc120, 0xc0 },
+       { 0xc121, 0x00 },
+       { 0xc122, 0x00 },
+       { 0xc123, 0x14 },
+       { 0xc125, 0x00 },
+       { 0xc200, 0x00 },
+       { 0xc201, 0x00 },
+       { 0xc202, 0x00 },
+       { 0xc203, 0x04 },
+       { 0xc204, 0x00 },
+       { 0xc205, 0x00 },
+       { 0xc206, 0x68 },
+       { 0xc207, 0x70 },
+       { 0xc208, 0x00 },
+       { 0xc20a, 0x00 },
+       { 0xc20b, 0x01 },
+       { 0xc20c, 0x7f },
+       { 0xc20d, 0x01 },
+       { 0xc20e, 0x7f },
+       { 0xc300, 0x00 },
+       { 0xc301, 0x00 },
+       { 0xc303, 0x80 },
+       { 0xc320, 0x00 },
+       { 0xc321, 0x09 },
+       { 0xc322, 0x02 },
+       { 0xc410, 0x04 },
+       { 0xc430, 0x00 },
+       { 0xc431, 0x00 },
+       { 0xca00, 0x10 },
+       { 0xca01, 0x00 },
+       { 0xca02, 0x0b },
+       { 0xca10, 0x10 },
+       { 0xca11, 0x00 },
+       { 0xca12, 0x0b },
+       { 0xdd93, 0x00 },
+       { 0xdd94, 0x64 },
+       { 0xe300, 0xa0 },
+       { 0xed00, 0x80 },
+       { 0xed01, 0x0f },
+       { 0xed02, 0xff },
+       { 0xed03, 0x00 },
+       { 0xed04, 0x00 },
+       { 0xed05, 0x0f },
+       { 0xed06, 0xff },
+       { 0xf010, 0x10 },
+       { 0xf011, 0xec },
+       { 0xf012, 0x68 },
+       { 0xf013, 0x21 },
+       { 0xf800, 0x00 },
+       { 0xf801, 0x12 },
+       { 0xf802, 0xe0 },
+       { 0xf803, 0x2f },
+       { 0xf804, 0x00 },
+       { 0xf805, 0x00 },
+       { 0xf806, 0x07 },
+       { 0xf807, 0xff },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+};
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2f55:
+       case 0x3000:
+       case 0x3004 ... 0x3005:
+       case 0x3202 ... 0x3203:
+       case 0x3206:
+       case 0xc000 ... 0xc00f:
+       case 0xc120 ... 0xc125:
+       case 0xc200 ... 0xc20e:
+       case 0xc300 ... 0xc303:
+       case 0xc320 ... 0xc322:
+       case 0xc410:
+       case 0xc430 ... 0xc431:
+       case 0xca00 ... 0xca02:
+       case 0xca10 ... 0xca12:
+       case 0xcb00 ... 0xcb0b:
+       case 0xcc00 ... 0xcce5:
+       case 0xcd00 ... 0xcde5:
+       case 0xce00 ... 0xce6a:
+       case 0xcf00 ... 0xcf53:
+       case 0xd000 ... 0xd0cc:
+       case 0xd100 ... 0xd1b9:
+       case 0xdb00 ... 0xdc53:
+       case 0xdd00 ... 0xde53:
+       case 0xdf00 ... 0xdf6b:
+       case 0xe300:
+       case 0xeb00 ... 0xebcc:
+       case 0xec00 ... 0xecb9:
+       case 0xed00 ... 0xed06:
+       case 0xf010 ... 0xf014:
+       case 0xf800 ... 0xf807:
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2f55:
+       case 0x3000 ... 0x3001:
+       case 0xc000:
+       case 0xc301:
+       case 0xc410:
+       case 0xc430 ... 0xc431:
+       case 0xdb06:
+       case 0xdb12:
+       case 0xdb1d ... 0xdb1f:
+       case 0xdb35:
+       case 0xdb37:
+       case 0xdb8a ... 0xdb92:
+       case 0xdbc5 ... 0xdbc8:
+       case 0xdc2b ... 0xdc49:
+       case 0xdd0b:
+       case 0xdd12:
+       case 0xdd1d ... 0xdd1f:
+       case 0xdd35:
+       case 0xdd8a ... 0xdd92:
+       case 0xddc5 ... 0xddc8:
+       case 0xde2b ... 0xde44:
+       case 0xdf4a ... 0xdf55:
+       case 0xe224 ... 0xe23b:
+       case 0xea01:
+       case 0xebc5:
+       case 0xebc8:
+       case 0xebcb ... 0xebcc:
+       case 0xed03 ... 0xed06:
+       case 0xf010 ... 0xf014:
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config rt1318_sdw_regmap = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .readable_reg = rt1318_readable_register,
+       .volatile_reg = rt1318_volatile_register,
+       .max_register = 0x41081488,
+       .reg_defaults = rt1318_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+static int rt1318_read_prop(struct sdw_slave *slave)
+{
+       struct sdw_slave_prop *prop = &slave->prop;
+       int nval;
+       int i, j;
+       u32 bit;
+       unsigned long addr;
+       struct sdw_dpn_prop *dpn;
+
+       prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+       prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+       prop->is_sdca = true;
+
+       prop->paging_support = true;
+
+       /* first we need to allocate memory for set bits in port lists */
+       prop->source_ports = BIT(2);
+       prop->sink_ports = BIT(1);
+
+       nval = hweight32(prop->source_ports);
+       prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+               sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+       if (!prop->src_dpn_prop)
+               return -ENOMEM;
+
+       i = 0;
+       dpn = prop->src_dpn_prop;
+       addr = prop->source_ports;
+       for_each_set_bit(bit, &addr, 32) {
+               dpn[i].num = bit;
+               dpn[i].type = SDW_DPN_FULL;
+               dpn[i].simple_ch_prep_sm = true;
+               dpn[i].ch_prep_timeout = 10;
+               i++;
+       }
+
+       /* do this again for sink now */
+       nval = hweight32(prop->sink_ports);
+       prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+               sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+       if (!prop->sink_dpn_prop)
+               return -ENOMEM;
+
+       j = 0;
+       dpn = prop->sink_dpn_prop;
+       addr = prop->sink_ports;
+       for_each_set_bit(bit, &addr, 32) {
+               dpn[j].num = bit;
+               dpn[j].type = SDW_DPN_FULL;
+               dpn[j].simple_ch_prep_sm = true;
+               dpn[j].ch_prep_timeout = 10;
+               j++;
+       }
+
+       /* set the timeout values */
+       prop->clk_stop_timeout = 20;
+
+       return 0;
+}
+
+static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
+{
+       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+       if (rt1318->hw_init)
+               return 0;
+
+       if (rt1318->first_hw_init) {
+               regcache_cache_only(rt1318->regmap, false);
+               regcache_cache_bypass(rt1318->regmap, true);
+       } else {
+               /*
+                * PM runtime is only enabled when a Slave reports as Attached
+                */
+
+               /* set autosuspend parameters */
+               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+               pm_runtime_use_autosuspend(&slave->dev);
+
+               /* update count of parent 'active' children */
+               pm_runtime_set_active(&slave->dev);
+
+               /* make sure the device does not suspend immediately */
+               pm_runtime_mark_last_busy(&slave->dev);
+
+               pm_runtime_enable(&slave->dev);
+       }
+
+       pm_runtime_get_noresume(&slave->dev);
+
+       /* blind write */
+       regmap_multi_reg_write(rt1318->regmap, rt1318_blind_write,
+               ARRAY_SIZE(rt1318_blind_write));
+
+       if (rt1318->first_hw_init) {
+               regcache_cache_bypass(rt1318->regmap, false);
+               regcache_mark_dirty(rt1318->regmap);
+       }
+
+       /* Mark Slave initialization complete */
+       rt1318->first_hw_init = true;
+       rt1318->hw_init = true;
+
+       pm_runtime_mark_last_busy(&slave->dev);
+       pm_runtime_put_autosuspend(&slave->dev);
+
+       dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+       return 0;
+}
+
+static int rt1318_update_status(struct sdw_slave *slave,
+                                       enum sdw_slave_status status)
+{
+       struct  rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+       /* Update the status */
+       rt1318->status = status;
+
+       if (status == SDW_SLAVE_UNATTACHED)
+               rt1318->hw_init = false;
+
+       /*
+        * Perform initialization only if slave status is present and
+        * hw_init flag is false
+        */
+       if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED)
+               return 0;
+
+       /* perform I/O transfers required for Slave initialization */
+       return rt1318_io_init(&slave->dev, slave);
+}
+
+static int rt1318_classd_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 rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+       unsigned char ps0 = 0x0, ps3 = 0x3;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_write(rt1318->regmap,
+                       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+                               RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+                               ps0);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_write(rt1318->regmap,
+                       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
+                               RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
+                               ps3);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const char * const rt1318_rx_data_ch_select[] = {
+       "L,R",
+       "L,L",
+       "L,R",
+       "L,L+R",
+       "R,L",
+       "R,R",
+       "R,L+R",
+       "L+R,L",
+       "L+R,R",
+       "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1318_rx_data_ch_enum,
+       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
+       rt1318_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+
+       /* UDMPU Cluster Selection */
+       SOC_ENUM("RX Channel Select", rt1318_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1318_sto_dac =
+       SOC_DAPM_DOUBLE_R("Switch",
+               SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L),
+               SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R),
+               0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1318_sto_dac),
+
+       /* Output */
+       SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+               rt1318_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_OUTPUT("SPOL"),
+       SND_SOC_DAPM_OUTPUT("SPOR"),
+       /* Input */
+       SND_SOC_DAPM_PGA("FB Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SIGGEN("FB Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+       { "DAC", "Switch", "DP1RX" },
+       { "CLASS D", NULL, "DAC" },
+       { "SPOL", NULL, "CLASS D" },
+       { "SPOR", NULL, "CLASS D" },
+
+       { "FB Data", NULL, "FB Gen" },
+       { "DP2TX", NULL, "FB Data" },
+};
+
+static int rt1318_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+                               int direction)
+{
+       struct sdw_stream_data *stream;
+
+       if (!sdw_stream)
+               return 0;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+
+       stream->sdw_stream = sdw_stream;
+
+       /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               dai->playback_dma_data = stream;
+       else
+               dai->capture_dma_data = stream;
+
+       return 0;
+}
+
+static void rt1318_sdw_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct sdw_stream_data *stream;
+
+       stream = snd_soc_dai_get_dma_data(dai, substream);
+       snd_soc_dai_set_dma_data(dai, substream, NULL);
+       kfree(stream);
+}
+
+static int rt1318_sdw_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 rt1318_sdw_priv *rt1318 =
+               snd_soc_component_get_drvdata(component);
+       struct sdw_stream_config stream_config;
+       struct sdw_port_config port_config;
+       enum sdw_data_direction direction;
+       struct sdw_stream_data *stream;
+       int retval, port, num_channels, ch_mask;
+       unsigned int sampling_rate;
+
+       dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+       stream = snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!stream)
+               return -EINVAL;
+
+       if (!rt1318->sdw_slave)
+               return -EINVAL;
+
+       /* SoundWire specific configuration */
+       /* port 1 for playback */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               direction = SDW_DATA_DIR_RX;
+               port = 1;
+       } else {
+               direction = SDW_DATA_DIR_TX;
+               port = 2;
+       }
+
+       num_channels = params_channels(params);
+       ch_mask = (1 << num_channels) - 1;
+
+       stream_config.frame_rate = params_rate(params);
+       stream_config.ch_count = num_channels;
+       stream_config.bps = snd_pcm_format_width(params_format(params));
+       stream_config.direction = direction;
+
+       port_config.ch_mask = ch_mask;
+       port_config.num = port;
+
+       retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
+                               &port_config, 1, stream->sdw_stream);
+       if (retval) {
+               dev_err(dai->dev, "Unable to configure port\n");
+               return retval;
+       }
+
+       /* sampling rate configuration */
+       switch (params_rate(params)) {
+       case 16000:
+               sampling_rate = RT1318_SDCA_RATE_16000HZ;
+               break;
+       case 32000:
+               sampling_rate = RT1318_SDCA_RATE_32000HZ;
+               break;
+       case 44100:
+               sampling_rate = RT1318_SDCA_RATE_44100HZ;
+               break;
+       case 48000:
+               sampling_rate = RT1318_SDCA_RATE_48000HZ;
+               break;
+       case 96000:
+               sampling_rate = RT1318_SDCA_RATE_96000HZ;
+               break;
+       case 192000:
+               sampling_rate = RT1318_SDCA_RATE_192000HZ;
+               break;
+       default:
+               dev_err(component->dev, "Rate %d is not supported\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       /* set sampling frequency */
+       regmap_write(rt1318->regmap,
+               SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+               sampling_rate);
+
+       return 0;
+}
+
+static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt1318_sdw_priv *rt1318 =
+               snd_soc_component_get_drvdata(component);
+       struct sdw_stream_data *stream =
+               snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!rt1318->sdw_slave)
+               return -EINVAL;
+
+       sdw_stream_remove_slave(rt1318->sdw_slave, stream->sdw_stream);
+       return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static struct sdw_slave_ops rt1318_slave_ops = {
+       .read_prop = rt1318_read_prop,
+       .update_status = rt1318_update_status,
+};
+
+static int rt1318_sdw_component_probe(struct snd_soc_component *component)
+{
+       int ret;
+       struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+       rt1318->component = component;
+
+       ret = pm_runtime_resume(component->dev);
+       dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1318 = {
+       .probe = rt1318_sdw_component_probe,
+       .controls = rt1318_snd_controls,
+       .num_controls = ARRAY_SIZE(rt1318_snd_controls),
+       .dapm_widgets = rt1318_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+       .dapm_routes = rt1318_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+       .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+       .hw_params = rt1318_sdw_hw_params,
+       .hw_free        = rt1318_sdw_pcm_hw_free,
+       .set_stream     = rt1318_set_sdw_stream,
+       .shutdown       = rt1318_sdw_shutdown,
+};
+
+#define RT1318_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1318_sdw_dai[] = {
+       {
+               .name = "rt1318-aif",
+               .playback = {
+                       .stream_name = "DP1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT1318_STEREO_RATES,
+                       .formats = RT1318_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "DP2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT1318_STEREO_RATES,
+                       .formats = RT1318_FORMATS,
+               },
+               .ops = &rt1318_aif_dai_ops,
+       },
+};
+
+static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
+                               struct sdw_slave *slave)
+{
+       struct rt1318_sdw_priv *rt1318;
+       int ret;
+
+       rt1318 = devm_kzalloc(dev, sizeof(*rt1318), GFP_KERNEL);
+       if (!rt1318)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, rt1318);
+       rt1318->sdw_slave = slave;
+       rt1318->regmap = regmap;
+
+       /*
+        * Mark hw_init to false
+        * HW init will be performed when device reports present
+        */
+       rt1318->hw_init = false;
+       rt1318->first_hw_init = false;
+
+       ret =  devm_snd_soc_register_component(dev,
+                               &soc_component_sdw_rt1318,
+                               rt1318_sdw_dai,
+                               ARRAY_SIZE(rt1318_sdw_dai));
+
+       dev_dbg(&slave->dev, "%s\n", __func__);
+
+       return ret;
+}
+
+static int rt1318_sdw_probe(struct sdw_slave *slave,
+                               const struct sdw_device_id *id)
+{
+       struct regmap *regmap;
+
+       /* Regmap Initialization */
+       regmap = devm_regmap_init_sdw(slave, &rt1318_sdw_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return rt1318_sdw_init(&slave->dev, regmap, slave);
+}
+
+static int rt1318_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
+
+       if (rt1318->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
+static const struct sdw_device_id rt1318_id[] = {
+       SDW_SLAVE_ENTRY_EXT(0x025d, 0x1318, 0x3, 0x1, 0),
+       {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1318_id);
+
+static int __maybe_unused rt1318_dev_suspend(struct device *dev)
+{
+       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+
+       if (!rt1318->hw_init)
+               return 0;
+
+       regcache_cache_only(rt1318->regmap, true);
+       return 0;
+}
+
+#define RT1318_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1318_dev_resume(struct device *dev)
+{
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
+       unsigned long time;
+
+       if (!rt1318->first_hw_init)
+               return 0;
+
+       if (!slave->unattach_request)
+               goto regmap_sync;
+
+       time = wait_for_completion_timeout(&slave->initialization_complete,
+                               msecs_to_jiffies(RT1318_PROBE_TIMEOUT));
+       if (!time) {
+               dev_err(&slave->dev, "Initialization not complete, timed out\n");
+               return -ETIMEDOUT;
+       }
+
+regmap_sync:
+       slave->unattach_request = 0;
+       regcache_cache_only(rt1318->regmap, false);
+       regcache_sync(rt1318->regmap);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rt1318_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
+       SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1318_sdw_driver = {
+       .driver = {
+               .name = "rt1318-sdca",
+               .owner = THIS_MODULE,
+               .pm = &rt1318_pm,
+       },
+       .probe = rt1318_sdw_probe,
+       .remove = rt1318_sdw_remove,
+       .ops = &rt1318_slave_ops,
+       .id_table = rt1318_id,
+};
+module_sdw_driver(rt1318_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h
new file mode 100644 (file)
index 0000000..4d7ac9c
--- /dev/null
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318-sdw.h -- RT1318 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2022 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1318_SDW_H__
+#define __RT1318_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* imp-defined registers */
+#define RT1318_SAPU_SM 0x3203
+
+#define R1318_TCON     0xc203
+#define R1318_TCON_RELATED_1   0xc206
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_0     0xdb00
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_4   0xdb08
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_4   0xdd08
+
+#define R1318_SPK_TEMPERATRUE_PROTECTION_L_6   0xdb12
+#define R1318_SPK_TEMPERATRUE_PROTECTION_R_6   0xdd12
+
+#define RT1318_INIT_RECIPROCAL_REG_L_24                0xdbb5
+#define RT1318_INIT_RECIPROCAL_REG_L_23_16     0xdbb6
+#define RT1318_INIT_RECIPROCAL_REG_L_15_8      0xdbb7
+#define RT1318_INIT_RECIPROCAL_REG_L_7_0       0xdbb8
+#define RT1318_INIT_RECIPROCAL_REG_R_24                0xddb5
+#define RT1318_INIT_RECIPROCAL_REG_R_23_16     0xddb6
+#define RT1318_INIT_RECIPROCAL_REG_R_15_8      0xddb7
+#define RT1318_INIT_RECIPROCAL_REG_R_7_0       0xddb8
+
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_24 0xdbc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_23_16 0xdbc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_15_8 0xdbc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_L_7_0 0xdbc8
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_24 0xddc5
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_23_16 0xddc6
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_15_8 0xddc7
+#define RT1318_INIT_R0_RECIPROCAL_SYN_R_7_0 0xddc8
+
+#define RT1318_R0_COMPARE_FLAG_L       0xdb35
+#define RT1318_R0_COMPARE_FLAG_R       0xdd35
+
+#define RT1318_STP_INITIAL_RS_TEMP_H 0xdd93
+#define RT1318_STP_INITIAL_RS_TEMP_L 0xdd94
+
+/* RT1318 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1318 SDCA entity */
+#define RT1318_SDCA_ENT_PDE23 0x31
+#define RT1318_SDCA_ENT_XU24 0x24
+#define RT1318_SDCA_ENT_FU21 0x03
+#define RT1318_SDCA_ENT_UDMPU21 0x02
+#define RT1318_SDCA_ENT_CS21 0x21
+#define RT1318_SDCA_ENT_SAPU 0x29
+
+/* RT1318 SDCA control */
+#define RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1318_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1318_SDCA_CTL_FU_MUTE 0x01
+#define RT1318_SDCA_CTL_FU_VOLUME 0x02
+#define RT1318_SDCA_CTL_UDMPU_CLUSTER 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+
+/* RT1318 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+
+/* sample frequency index */
+#define RT1318_SDCA_RATE_16000HZ               0x04
+#define RT1318_SDCA_RATE_32000HZ               0x07
+#define RT1318_SDCA_RATE_44100HZ               0x08
+#define RT1318_SDCA_RATE_48000HZ               0x09
+#define RT1318_SDCA_RATE_96000HZ               0x0b
+#define RT1318_SDCA_RATE_192000HZ              0x0d
+
+
+struct rt1318_sdw_priv {
+       struct snd_soc_component *component;
+       struct regmap *regmap;
+       struct sdw_slave *sdw_slave;
+       enum sdw_slave_status status;
+       struct sdw_bus_params params;
+       bool hw_init;
+       bool first_hw_init;
+};
+
+struct sdw_stream_data {
+       struct sdw_stream_runtime *sdw_stream;
+};
+
+#endif /* __RT1318_SDW_H__ */
index a2ce52d..cea26f3 100644 (file)
@@ -1166,6 +1166,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
                }
        },
+       {
+               .ident = "Intel Kabylake R RVP",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
+               }
+       },
        { }
 };
 
index 2df95e7..7e3eb65 100644 (file)
@@ -35,6 +35,8 @@ const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
        "AVDD",
        "MICVDD",
        "VBAT",
+       "DBVDD",
+       "LDO1-IN",
 };
 EXPORT_SYMBOL_GPL(rt5682_supply_names);
 
index 52ff0d9..d568c69 100644 (file)
@@ -1424,7 +1424,7 @@ enum {
        RT5682_CLK_SEL_I2S2_ASRC,
 };
 
-#define RT5682_NUM_SUPPLIES 3
+#define RT5682_NUM_SUPPLIES 5
 
 struct rt5682_priv {
        struct snd_soc_component *component;
index 80c673a..f5e5dbc 100644 (file)
@@ -44,6 +44,8 @@ static const struct rt5682s_platform_data i2s_default_platform_data = {
 static const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = {
        [RT5682S_SUPPLY_AVDD] = "AVDD",
        [RT5682S_SUPPLY_MICVDD] = "MICVDD",
+       [RT5682S_SUPPLY_DBVDD] = "DBVDD",
+       [RT5682S_SUPPLY_LDO1_IN] = "LDO1-IN",
 };
 
 static const struct reg_sequence patch_list[] = {
@@ -3089,6 +3091,14 @@ static void rt5682s_i2c_disable_regulators(void *data)
        if (ret)
                dev_err(dev, "Failed to disable supply AVDD: %d\n", ret);
 
+       ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+       if (ret)
+               dev_err(dev, "Failed to disable supply DBVDD: %d\n", ret);
+
+       ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+       if (ret)
+               dev_err(dev, "Failed to disable supply LDO1-IN: %d\n", ret);
+
        usleep_range(1000, 1500);
 
        ret = regulator_disable(rt5682s->supplies[RT5682S_SUPPLY_MICVDD].consumer);
@@ -3150,6 +3160,18 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
+       ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_DBVDD].consumer);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to enable supply DBVDD: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_enable(rt5682s->supplies[RT5682S_SUPPLY_LDO1_IN].consumer);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to enable supply LDO1-IN: %d\n", ret);
+               return ret;
+       }
+
        if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
                if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
                                          GPIOF_OUT_INIT_HIGH, "rt5682s"))
index 45464a0..67f86a3 100644 (file)
@@ -1438,6 +1438,8 @@ struct pll_calc_map {
 enum {
        RT5682S_SUPPLY_AVDD,
        RT5682S_SUPPLY_MICVDD,
+       RT5682S_SUPPLY_DBVDD,
+       RT5682S_SUPPLY_LDO1_IN,
        RT5682S_NUM_SUPPLIES,
 };
 
index d30c0d2..bf67de1 100644 (file)
@@ -55,6 +55,14 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
                                             e, NULL);
 }
 
+static unsigned int simple_mux_read(struct snd_soc_component *component,
+                                   unsigned int reg)
+{
+       struct simple_mux *priv = snd_soc_component_get_drvdata(component);
+
+       return priv->mux;
+}
+
 static const struct snd_kcontrol_new simple_mux_mux =
        SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
 
@@ -76,6 +84,7 @@ static const struct snd_soc_component_driver simple_mux_component_driver = {
        .num_dapm_widgets       = ARRAY_SIZE(simple_mux_dapm_widgets),
        .dapm_routes            = simple_mux_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(simple_mux_dapm_routes),
+       .read                   = simple_mux_read,
 };
 
 static int simple_mux_probe(struct platform_device *pdev)
index 43daa9d..2702603 100644 (file)
@@ -12,8 +12,7 @@
 
 #include "src4xxx.h"
 
-static int src4xxx_i2c_probe(struct i2c_client *i2c,
-                       const struct i2c_device_id *id)
+static int src4xxx_i2c_probe(struct i2c_client *i2c)
 {
        return src4xxx_probe(&i2c->dev,
                devm_regmap_init_i2c(i2c, &src4xxx_regmap_config), NULL);
@@ -37,7 +36,7 @@ static struct i2c_driver src4xxx_i2c_driver = {
                .name = "src4xxx",
                .of_match_table = of_match_ptr(src4xxx_of_match),
        },
-       .probe = src4xxx_i2c_probe,
+       .probe_new = src4xxx_i2c_probe,
        .id_table = src4xxx_i2c_ids,
 };
 module_i2c_driver(src4xxx_i2c_driver);
index a6db6f0..9e3108f 100644 (file)
@@ -598,8 +598,7 @@ static int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780)
        return 0;
 }
 
-static int tas2780_i2c_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int tas2780_i2c_probe(struct i2c_client *client)
 {
        struct tas2780_priv *tas2780;
        int result;
@@ -653,7 +652,7 @@ static struct i2c_driver tas2780_i2c_driver = {
                .name   = "tas2780",
                .of_match_table = of_match_ptr(tas2780_of_match),
        },
-       .probe  = tas2780_i2c_probe,
+       .probe_new  = tas2780_i2c_probe,
        .id_table   = tas2780_i2c_id,
 };
 module_i2c_driver(tas2780_i2c_driver);
index 0893880..56e795a 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -45,7 +45,6 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
-#include <sound/tlv320aic3x.h>
 
 #include "tlv320aic3x.h"
 
@@ -57,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
        "DRVDD",        /* ADC Analog and Output Driver Voltage */
 };
 
-static LIST_HEAD(reset_list);
-
 struct aic3x_priv;
 
 struct aic3x_disable_nb {
@@ -66,6 +63,10 @@ struct aic3x_disable_nb {
        struct aic3x_priv *aic3x;
 };
 
+struct aic3x_setup_data {
+       unsigned int gpio_func[2];
+};
+
 /* codec private data */
 struct aic3x_priv {
        struct snd_soc_component *component;
@@ -77,9 +78,9 @@ struct aic3x_priv {
        unsigned int dai_fmt;
        unsigned int tdm_delay;
        unsigned int slot_width;
-       struct list_head list;
        int master;
-       int gpio_reset;
+       struct gpio_desc *gpio_reset;
+       bool shared_reset;
        int power;
        u16 model;
 
@@ -1366,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb,
                 * Put codec to reset and require cache sync as at least one
                 * of the supplies was disabled
                 */
-               if (gpio_is_valid(aic3x->gpio_reset))
-                       gpio_set_value(aic3x->gpio_reset, 0);
+               if (aic3x->gpio_reset)
+                       gpiod_set_value(aic3x->gpio_reset, 1);
                regcache_mark_dirty(aic3x->regmap);
        }
 
@@ -1387,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
                        goto out;
                aic3x->power = 1;
 
-               if (gpio_is_valid(aic3x->gpio_reset)) {
+               if (aic3x->gpio_reset) {
                        udelay(1);
-                       gpio_set_value(aic3x->gpio_reset, 1);
+                       gpiod_set_value(aic3x->gpio_reset, 0);
                }
 
                /* Sync reg_cache with the hardware */
@@ -1595,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component)
        return 0;
 }
 
-static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
-{
-       struct aic3x_priv *a;
-
-       list_for_each_entry(a, &reset_list, list) {
-               if (gpio_is_valid(aic3x->gpio_reset) &&
-                   aic3x->gpio_reset == a->gpio_reset)
-                       return true;
-       }
-
-       return false;
-}
-
 static int aic3x_component_probe(struct snd_soc_component *component)
 {
        struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
@@ -1748,7 +1736,6 @@ static const struct reg_sequence aic3007_class_d[] = {
 
 int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
 {
-       struct aic3x_pdata *pdata = dev->platform_data;
        struct aic3x_priv *aic3x;
        struct aic3x_setup_data *ai3x_setup;
        struct device_node *np = dev->of_node;
@@ -1768,28 +1755,11 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
        regcache_cache_only(aic3x->regmap, true);
 
        dev_set_drvdata(dev, aic3x);
-       if (pdata) {
-               aic3x->gpio_reset = pdata->gpio_reset;
-               aic3x->setup = pdata->setup;
-               aic3x->micbias_vg = pdata->micbias_vg;
-       } else if (np) {
+       if (np) {
                ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL);
                if (!ai3x_setup)
                        return -ENOMEM;
 
-               ret = of_get_named_gpio(np, "reset-gpios", 0);
-               if (ret >= 0) {
-                       aic3x->gpio_reset = ret;
-               } else {
-                       ret = of_get_named_gpio(np, "gpio-reset", 0);
-                       if (ret > 0) {
-                               dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
-                               aic3x->gpio_reset = ret;
-                       } else {
-                               aic3x->gpio_reset = -1;
-                       }
-               }
-
                if (of_property_read_u32_array(np, "ai3x-gpio-func",
                                        ai3x_setup->gpio_func, 2) >= 0) {
                        aic3x->setup = ai3x_setup;
@@ -1814,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
                } else {
                        aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
                }
-
-       } else {
-               aic3x->gpio_reset = -1;
        }
 
        aic3x->model = driver_data;
 
-       if (gpio_is_valid(aic3x->gpio_reset) &&
-           !aic3x_is_shared_reset(aic3x)) {
-               ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
-               if (ret != 0)
-                       goto err;
-               gpio_direction_output(aic3x->gpio_reset, 0);
+       aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
+                                                   GPIOD_OUT_HIGH);
+       ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+       if (ret) {
+               if (ret != -EBUSY)
+                       return ret;
+
+               /*
+                * Apparently there are setups where the codec is sharing
+                * its reset line. Try to get it non-exclusively, although
+                * the utility of this is unclear: how do we make sure that
+                * resetting one chip will not disturb the others that share
+                * the same line?
+                */
+               aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
+                               GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+               ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+               if (ret)
+                       return ret;
+
+               aic3x->shared_reset = true;
        }
 
+       gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
+
        for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
                aic3x->supplies[i].supply = aic3x_supply_names[i];
 
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
                                      aic3x->supplies);
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to request supplies: %d\n", ret);
-               goto err_gpio;
+               return ret;
        }
 
        aic3x_configure_ocmv(dev, aic3x);
@@ -1845,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
                ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
                                            ARRAY_SIZE(aic3007_class_d));
                if (ret != 0)
-                       dev_err(dev, "Failed to init class D: %d\n",
-                               ret);
+                       dev_err(dev, "Failed to init class D: %d\n", ret);
        }
 
        ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
-
-       if (ret != 0)
-               goto err_gpio;
-
-       INIT_LIST_HEAD(&aic3x->list);
-       list_add(&aic3x->list, &reset_list);
+       if (ret)
+               return ret;
 
        return 0;
-
-err_gpio:
-       if (gpio_is_valid(aic3x->gpio_reset) &&
-           !aic3x_is_shared_reset(aic3x))
-               gpio_free(aic3x->gpio_reset);
-err:
-       return ret;
 }
 EXPORT_SYMBOL(aic3x_probe);
 
@@ -1872,13 +1844,9 @@ void aic3x_remove(struct device *dev)
 {
        struct aic3x_priv *aic3x = dev_get_drvdata(dev);
 
-       list_del(&aic3x->list);
-
-       if (gpio_is_valid(aic3x->gpio_reset) &&
-           !aic3x_is_shared_reset(aic3x)) {
-               gpio_set_value(aic3x->gpio_reset, 0);
-               gpio_free(aic3x->gpio_reset);
-       }
+       /* Leave the codec in reset state */
+       if (aic3x->gpio_reset && !aic3x->shared_reset)
+               gpiod_set_value(aic3x->gpio_reset, 1);
 }
 EXPORT_SYMBOL(aic3x_remove);
 
index 14298f9..066e5a6 100644 (file)
@@ -298,4 +298,47 @@ enum {
 #define AIC3X_BUTTON_DEBOUNCE_SHIFT    0
 #define AIC3X_BUTTON_DEBOUNCE_MASK     3
 
+/* GPIO API */
+enum {
+       AIC3X_GPIO1_FUNC_DISABLED               = 0,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
+       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
+       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
+       AIC3X_GPIO1_FUNC_INPUT                  = 8,
+       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
+       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
+       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
+       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
+};
+
+enum {
+       AIC3X_GPIO2_FUNC_DISABLED               = 0,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
+       AIC3X_GPIO2_FUNC_INPUT                  = 3,
+       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
+       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
+       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
+       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
+       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
+};
+
+enum aic3x_micbias_voltage {
+       AIC3X_MICBIAS_OFF = 0,
+       AIC3X_MICBIAS_2_0V = 1,
+       AIC3X_MICBIAS_2_5V = 2,
+       AIC3X_MICBIAS_AVDDV = 3,
+};
+
 #endif /* _AIC3X_H */
index e487682..9c50ac3 100644 (file)
@@ -700,8 +700,10 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
        struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
        struct twl4030_board_params *board_params = twl4030->board_params;
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
-       unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
-                                   8388608, 16777216, 33554432, 67108864};
+       static const unsigned int ramp_base[] = {
+               524288, 1048576, 2097152, 4194304,
+               8388608, 16777216, 33554432, 67108864
+       };
        unsigned int delay;
 
        hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
index 7dc6aaf..a485702 100644 (file)
@@ -971,9 +971,16 @@ static const struct i2c_device_id wm8961_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
 
+static const struct of_device_id wm8961_of_match[] __maybe_unused = {
+       { .compatible = "wlf,wm8961", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8961_of_match);
+
 static struct i2c_driver wm8961_i2c_driver = {
        .driver = {
                .name = "wm8961",
+               .of_match_table = of_match_ptr(wm8961_of_match),
        },
        .probe_new = wm8961_i2c_probe,
        .id_table = wm8961_i2c_id,
index a682f80..aa2f554 100644 (file)
@@ -498,7 +498,7 @@ static int wm8978_configure_pll(struct snd_soc_component *component)
 
                if (4 * f_opclk < 3 * f_mclk)
                        /* Have to use OPCLKDIV */
-                       opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+                       opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk);
                else
                        opclk_div = 1;
 
index 8a2e977..ea0dbc6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <sound/core.h>
@@ -419,16 +420,21 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
                (struct soc_bytes_ext *)kctl->private_value;
        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
        struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+       void *scratch;
        int ret = 0;
 
-       mutex_lock(&cs_ctl->dsp->pwr_lock);
+       scratch = vmalloc(size);
+       if (!scratch)
+               return -ENOMEM;
 
-       if (copy_from_user(cs_ctl->cache, bytes, size))
+       if (copy_from_user(scratch, bytes, size)) {
                ret = -EFAULT;
-       else
-               ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, cs_ctl->cache, size);
-
-       mutex_unlock(&cs_ctl->dsp->pwr_lock);
+       } else {
+               mutex_lock(&cs_ctl->dsp->pwr_lock);
+               ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, scratch, size);
+               mutex_unlock(&cs_ctl->dsp->pwr_lock);
+       }
+       vfree(scratch);
 
        return ret;
 }
@@ -455,7 +461,10 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
 
        mutex_unlock(&cs_ctl->dsp->pwr_lock);
 
-       return ret;
+       if (ret < 0)
+               return ret;
+
+       return 1;
 }
 
 static int wm_coeff_get(struct snd_kcontrol *kctl,
@@ -682,10 +691,10 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
        int ret;
 
        ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
-       if (ret)
+       if (ret < 0)
                return ret;
 
-       if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
+       if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS))
                return 0;
 
        ctl = cs_ctl->priv;
@@ -1035,6 +1044,16 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(wm_adsp_early_event);
 
+static int wm_adsp_pre_run(struct cs_dsp *cs_dsp)
+{
+       struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
+
+       if (!dsp->pre_run)
+               return 0;
+
+       return (*dsp->pre_run)(dsp);
+}
+
 static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp)
 {
        struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp);
@@ -2043,9 +2062,11 @@ static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
 static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
        .control_add = wm_adsp_control_add,
        .control_remove = wm_adsp_control_remove,
+       .pre_run = wm_adsp_pre_run,
        .post_run = wm_adsp_event_post_run,
        .post_stop = wm_adsp_event_post_stop,
        .watchdog_expired = wm_adsp_fatal_error,
 };
 
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(FW_CS_DSP);
index 375009a..dc2f7a0 100644 (file)
@@ -36,6 +36,7 @@ struct wm_adsp {
        int fw;
 
        struct work_struct boot_work;
+       int (*pre_run)(struct wm_adsp *dsp);
 
        bool preloaded;
        bool fatal_error;
index c7b10bb..966ba49 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -1380,22 +1380,19 @@ static int wsa883x_probe(struct sdw_slave *pdev,
                return -ENOMEM;
 
        wsa883x->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(wsa883x->vdd)) {
-               dev_err(dev, "No vdd regulator found\n");
-               return PTR_ERR(wsa883x->vdd);
-       }
+       if (IS_ERR(wsa883x->vdd))
+               return dev_err_probe(dev, PTR_ERR(wsa883x->vdd),
+                                    "No vdd regulator found\n");
 
        ret = regulator_enable(wsa883x->vdd);
-       if (ret) {
-               dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n");
 
        wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
-                                               GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+                                               GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH);
        if (IS_ERR(wsa883x->sd_n)) {
-               dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
-               ret = PTR_ERR(wsa883x->sd_n);
+               ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->sd_n),
+                                   "Shutdown Control GPIO not found\n");
                goto err;
        }
 
@@ -1411,12 +1408,13 @@ static int wsa883x_probe(struct sdw_slave *pdev,
        pdev->prop.simple_clk_stop_capable = true;
        pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
        pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
-       gpiod_direction_output(wsa883x->sd_n, 1);
+       gpiod_direction_output(wsa883x->sd_n, 0);
 
        wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
        if (IS_ERR(wsa883x->regmap)) {
-               dev_err(&pdev->dev, "regmap_init failed\n");
-               ret = PTR_ERR(wsa883x->regmap);
+               gpiod_direction_output(wsa883x->sd_n, 1);
+               ret = dev_err_probe(&pdev->dev, PTR_ERR(wsa883x->regmap),
+                                   "regmap_init failed\n");
                goto err;
        }
        pm_runtime_set_autosuspend_delay(dev, 3000);
index 79ef4e2..22e75c1 100644 (file)
@@ -47,11 +47,15 @@ struct fsl_micfil {
        struct clk *pll11k_clk;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct sdma_peripheral_config sdmacfg;
+       struct snd_soc_card *card;
        unsigned int dataline;
        char name[32];
        int irq[MICFIL_IRQ_LINES];
        enum quality quality;
        int dc_remover;
+       int vad_init_mode;
+       int vad_enabled;
+       int vad_detected;
 };
 
 struct fsl_micfil_soc_data {
@@ -59,6 +63,7 @@ struct fsl_micfil_soc_data {
        unsigned int fifo_depth;
        unsigned int dataline;
        bool imx;
+       bool use_edma;
        u64  formats;
 };
 
@@ -78,9 +83,19 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
        .formats = SNDRV_PCM_FMTBIT_S32_LE,
 };
 
+static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
+       .imx = true,
+       .fifos = 8,
+       .fifo_depth = 32,
+       .dataline =  0xf,
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .use_edma = true,
+};
+
 static const struct of_device_id fsl_micfil_dt_ids[] = {
        { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm },
        { .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp },
+       { .compatible = "fsl,imx93-micfil", .data = &fsl_micfil_imx93 },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids);
@@ -152,6 +167,152 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol,
        return micfil_set_quality(micfil);
 }
 
+static const char * const micfil_hwvad_enable[] = {
+       "Disable (Record only)",
+       "Enable (Record with Vad)",
+};
+
+static const char * const micfil_hwvad_init_mode[] = {
+       "Envelope mode", "Energy mode",
+};
+
+static const char * const micfil_hwvad_hpf_texts[] = {
+       "Filter bypass",
+       "Cut-off @1750Hz",
+       "Cut-off @215Hz",
+       "Cut-off @102Hz",
+};
+
+/*
+ * DC Remover Control
+ * Filter Bypassed     1 1
+ * Cut-off @21Hz       0 0
+ * Cut-off @83Hz       0 1
+ * Cut-off @152HZ      1 0
+ */
+static const char * const micfil_dc_remover_texts[] = {
+       "Cut-off @21Hz", "Cut-off @83Hz",
+       "Cut-off @152Hz", "Bypass",
+};
+
+static const struct soc_enum hwvad_enable_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_enable),
+                           micfil_hwvad_enable);
+static const struct soc_enum hwvad_init_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_init_mode),
+                           micfil_hwvad_init_mode);
+static const struct soc_enum hwvad_hpf_enum =
+       SOC_ENUM_SINGLE(REG_MICFIL_VAD0_CTRL2, 0,
+                       ARRAY_SIZE(micfil_hwvad_hpf_texts),
+                       micfil_hwvad_hpf_texts);
+static const struct soc_enum fsl_micfil_dc_remover_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_dc_remover_texts),
+                           micfil_dc_remover_texts);
+
+static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+       unsigned int *item = ucontrol->value.enumerated.item;
+       int val = snd_soc_enum_item_to_val(e, item[0]);
+       int i = 0, ret = 0;
+       u32 reg_val = 0;
+
+       if (val < 0 || val > 3)
+               return -EINVAL;
+
+       micfil->dc_remover = val;
+
+       /* Calculate total value for all channels */
+       for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
+               reg_val |= val << MICFIL_DC_CHX_SHIFT(i);
+
+       /* Update DC Remover mode for all channels */
+       ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL,
+                                           MICFIL_DC_CTRL_CONFIG, reg_val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = micfil->dc_remover;
+
+       return 0;
+}
+
+static int hwvad_put_enable(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+       int val = snd_soc_enum_item_to_val(e, item[0]);
+
+       micfil->vad_enabled = val;
+
+       return 0;
+}
+
+static int hwvad_get_enable(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = micfil->vad_enabled;
+
+       return 0;
+}
+
+static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+       int val = snd_soc_enum_item_to_val(e, item[0]);
+
+       /* 0 - Envelope-based Mode
+        * 1 - Energy-based Mode
+        */
+       micfil->vad_init_mode = val;
+
+       return 0;
+}
+
+static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = micfil->vad_init_mode;
+
+       return 0;
+}
+
+static int hwvad_detected(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = micfil->vad_detected;
+
+       return 0;
+}
+
 static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
        SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
                          MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
@@ -172,6 +333,27 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
        SOC_ENUM_EXT("MICFIL Quality Select",
                     fsl_micfil_quality_enum,
                     micfil_quality_get, micfil_quality_set),
+       SOC_ENUM_EXT("HWVAD Enablement Switch", hwvad_enable_enum,
+                    hwvad_get_enable, hwvad_put_enable),
+       SOC_ENUM_EXT("HWVAD Initialization Mode", hwvad_init_mode_enum,
+                    hwvad_get_init_mode, hwvad_put_init_mode),
+       SOC_ENUM("HWVAD High-Pass Filter", hwvad_hpf_enum),
+       SOC_SINGLE("HWVAD ZCD Switch", REG_MICFIL_VAD0_ZCD, 0, 1, 0),
+       SOC_SINGLE("HWVAD ZCD Auto Threshold Switch",
+                  REG_MICFIL_VAD0_ZCD, 2, 1, 0),
+       SOC_ENUM_EXT("MICFIL DC Remover Control", fsl_micfil_dc_remover_enum,
+                    micfil_get_dc_remover_state, micfil_put_dc_remover_state),
+       SOC_SINGLE("HWVAD Input Gain", REG_MICFIL_VAD0_CTRL2, 8, 15, 0),
+       SOC_SINGLE("HWVAD Sound Gain", REG_MICFIL_VAD0_SCONFIG, 0, 15, 0),
+       SOC_SINGLE("HWVAD Noise Gain", REG_MICFIL_VAD0_NCONFIG, 0, 15, 0),
+       SOC_SINGLE_RANGE("HWVAD Detector Frame Time", REG_MICFIL_VAD0_CTRL2, 16, 0, 63, 0),
+       SOC_SINGLE("HWVAD Detector Initialization Time", REG_MICFIL_VAD0_CTRL1, 8, 31, 0),
+       SOC_SINGLE("HWVAD Noise Filter Adjustment", REG_MICFIL_VAD0_NCONFIG, 8, 31, 0),
+       SOC_SINGLE("HWVAD ZCD Threshold", REG_MICFIL_VAD0_ZCD, 16, 1023, 0),
+       SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0),
+       SOC_SINGLE("HWVAD ZCD And Behavior Switch",
+                  REG_MICFIL_VAD0_ZCD, 4, 1, 0),
+       SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
 };
 
 /* The SRES is a self-negated bit which provides the CPU with the
@@ -210,6 +392,167 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
+/* Enable/disable hwvad interrupts */
+static int fsl_micfil_configure_hwvad_interrupts(struct fsl_micfil *micfil, int enable)
+{
+       u32 vadie_reg = enable ? MICFIL_VAD0_CTRL1_IE : 0;
+       u32 vaderie_reg = enable ? MICFIL_VAD0_CTRL1_ERIE : 0;
+
+       /* Voice Activity Detector Error Interruption */
+       regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                          MICFIL_VAD0_CTRL1_ERIE, vaderie_reg);
+
+       /* Voice Activity Detector Interruption */
+       regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                          MICFIL_VAD0_CTRL1_IE, vadie_reg);
+
+       return 0;
+}
+
+/* Configuration done only in energy-based initialization mode */
+static int fsl_micfil_init_hwvad_energy_mode(struct fsl_micfil *micfil)
+{
+       /* Keep the VADFRENDIS bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+                         MICFIL_VAD0_CTRL2_FRENDIS);
+
+       /* Keep the VADPREFEN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+                         MICFIL_VAD0_CTRL2_PREFEN);
+
+       /* Keep the VADSFILEN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+                         MICFIL_VAD0_SCONFIG_SFILEN);
+
+       /* Keep the VADSMAXEN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+                         MICFIL_VAD0_SCONFIG_SMAXEN);
+
+       /* Keep the VADNFILAUTO bitfield asserted. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                       MICFIL_VAD0_NCONFIG_NFILAUT);
+
+       /* Keep the VADNMINEN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                         MICFIL_VAD0_NCONFIG_NMINEN);
+
+       /* Keep the VADNDECEN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                         MICFIL_VAD0_NCONFIG_NDECEN);
+
+       /* Keep the VADNOREN bitfield cleared. */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                         MICFIL_VAD0_NCONFIG_NOREN);
+
+       return 0;
+}
+
+/* Configuration done only in envelope-based initialization mode */
+static int fsl_micfil_init_hwvad_envelope_mode(struct fsl_micfil *micfil)
+{
+       /* Assert the VADFRENDIS bitfield */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+                       MICFIL_VAD0_CTRL2_FRENDIS);
+
+       /* Assert the VADPREFEN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2,
+                       MICFIL_VAD0_CTRL2_PREFEN);
+
+       /* Assert the VADSFILEN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+                       MICFIL_VAD0_SCONFIG_SFILEN);
+
+       /* Assert the VADSMAXEN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG,
+                       MICFIL_VAD0_SCONFIG_SMAXEN);
+
+       /* Clear the VADNFILAUTO bitfield */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                         MICFIL_VAD0_NCONFIG_NFILAUT);
+
+       /* Assert the VADNMINEN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                       MICFIL_VAD0_NCONFIG_NMINEN);
+
+       /* Assert the VADNDECEN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                       MICFIL_VAD0_NCONFIG_NDECEN);
+
+       /* Assert VADNOREN bitfield. */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG,
+                       MICFIL_VAD0_NCONFIG_NOREN);
+
+       return 0;
+}
+
+/*
+ * Hardware Voice Active Detection: The HWVAD takes data from the input
+ * of a selected PDM microphone to detect if there is any
+ * voice activity. When a voice activity is detected, an interrupt could
+ * be delivered to the system. Initialization in section 8.4:
+ * Can work in two modes:
+ *  -> Eneveope-based mode (section 8.4.1)
+ *  -> Energy-based mode (section 8.4.2)
+ *
+ * It is important to remark that the HWVAD detector could be enabled
+ * or reset only when the MICFIL isn't running i.e. when the BSY_FIL
+ * bit in STAT register is cleared
+ */
+static int fsl_micfil_hwvad_enable(struct fsl_micfil *micfil)
+{
+       int ret;
+
+       micfil->vad_detected = 0;
+
+       /* envelope-based specific initialization */
+       if (micfil->vad_init_mode == MICFIL_HWVAD_ENVELOPE_MODE)
+               ret = fsl_micfil_init_hwvad_envelope_mode(micfil);
+       else
+               ret = fsl_micfil_init_hwvad_energy_mode(micfil);
+       if (ret)
+               return ret;
+
+       /* Voice Activity Detector Internal Filters Initialization*/
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                       MICFIL_VAD0_CTRL1_ST10);
+
+       /* Voice Activity Detector Internal Filter */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                         MICFIL_VAD0_CTRL1_ST10);
+
+       /* Enable Interrupts */
+       ret = fsl_micfil_configure_hwvad_interrupts(micfil, 1);
+       if (ret)
+               return ret;
+
+       /* Voice Activity Detector Reset */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                       MICFIL_VAD0_CTRL1_RST);
+
+       /* Voice Activity Detector Enabled */
+       regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                       MICFIL_VAD0_CTRL1_EN);
+
+       return 0;
+}
+
+static int fsl_micfil_hwvad_disable(struct fsl_micfil *micfil)
+{
+       struct device *dev = &micfil->pdev->dev;
+       int ret = 0;
+
+       /* Disable HWVAD */
+       regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                         MICFIL_VAD0_CTRL1_EN);
+
+       /* Disable hwvad interrupts */
+       ret = fsl_micfil_configure_hwvad_interrupts(micfil, 0);
+       if (ret)
+               dev_err(dev, "Failed to disable interrupts\n");
+
+       return ret;
+}
+
 static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
                              struct snd_soc_dai *dai)
 {
@@ -245,10 +588,16 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret)
                        return ret;
 
+               if (micfil->vad_enabled)
+                       fsl_micfil_hwvad_enable(micfil);
+
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (micfil->vad_enabled)
+                       fsl_micfil_hwvad_disable(micfil);
+
                /* Disable the module */
                ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1,
                                        MICFIL_CTRL1_PDMIEN);
@@ -328,11 +677,23 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
                                 FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
                                 FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr));
 
+       /* Configure CIC OSR in VADCICOSR */
+       regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                          MICFIL_VAD0_CTRL1_CICOSR,
+                          FIELD_PREP(MICFIL_VAD0_CTRL1_CICOSR, 16 - osr));
+
+       /* Configure source channel in VADCHSEL */
+       regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
+                          MICFIL_VAD0_CTRL1_CHSEL,
+                          FIELD_PREP(MICFIL_VAD0_CTRL1_CHSEL, (channels - 1)));
+
        micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg;
        micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg);
        micfil->sdmacfg.n_fifos_src = channels;
        micfil->sdmacfg.sw_done = true;
        micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX;
+       if (micfil->soc->use_edma)
+               micfil->dma_params_rx.maxburst = channels;
 
        return 0;
 }
@@ -351,6 +712,7 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
        int ret, i;
 
        micfil->quality = QUALITY_VLOW0;
+       micfil->card = cpu_dai->component->card;
 
        /* set default gain to 2 */
        regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
@@ -585,6 +947,71 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t voice_detected_fn(int irq, void *devid)
+{
+       struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+       struct snd_kcontrol *kctl;
+
+       if (!micfil->card)
+               return IRQ_HANDLED;
+
+       kctl = snd_soc_card_get_kcontrol(micfil->card, "VAD Detected");
+       if (!kctl)
+               return IRQ_HANDLED;
+
+       if (micfil->vad_detected)
+               snd_ctl_notify(micfil->card->snd_card,
+                              SNDRV_CTL_EVENT_MASK_VALUE,
+                              &kctl->id);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t hwvad_isr(int irq, void *devid)
+{
+       struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+       struct device *dev = &micfil->pdev->dev;
+       u32 vad0_reg;
+       int ret;
+
+       regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+       /*
+        * The only difference between MICFIL_VAD0_STAT_EF and
+        * MICFIL_VAD0_STAT_IF is that the former requires Write
+        * 1 to Clear. Since both flags are set, it is enough
+        * to only read one of them
+        */
+       if (vad0_reg & MICFIL_VAD0_STAT_IF) {
+               /* Write 1 to clear */
+               regmap_write_bits(micfil->regmap, REG_MICFIL_VAD0_STAT,
+                                 MICFIL_VAD0_STAT_IF,
+                                 MICFIL_VAD0_STAT_IF);
+
+               micfil->vad_detected = 1;
+       }
+
+       ret = fsl_micfil_hwvad_disable(micfil);
+       if (ret)
+               dev_err(dev, "Failed to disable hwvad\n");
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t hwvad_err_isr(int irq, void *devid)
+{
+       struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
+       struct device *dev = &micfil->pdev->dev;
+       u32 vad0_reg;
+
+       regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg);
+
+       if (vad0_reg & MICFIL_VAD0_STAT_INSATF)
+               dev_dbg(dev, "voice activity input overflow/underflow detected\n");
+
+       return IRQ_HANDLED;
+}
+
 static int fsl_micfil_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -677,6 +1104,26 @@ static int fsl_micfil_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* Digital Microphone interface voice activity detector event */
+       ret = devm_request_threaded_irq(&pdev->dev, micfil->irq[2],
+                                       hwvad_isr, voice_detected_fn,
+                                       IRQF_SHARED, micfil->name, micfil);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim hwvad event irq %u\n",
+                       micfil->irq[0]);
+               return ret;
+       }
+
+       /* Digital Microphone interface voice activity detector error */
+       ret = devm_request_irq(&pdev->dev, micfil->irq[3],
+                              hwvad_err_isr, IRQF_SHARED,
+                              micfil->name, micfil);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim hwvad error irq %u\n",
+                       micfil->irq[1]);
+               return ret;
+       }
+
        micfil->dma_params_rx.chan_name = "rx";
        micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0;
        micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX;
index d60285d..9237a1c 100644 (file)
 #define FIFO_PTRWID                    3
 #define FIFO_LEN                       BIT(FIFO_PTRWID)
 
-#define MICFIL_IRQ_LINES               2
+#define MICFIL_IRQ_LINES               4
 #define MICFIL_MAX_RETRY               25
 #define MICFIL_SLEEP_MIN               90000 /* in us */
 #define MICFIL_SLEEP_MAX               100000 /* in us */
 #define MICFIL_DMA_MAXBURST_RX         6
 
+/* HWVAD Constants */
+#define MICFIL_HWVAD_ENVELOPE_MODE     0
+#define MICFIL_HWVAD_ENERGY_MODE       1
+
 #endif /* _FSL_MICFIL_H */
index bf94838..46c7868 100644 (file)
@@ -117,14 +117,14 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 32,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_RPMSG_FORMATS,
        },
        .capture = {
                .stream_name = "CPU-Capture",
                .channels_min = 2,
-               .channels_max = 2,
+               .channels_max = 32,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_RPMSG_FORMATS,
        },
@@ -235,7 +235,7 @@ static int fsl_rpmsg_probe(struct platform_device *pdev)
 
        rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
                                                         "imx-audio-rpmsg",
-                                                        PLATFORM_DEVID_NONE,
+                                                        PLATFORM_DEVID_AUTO,
                                                         NULL,
                                                         0);
        if (IS_ERR(rpmsg->card_pdev)) {
index 81f89f6..a0ea27f 100644 (file)
@@ -872,10 +872,10 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 
        regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
                           FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
-                          sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
+                          sai->soc_data->fifo_depth - sai->dma_params_tx.maxburst);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs),
                           FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
-                          FSL_SAI_MAXBURST_RX - 1);
+                          sai->dma_params_rx.maxburst - 1);
 
        snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
                                &sai->dma_params_rx);
@@ -1416,8 +1416,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0;
        sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0;
-       sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
-       sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+       sai->dma_params_rx.maxburst =
+               sai->soc_data->max_burst[RX] ? sai->soc_data->max_burst[RX] : FSL_SAI_MAXBURST_RX;
+       sai->dma_params_tx.maxburst =
+               sai->soc_data->max_burst[TX] ? sai->soc_data->max_burst[TX] : FSL_SAI_MAXBURST_TX;
 
        sai->pinctrl = devm_pinctrl_get(&pdev->dev);
 
@@ -1579,6 +1581,18 @@ static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = {
        .max_register = FSL_SAI_RTCAP,
 };
 
+static const struct fsl_sai_soc_data fsl_sai_imx93_data = {
+       .use_imx_pcm = true,
+       .use_edma = true,
+       .fifo_depth = 128,
+       .reg_offset = 8,
+       .mclk0_is_mclk1 = false,
+       .pins = 4,
+       .flags = 0,
+       .max_register = FSL_SAI_MCTL,
+       .max_burst = {8, 8},
+};
+
 static const struct of_device_id fsl_sai_ids[] = {
        { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
        { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
@@ -1590,6 +1604,7 @@ static const struct of_device_id fsl_sai_ids[] = {
        { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data },
        { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data },
        { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data },
+       { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_sai_ids);
index 697f669..197748a 100644 (file)
@@ -235,6 +235,7 @@ struct fsl_sai_soc_data {
        unsigned int reg_offset;
        unsigned int flags;
        unsigned int max_register;
+       unsigned int max_burst[2];
 };
 
 /**
index c043efe..2a6802f 100644 (file)
@@ -934,6 +934,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = {
        { FSL_XCVR_RX_DPTH_CTRL_SET,    0x00002C89 },
        { FSL_XCVR_RX_DPTH_CTRL_CLR,    0x00002C89 },
        { FSL_XCVR_RX_DPTH_CTRL_TOG,    0x00002C89 },
+       { FSL_XCVR_RX_DPTH_CNTR_CTRL,   0x00000000 },
+       { FSL_XCVR_RX_DPTH_CNTR_CTRL_SET, 0x00000000 },
+       { FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR, 0x00000000 },
+       { FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG, 0x00000000 },
+       { FSL_XCVR_RX_DPTH_TSCR, 0x00000000 },
+       { FSL_XCVR_RX_DPTH_BCR,  0x00000000 },
+       { FSL_XCVR_RX_DPTH_BCTR, 0x00000000 },
+       { FSL_XCVR_RX_DPTH_BCRR, 0x00000000 },
        { FSL_XCVR_TX_DPTH_CTRL,        0x00000000 },
        { FSL_XCVR_TX_DPTH_CTRL_SET,    0x00000000 },
        { FSL_XCVR_TX_DPTH_CTRL_CLR,    0x00000000 },
@@ -944,6 +952,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = {
        { FSL_XCVR_TX_CS_DATA_3,        0x00000000 },
        { FSL_XCVR_TX_CS_DATA_4,        0x00000000 },
        { FSL_XCVR_TX_CS_DATA_5,        0x00000000 },
+       { FSL_XCVR_TX_DPTH_CNTR_CTRL,   0x00000000 },
+       { FSL_XCVR_TX_DPTH_CNTR_CTRL_SET, 0x00000000 },
+       { FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR, 0x00000000 },
+       { FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG, 0x00000000 },
+       { FSL_XCVR_TX_DPTH_TSCR, 0x00000000 },
+       { FSL_XCVR_TX_DPTH_BCR,  0x00000000 },
+       { FSL_XCVR_TX_DPTH_BCTR, 0x00000000 },
+       { FSL_XCVR_TX_DPTH_BCRR, 0x00000000 },
        { FSL_XCVR_DEBUG_REG_0,         0x00000000 },
        { FSL_XCVR_DEBUG_REG_1,         0x00000000 },
 };
@@ -975,6 +991,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
        case FSL_XCVR_RX_DPTH_CTRL_SET:
        case FSL_XCVR_RX_DPTH_CTRL_CLR:
        case FSL_XCVR_RX_DPTH_CTRL_TOG:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
+       case FSL_XCVR_RX_DPTH_TSCR:
+       case FSL_XCVR_RX_DPTH_BCR:
+       case FSL_XCVR_RX_DPTH_BCTR:
+       case FSL_XCVR_RX_DPTH_BCRR:
        case FSL_XCVR_TX_DPTH_CTRL:
        case FSL_XCVR_TX_DPTH_CTRL_SET:
        case FSL_XCVR_TX_DPTH_CTRL_CLR:
@@ -985,6 +1009,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
        case FSL_XCVR_TX_CS_DATA_3:
        case FSL_XCVR_TX_CS_DATA_4:
        case FSL_XCVR_TX_CS_DATA_5:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG:
+       case FSL_XCVR_TX_DPTH_TSCR:
+       case FSL_XCVR_TX_DPTH_BCR:
+       case FSL_XCVR_TX_DPTH_BCTR:
+       case FSL_XCVR_TX_DPTH_BCRR:
        case FSL_XCVR_DEBUG_REG_0:
        case FSL_XCVR_DEBUG_REG_1:
                return true;
@@ -1017,6 +1049,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
        case FSL_XCVR_RX_DPTH_CTRL_SET:
        case FSL_XCVR_RX_DPTH_CTRL_CLR:
        case FSL_XCVR_RX_DPTH_CTRL_TOG:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
+       case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
        case FSL_XCVR_TX_DPTH_CTRL_SET:
        case FSL_XCVR_TX_DPTH_CTRL_CLR:
        case FSL_XCVR_TX_DPTH_CTRL_TOG:
@@ -1026,6 +1062,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
        case FSL_XCVR_TX_CS_DATA_3:
        case FSL_XCVR_TX_CS_DATA_4:
        case FSL_XCVR_TX_CS_DATA_5:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR:
+       case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG:
                return true;
        default:
                return false;
index 7f2853c..4769b0f 100644 (file)
 #define FSL_XCVR_RX_DPTH_CTRL_CLR      0x188
 #define FSL_XCVR_RX_DPTH_CTRL_TOG      0x18c
 
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL     0x1C0
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_SET 0x1C4
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR 0x1C8
+#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG 0x1CC
+
+#define FSL_XCVR_RX_DPTH_TSCR          0x1D0
+#define FSL_XCVR_RX_DPTH_BCR           0x1D4
+#define FSL_XCVR_RX_DPTH_BCTR          0x1D8
+#define FSL_XCVR_RX_DPTH_BCRR          0x1DC
+
 #define FSL_XCVR_TX_DPTH_CTRL          0x220 /* TX datapath ctrl reg */
 #define FSL_XCVR_TX_DPTH_CTRL_SET      0x224
 #define FSL_XCVR_TX_DPTH_CTRL_CLR      0x228
 #define FSL_XCVR_TX_CS_DATA_3          0x23C
 #define FSL_XCVR_TX_CS_DATA_4          0x240
 #define FSL_XCVR_TX_CS_DATA_5          0x244
+
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL     0x260
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_SET 0x264
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR 0x268
+#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG 0x26C
+
+#define FSL_XCVR_TX_DPTH_TSCR          0x270
+#define FSL_XCVR_TX_DPTH_BCR           0x274
+#define FSL_XCVR_TX_DPTH_BCTR          0x278
+#define FSL_XCVR_TX_DPTH_BCRR          0x27C
+
 #define FSL_XCVR_DEBUG_REG_0           0x2E0
 #define FSL_XCVR_DEBUG_REG_1           0x2F0
 
index 905c3a0..d5234ac 100644 (file)
@@ -88,7 +88,7 @@ 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_NONE,
+                                                        PLATFORM_DEVID_AUTO,
                                                         NULL, 0);
        if (IS_ERR(data->rpmsg_pdev)) {
                dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
@@ -110,6 +110,7 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
 
 static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
        { .name = "rpmsg-audio-channel" },
+       { .name = "rpmsg-micfil-channel" },
        { },
 };
 
index 3504904..2f31099 100644 (file)
@@ -178,7 +178,7 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
                msg->s_msg.param.channels = RPMSG_CH_STEREO;
                break;
        default:
-               ret = -EINVAL;
+               msg->s_msg.param.channels = params_channels(params);
                break;
        }
 
@@ -684,7 +684,7 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
        info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
        info->dev = &pdev->dev;
        /* Setup work queue */
-       info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
+       info->rpmsg_wq = alloc_ordered_workqueue(info->rpdev->id.name,
                                                 WQ_HIGHPRI |
                                                 WQ_UNBOUND |
                                                 WQ_FREEZABLE);
@@ -723,11 +723,15 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
        if (ret)
                goto fail;
 
-       component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
+       component = snd_soc_lookup_component(&pdev->dev, NULL);
        if (!component) {
                ret = -EINVAL;
                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
index 4d99f48..8917810 100644 (file)
@@ -58,6 +58,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
        struct platform_device *rpmsg_pdev = to_platform_device(dev);
        struct device_node *np = rpmsg_pdev->dev.of_node;
        struct of_phandle_args args;
+       const char *platform_name;
        struct imx_rpmsg *data;
        int ret = 0;
 
@@ -109,7 +110,10 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
        }
 
        data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
-       data->dai.platforms->name = IMX_PCM_DRV_NAME;
+       if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name))
+               data->dai.platforms->name = platform_name;
+       else
+               data->dai.platforms->name = "rpmsg-audio-channel";
        data->dai.playback_only = true;
        data->dai.capture_only = true;
        data->card.num_links = 1;
index fe547c1..994db61 100644 (file)
         *              +-+             +-+
         *
         * [DPCM]
+        *
+        *      CPU3/CPU4 are converting rate to 44100
+        *
         *      FE              BE
         *                ****
         *      cpu3 <-@--*  *--@-> codec3
-        *      cpu4 <-@--*  *
+        *      cpu4 <-@--*  *  (44.1kHz)
         *                ****
         *
         * [DPCM-Multi]
                        port@2  { codec2_ep:  endpoint { remote-endpoint = <&mcodec2_ep>; }; };
 
                        /* [DPCM]::BE */
-                       port@3  { codec3_ep:  endpoint { remote-endpoint = <&be00_ep>; }; };
+                       port@3  {
+                               convert-rate = <44100>;
+                               codec3_ep:  endpoint { remote-endpoint = <&be00_ep>; };
+                       };
 
                        /* [DPCM-Multi]::BE */
                        port@4  { codec4_ep:  endpoint { remote-endpoint = <&mbe1_ep>; }; };
index 8ac6df6..06609a5 100644 (file)
@@ -849,7 +849,8 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
                        goto err;
        }
 
-       graph_parse_convert(rep, dai_props);
+       graph_parse_convert(ep,  dai_props); /* at node of <dpcm> */
+       graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
 
        snd_soc_dai_link_set_capabilities(dai_link);
 
@@ -1271,9 +1272,6 @@ err:
        if (ret < 0)
                dev_err_probe(dev, ret, "parse error\n");
 
-       if (ret == 0)
-               dev_warn(dev, "Audio Graph Card2 is still under Experimental stage\n");
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
index be69bbc..e35becc 100644 (file)
@@ -41,27 +41,6 @@ static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
        }
 }
 
-void asoc_simple_convert_fixup(struct asoc_simple_data *data,
-                              struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       if (data->convert_rate)
-               rate->min =
-               rate->max = data->convert_rate;
-
-       if (data->convert_channels)
-               channels->min =
-               channels->max = data->convert_channels;
-
-       if (data->convert_sample_format)
-               asoc_simple_fixup_sample_fmt(data, params);
-}
-EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
-
 void asoc_simple_parse_convert(struct device_node *np,
                               char *prefix,
                               struct asoc_simple_data *data)
@@ -522,8 +501,20 @@ int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 {
        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
        struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+       struct asoc_simple_data *data = &dai_props->adata;
+       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       if (data->convert_rate)
+               rate->min =
+               rate->max = data->convert_rate;
 
-       asoc_simple_convert_fixup(&dai_props->adata, params);
+       if (data->convert_channels)
+               channels->min =
+               channels->max = data->convert_channels;
+
+       if (data->convert_sample_format)
+               asoc_simple_fixup_sample_fmt(data, params);
 
        return 0;
 }
index d2ca710..ac799de 100644 (file)
@@ -177,7 +177,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
        select SND_HDA_DSP_LOADER
        select SND_SOC_TOPOLOGY
        select SND_SOC_INTEL_SST
-       select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
+       select SND_SOC_HDAC_HDA
        select SND_SOC_ACPI_INTEL_MATCH
        select SND_INTEL_DSP_CONFIG
        help
index b8e2b23..7c8ce98 100644 (file)
@@ -133,12 +133,14 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
        buf = apl_log_payload_addr(addr);
        memcpy_fromio(&layout, addr, sizeof(layout));
        if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+               union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
+
                /*
                 * DSP awaits the remaining logs to be
                 * gathered before dumping stack
                 */
-               msg->log.core = msg->ext.coredump.core_id;
-               avs_dsp_op(adev, log_buffer_status, msg);
+               lbs_msg.log.core = msg->ext.coredump.core_id;
+               avs_dsp_op(adev, log_buffer_status, &lbs_msg);
        }
 
        pos = dump + AVS_FW_REGS_SIZE;
index 92e3772..8d05b27 100644 (file)
@@ -24,6 +24,13 @@ struct avs_tplg_library;
 struct avs_soc_component;
 struct avs_ipc_msg;
 
+#ifdef CONFIG_ACPI
+#define AVS_S0IX_SUPPORTED \
+       (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
+#else
+#define AVS_S0IX_SUPPORTED false
+#endif
+
 /*
  * struct avs_dsp_ops - Platform-specific DSP operations
  *
@@ -127,6 +134,7 @@ struct avs_dev {
        struct list_head fw_list;
        int *core_refs;         /* reference count per core */
        char **lib_names;
+       int num_lp_paths;
 
        struct completion fw_ready;
        struct work_struct probe_work;
@@ -220,8 +228,10 @@ static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
        /*
         * If IPC channel is blocked e.g.: due to ongoing recovery,
         * -EPERM error code is expected and thus it's not an actual error.
+        *
+        * Unsupported IPCs are of no harm either.
         */
-       if (error == -EPERM)
+       if (error == -EPERM || error == AVS_IPC_NOT_SUPPORTED)
                dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
                        tx->glb.primary, tx->glb.ext.val, error);
        else
index 87f9c18..02cc1ce 100644 (file)
@@ -29,6 +29,12 @@ static const struct dmi_system_id kbl_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
                },
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
+               },
+       },
        {}
 };
 
@@ -122,6 +128,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
                .tplg_filename = "rt298-tplg.bin",
        },
        {
+               .id = "MX98927",
+               .drv_name = "avs_max98927",
+               .mach_params = {
+                       .i2s_link_mask = AVS_SSP(0),
+               },
+               .tplg_filename = "max98927-tplg.bin",
+       },
+       {
                .id = "MX98373",
                .drv_name = "avs_max98373",
                .mach_params = {
@@ -130,6 +144,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
                .tplg_filename = "max98373-tplg.bin",
        },
        {
+               .id = "MX98357A",
+               .drv_name = "avs_max98357a",
+               .mach_params = {
+                       .i2s_link_mask = AVS_SSP(0),
+               },
+               .tplg_filename = "max98357a-tplg.bin",
+       },
+       {
                .id = "DLGS7219",
                .drv_name = "avs_da7219",
                .mach_params = {
index 4d68e3e..9bd40fd 100644 (file)
@@ -36,6 +36,16 @@ config SND_SOC_INTEL_AVS_MACH_I2S_TEST
           This adds support for I2S test-board which can be used to verify
           transfer over I2S interface with SSP loopback scenarios.
 
+config SND_SOC_INTEL_AVS_MACH_MAX98927
+       tristate "max98927 I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_MAX98927
+       help
+         This adds support for AVS with MAX98927 I2S codec configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_MAX98357A
        tristate "max98357A I2S board"
        depends on I2C
index bc75376..4d70b8d 100644 (file)
@@ -4,6 +4,7 @@ snd-soc-avs-da7219-objs := da7219.o
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98927-objs := max98927.o
 snd-soc-avs-max98357a-objs := max98357a.o
 snd-soc-avs-max98373-objs := max98373.o
 snd-soc-avs-nau8825-objs := nau8825.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
index 02ae542..ad86cef 100644 (file)
@@ -6,6 +6,7 @@
 //
 
 #include <linux/module.h>
+#include <linux/platform_data/x86/soc.h>
 #include <linux/platform_device.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
@@ -15,7 +16,6 @@
 #include <sound/soc-dapm.h>
 #include <uapi/linux/input-event-codes.h>
 #include "../../../codecs/da7219.h"
-#include "../../../codecs/da7219-aad.h"
 
 #define DA7219_DAI_NAME                "da7219-hifi"
 
@@ -80,7 +80,10 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
        int ret;
 
        jack = snd_soc_card_get_drvdata(card);
-       clk_freq = 19200000;
+       if (soc_intel_is_apl())
+               clk_freq = 19200000;
+       else /* kbl */
+               clk_freq = 24576000;
 
        ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
        if (ret) {
@@ -106,7 +109,7 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, jack);
+       snd_soc_component_set_jack(component, jack, NULL);
 
        return 0;
 }
index 073663b..e68c4c7 100644 (file)
@@ -6,6 +6,7 @@
 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 //
 
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <sound/hda_codec.h>
 #include <sound/hda_i915.h>
index 0fa8f56..8e221ec 100644 (file)
@@ -53,7 +53,7 @@ avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_par
        channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
new file mode 100644 (file)
index 0000000..7cccce9
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98927_DEV0_NAME     "i2c-MX98927:00"
+#define MAX98927_DEV1_NAME     "i2c-MX98927:01"
+#define MAX98927_CODEC_NAME    "max98927-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
+               .name_prefix = "Right",
+       },
+       {
+               .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME),
+               .name_prefix = "Left",
+       },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       { "Left Spk", NULL, "Left BE_OUT" },
+       { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98927_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 16 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+       return 0;
+}
+
+static int avs_max98927_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai;
+       int ret = 0;
+       int i;
+
+       for_each_rtd_codec_dais(runtime, i, codec_dai) {
+               if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME))
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+               else if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME))
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+
+               if (ret < 0) {
+                       dev_err(runtime->dev, "hw_params for %s failed: %d\n",
+                               codec_dai->component->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops avs_max98927_ops = {
+       .hw_params = avs_max98927_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV0_NAME);
+       dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+       dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV1_NAME);
+       dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
+       if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+           !dl->codecs[1].name || !dl->codecs[1].dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 2;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->be_hw_params_fixup = avs_max98927_be_fixup;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+       dl->ignore_pmdown_time = 1;
+       dl->ops = &avs_max98927_ops;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_max98927_probe(struct platform_device *pdev)
+{
+       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, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = "avs_max98927";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->codec_conf = card_codec_conf;
+       card->num_configs = ARRAY_SIZE(card_codec_conf);
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98927_driver = {
+       .probe = avs_max98927_probe,
+       .driver = {
+               .name = "avs_max98927",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_max98927_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98927");
index b28d368..58c9d9e 100644 (file)
@@ -6,6 +6,7 @@
 //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 //
 
+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/soc-acpi.h>
 #include "../../../codecs/rt298.h"
 
+static const struct dmi_system_id kblr_dmi_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
+               },
+       },
+       {}
+};
+
 static const struct snd_kcontrol_new card_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Mic Jack"),
@@ -96,9 +107,15 @@ avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_param
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       unsigned int clk_freq;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+       if (dmi_first_match(kblr_dmi_table))
+               clk_freq = 24000000;
+       else
+               clk_freq = 19200000;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, clk_freq, SND_SOC_CLOCK_IN);
        if (ret < 0)
                dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
 
@@ -139,7 +156,10 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
        dl->platforms = platform;
        dl->num_platforms = 1;
        dl->id = 0;
-       dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       if (dmi_first_match(kblr_dmi_table))
+               dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       else
+               dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
        dl->init = avs_rt298_codec_init;
        dl->be_hw_params_fixup = avs_rt298_be_fixup;
        dl->ops = &avs_rt298_ops;
index 9f84c8a..c5db696 100644 (file)
@@ -103,7 +103,7 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para
        channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index bb0719c..f7bc064 100644 (file)
 #include "avs.h"
 #include "cldma.h"
 
+static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
+module_param(pgctl_mask, uint, 0444);
+MODULE_PARM_DESC(pgctl_mask, "PCI PGCTL policy override");
+
+static u32 cgctl_mask = AZX_CGCTL_MISCBDCGE_MASK;
+module_param(cgctl_mask, uint, 0444);
+MODULE_PARM_DESC(cgctl_mask, "PCI CGCTL policy override");
+
 static void
 avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
 {
@@ -41,19 +49,16 @@ avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value)
 
 void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
 {
-       u32 value;
+       u32 value = enable ? 0 : pgctl_mask;
 
-       value = enable ? 0 : AZX_PGCTL_LSRMD_MASK;
-       avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL,
-                                   AZX_PGCTL_LSRMD_MASK, value);
+       avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value);
 }
 
 static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable)
 {
-       u32 value;
+       u32 value = enable ? cgctl_mask : 0;
 
-       value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
-       avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, value);
+       avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value);
 }
 
 void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
@@ -63,9 +68,8 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
 
 void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
 {
-       u32 value;
+       u32 value = enable ? AZX_VS_EM2_L1SEN : 0;
 
-       value = enable ? AZX_VS_EM2_L1SEN : 0;
        snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
 }
 
@@ -440,7 +444,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        if (bus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(bus);
 
-       if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+       if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
                dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
        dma_set_max_seg_size(dev, UINT_MAX);
 
@@ -504,7 +508,7 @@ static void avs_pci_remove(struct pci_dev *pci)
        snd_hdac_bus_free_stream_pages(bus);
        snd_hdac_ext_stream_free_all(bus);
        /* reverse ml_capabilities */
-       snd_hdac_link_free_all(bus);
+       snd_hdac_ext_link_free_all(bus);
        snd_hdac_ext_bus_exit(bus);
 
        avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0));
@@ -534,12 +538,30 @@ static void avs_pci_remove(struct pci_dev *pci)
        pm_runtime_get_noresume(&pci->dev);
 }
 
-static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
+static int avs_suspend_standby(struct avs_dev *adev)
+{
+       struct hdac_bus *bus = &adev->base.core;
+       struct pci_dev *pci = adev->base.pci;
+
+       if (bus->cmd_dma_state)
+               snd_hdac_bus_stop_cmd_io(bus);
+
+       snd_hdac_ext_bus_link_power_down_all(bus);
+
+       enable_irq_wake(pci->irq);
+       pci_save_state(pci);
+
+       return 0;
+}
+
+static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
 {
        struct hdac_bus *bus = &adev->base.core;
        int ret;
 
        flush_work(&adev->probe_work);
+       if (low_power && adev->num_lp_paths)
+               return avs_suspend_standby(adev);
 
        snd_hdac_ext_bus_link_power_down_all(bus);
 
@@ -577,12 +599,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
        return 0;
 }
 
-static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
+static int avs_resume_standby(struct avs_dev *adev)
+{
+       struct hdac_bus *bus = &adev->base.core;
+       struct pci_dev *pci = adev->base.pci;
+
+       pci_restore_state(pci);
+       disable_irq_wake(pci->irq);
+
+       snd_hdac_ext_bus_link_power_up_all(bus);
+
+       if (bus->cmd_dma_state)
+               snd_hdac_bus_init_cmd_io(bus);
+
+       return 0;
+}
+
+static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
 {
        struct hdac_bus *bus = &adev->base.core;
-       struct hdac_ext_link *hlink;
        int ret;
 
+       if (low_power && adev->num_lp_paths)
+               return avs_resume_standby(adev);
+
        snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
        avs_hdac_bus_init_chip(bus, true);
 
@@ -595,41 +635,55 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
                return ret;
        }
 
-       /* turn off the links that were off before suspend */
-       list_for_each_entry(hlink, &bus->hlink_list, list) {
-               if (!hlink->ref_count)
-                       snd_hdac_ext_bus_link_power_down(hlink);
-       }
-
-       /* check dma status and clean up CORB/RIRB buffers */
-       if (!bus->cmd_dma_state)
-               snd_hdac_bus_stop_cmd_io(bus);
-
        return 0;
 }
 
 static int __maybe_unused avs_suspend(struct device *dev)
 {
-       return avs_suspend_common(to_avs_dev(dev));
+       return avs_suspend_common(to_avs_dev(dev), true);
 }
 
 static int __maybe_unused avs_resume(struct device *dev)
 {
-       return avs_resume_common(to_avs_dev(dev), true);
+       return avs_resume_common(to_avs_dev(dev), true, true);
 }
 
 static int __maybe_unused avs_runtime_suspend(struct device *dev)
 {
-       return avs_suspend_common(to_avs_dev(dev));
+       return avs_suspend_common(to_avs_dev(dev), true);
 }
 
 static int __maybe_unused avs_runtime_resume(struct device *dev)
 {
-       return avs_resume_common(to_avs_dev(dev), true);
+       return avs_resume_common(to_avs_dev(dev), true, false);
+}
+
+static int __maybe_unused avs_freeze(struct device *dev)
+{
+       return avs_suspend_common(to_avs_dev(dev), false);
+}
+static int __maybe_unused avs_thaw(struct device *dev)
+{
+       return avs_resume_common(to_avs_dev(dev), false, true);
+}
+
+static int __maybe_unused avs_poweroff(struct device *dev)
+{
+       return avs_suspend_common(to_avs_dev(dev), false);
+}
+
+static int __maybe_unused avs_restore(struct device *dev)
+{
+       return avs_resume_common(to_avs_dev(dev), false, true);
 }
 
 static const struct dev_pm_ops avs_dev_pm = {
-       SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume)
+       .suspend = avs_suspend,
+       .resume = avs_resume,
+       .freeze = avs_freeze,
+       .thaw = avs_thaw,
+       .poweroff = avs_poweroff,
+       .restore = avs_restore,
        SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
 };
 
@@ -667,7 +721,11 @@ static const struct avs_spec apl_desc = {
 
 static const struct pci_device_id avs_ids[] = {
        { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
+       { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
        { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
+       { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
+       { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
+       { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
        { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
        { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
        { 0 }
index 020d85c..af8a260 100644 (file)
@@ -74,7 +74,7 @@ int avs_dsp_disable_d0ix(struct avs_dev *adev)
        struct avs_ipc *ipc = adev->ipc;
 
        /* Prevent PG only on the first disable. */
-       if (atomic_add_return(1, &ipc->d0ix_disable_depth) == 1) {
+       if (atomic_inc_return(&ipc->d0ix_disable_depth) == 1) {
                cancel_delayed_work_sync(&ipc->d0ix_work);
                return avs_dsp_set_d0ix(adev, false);
        }
@@ -123,7 +123,10 @@ static void avs_dsp_recovery(struct avs_dev *adev)
                                if (!substream || !substream->runtime)
                                        continue;
 
+                               /* No need for _irq() as we are in nonatomic context. */
+                               snd_pcm_stream_lock(substream);
                                snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+                               snd_pcm_stream_unlock(substream);
                        }
                }
        }
@@ -192,7 +195,8 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
                /* update size in case of LARGE_CONFIG_GET */
                if (msg.msg_target == AVS_MOD_MSG &&
                    msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
-                       ipc->rx.size = msg.ext.large_config.data_off_size;
+                       ipc->rx.size = min_t(u32, AVS_MAILBOX_SIZE,
+                                            msg.ext.large_config.data_off_size);
 
                memcpy_fromio(ipc->rx.data, avs_uplink_addr(adev), ipc->rx.size);
                trace_avs_msg_payload(ipc->rx.data, ipc->rx.size);
index 9e3f8ff..56bb0a5 100644 (file)
@@ -43,7 +43,7 @@
 /* Occasionally, engineering (release candidate) firmware is provided for testing. */
 static bool debug_ignore_fw_version;
 module_param_named(ignore_fw_version, debug_ignore_fw_version, bool, 0444);
-MODULE_PARM_DESC(ignore_fw_version, "Verify FW version 0=yes (default), 1=no");
+MODULE_PARM_DESC(ignore_fw_version, "Ignore firmware version check 0=no (default), 1=yes");
 
 #define AVS_LIB_NAME_SIZE      8
 
@@ -224,11 +224,19 @@ static int avs_cldma_load_module(struct avs_dev *adev, struct avs_module_entry *
        if (ret < 0)
                return ret;
 
+       avs_hda_power_gating_enable(adev, false);
+       avs_hda_clock_gating_enable(adev, false);
+       avs_hda_l1sen_enable(adev, false);
+
        hda_cldma_set_data(cl, (void *)mod->data, mod->size);
        hda_cldma_transfer(cl, msecs_to_jiffies(AVS_CLDMA_START_DELAY_MS));
        ret = avs_ipc_load_modules(adev, &mentry->module_id, 1);
        hda_cldma_stop(cl);
 
+       avs_hda_l1sen_enable(adev, true);
+       avs_hda_clock_gating_enable(adev, true);
+       avs_hda_power_gating_enable(adev, true);
+
        if (ret) {
                dev_err(adev->dev, "load module %d failed: %d\n", mentry->module_id, ret);
                avs_release_last_firmware(adev);
@@ -369,8 +377,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
                goto release_stream;
 
        /* enable SPIB for hda stream */
-       snd_hdac_ext_stream_spbcap_enable(bus, true, hstream->index);
-       ret = snd_hdac_ext_stream_set_spib(bus, estream, fw->size);
+       snd_hdac_stream_spbcap_enable(bus, true, hstream->index);
+       ret = snd_hdac_stream_set_spib(bus, hstream, fw->size);
        if (ret)
                goto cleanup_resources;
 
@@ -400,8 +408,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
 
 cleanup_resources:
        /* disable SPIB for hda stream */
-       snd_hdac_ext_stream_spbcap_enable(bus, false, hstream->index);
-       snd_hdac_ext_stream_set_spib(bus, estream, 0);
+       snd_hdac_stream_spbcap_enable(bus, false, hstream->index);
+       snd_hdac_stream_set_spib(bus, hstream, 0);
 
        snd_hdac_dsp_cleanup(hstream, &dmab);
 release_stream:
@@ -436,8 +444,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
                goto release_stream;
 
        /* enable SPIB for hda stream */
-       snd_hdac_ext_stream_spbcap_enable(bus, true, stream->index);
-       snd_hdac_ext_stream_set_spib(bus, estream, lib->size);
+       snd_hdac_stream_spbcap_enable(bus, true, stream->index);
+       snd_hdac_stream_set_spib(bus, stream, lib->size);
 
        memcpy(dmab.area, lib->data, lib->size);
 
@@ -451,8 +459,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
        }
 
        /* disable SPIB for hda stream */
-       snd_hdac_ext_stream_spbcap_enable(bus, false, stream->index);
-       snd_hdac_ext_stream_set_spib(bus, estream, 0);
+       snd_hdac_stream_spbcap_enable(bus, false, stream->index);
+       snd_hdac_stream_set_spib(bus, stream, 0);
 
        snd_hdac_dsp_cleanup(stream, &dmab);
 release_stream:
@@ -605,6 +613,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
        for (i = 1; i < adev->fw_cfg.max_libs_count; i++)
                memset(adev->lib_names[i], 0, AVS_LIB_NAME_SIZE);
 
+       avs_hda_power_gating_enable(adev, false);
        avs_hda_clock_gating_enable(adev, false);
        avs_hda_l1sen_enable(adev, false);
 
@@ -625,6 +634,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
 reenable_gating:
        avs_hda_l1sen_enable(adev, true);
        avs_hda_clock_gating_enable(adev, true);
+       avs_hda_power_gating_enable(adev, true);
 
        if (ret < 0)
                return ret;
index d4bcee1..6b0fecb 100644 (file)
@@ -687,20 +687,13 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
 
 int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
 {
-       int ret;
-
-       ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
-                                      AVS_BASEFW_ENABLE_LOGS, log_info, size);
-       if (ret)
-               dev_err(adev->dev, "enable logs failed: %d\n", ret);
-
-       return ret;
+       return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+                                       AVS_BASEFW_ENABLE_LOGS, log_info, size);
 }
 
 int avs_ipc_set_system_time(struct avs_dev *adev)
 {
        struct avs_sys_time sys_time;
-       int ret;
        u64 us;
 
        /* firmware expects UTC time in micro seconds */
@@ -708,12 +701,8 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
        sys_time.val_l = us & UINT_MAX;
        sys_time.val_u = us >> 32;
 
-       ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
-                                      AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
-       if (ret)
-               dev_err(adev->dev, "set system time failed: %d\n", ret);
-
-       return ret;
+       return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+                                       AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
 }
 
 int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
index c0f90db..02b3b7a 100644 (file)
@@ -150,6 +150,8 @@ union avs_module_msg {
        };
 } __packed;
 
+#define AVS_IPC_NOT_SUPPORTED 15
+
 union avs_reply_msg {
        u64 val;
        struct {
index 8fe5917..70d687f 100644 (file)
@@ -28,6 +28,8 @@ struct avs_dma_data {
         * host stream assigned
         */
        struct hdac_ext_stream *host_stream;
+
+       struct snd_pcm_substream *substream;
 };
 
 static struct avs_tplg_path_template *
@@ -55,8 +57,11 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
        return dw->priv;
 }
 
-static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe)
+static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe,
+                          const struct snd_soc_dai_ops *ops)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct avs_dev *adev = to_avs_dev(dai->dev);
        struct avs_tplg_path_template *template;
        struct avs_dma_data *data;
 
@@ -71,9 +76,13 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
        if (!data)
                return -ENOMEM;
 
+       data->substream = substream;
        data->template = template;
        snd_soc_dai_set_dma_data(dai, substream, data);
 
+       if (rtd->dai_link->ignore_suspend)
+               adev->num_lp_paths++;
+
        return 0;
 }
 
@@ -151,15 +160,22 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
        return ret;
 }
 
+static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops;
+
 static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
-       return avs_dai_startup(substream, dai, false);
+       return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops);
 }
 
 static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct avs_dev *adev = to_avs_dev(dai->dev);
        struct avs_dma_data *data;
 
+       if (rtd->dai_link->ignore_suspend)
+               adev->num_lp_paths--;
+
        data = snd_soc_dai_get_dma_data(dai, substream);
 
        snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -202,30 +218,43 @@ static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct
 static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
                                     struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct avs_dma_data *data;
        int ret = 0;
 
        data = snd_soc_dai_get_dma_data(dai, substream);
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ret = avs_path_pause(data->path);
+               if (ret < 0) {
+                       dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+                       break;
+               }
+
                ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
                if (ret < 0)
                        dev_err(dai->dev, "run BE path failed: %d\n", ret);
                break;
 
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_STOP:
                ret = avs_path_pause(data->path);
                if (ret < 0)
                        dev_err(dai->dev, "pause BE path failed: %d\n", ret);
 
-               if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-                       ret = avs_path_reset(data->path);
-                       if (ret < 0)
-                               dev_err(dai->dev, "reset BE path failed: %d\n", ret);
-               }
+               ret = avs_path_reset(data->path);
+               if (ret < 0)
+                       dev_err(dai->dev, "reset BE path failed: %d\n", ret);
                break;
 
        default:
@@ -245,9 +274,11 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
        .trigger = avs_dai_nonhda_be_trigger,
 };
 
+static const struct snd_soc_dai_ops avs_dai_hda_be_ops;
+
 static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
-       return avs_dai_startup(substream, dai, false);
+       return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops);
 }
 
 static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -292,12 +323,12 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn
 
        /* clear link <-> stream mapping */
        codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
-       link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr);
+       link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
        if (!link)
                return -EINVAL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+               snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
 
        return 0;
 }
@@ -322,15 +353,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
                                                 runtime->sample_bits, 0);
 
        snd_hdac_ext_stream_decouple(bus, link_stream, true);
-       snd_hdac_ext_link_stream_reset(link_stream);
-       snd_hdac_ext_link_stream_setup(link_stream, format_val);
+       snd_hdac_ext_stream_reset(link_stream);
+       snd_hdac_ext_stream_setup(link_stream, format_val);
 
-       link = snd_hdac_ext_bus_link_at(bus, codec->core.addr);
+       link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);
        if (!link)
                return -EINVAL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+               snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
 
        ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
        if (ret)
@@ -343,6 +374,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
 static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
                                  struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct hdac_ext_stream *link_stream;
        struct avs_dma_data *data;
        int ret = 0;
@@ -353,28 +385,40 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
        link_stream = substream->runtime->private_data;
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               snd_hdac_ext_link_stream_start(link_stream);
+               snd_hdac_ext_stream_start(link_stream);
+
+               ret = avs_path_pause(data->path);
+               if (ret < 0) {
+                       dev_err(dai->dev, "pause BE path failed: %d\n", ret);
+                       break;
+               }
 
                ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
                if (ret < 0)
                        dev_err(dai->dev, "run BE path failed: %d\n", ret);
                break;
 
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_STOP:
                ret = avs_path_pause(data->path);
                if (ret < 0)
                        dev_err(dai->dev, "pause BE path failed: %d\n", ret);
 
-               snd_hdac_ext_link_stream_clear(link_stream);
+               snd_hdac_ext_stream_clear(link_stream);
 
-               if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-                       ret = avs_path_reset(data->path);
-                       if (ret < 0)
-                               dev_err(dai->dev, "reset BE path failed: %d\n", ret);
-               }
+               ret = avs_path_reset(data->path);
+               if (ret < 0)
+                       dev_err(dai->dev, "reset BE path failed: %d\n", ret);
                break;
 
        default:
@@ -407,6 +451,8 @@ static const struct snd_pcm_hw_constraint_list hw_rates = {
        .mask = 0,
 };
 
+const struct snd_soc_dai_ops avs_dai_fe_ops;
+
 static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -416,7 +462,7 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
        struct hdac_ext_stream *host_stream;
        int ret;
 
-       ret = avs_dai_startup(substream, dai, true);
+       ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops);
        if (ret)
                return ret;
 
@@ -443,8 +489,13 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
 
 static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+       struct avs_dev *adev = to_avs_dev(dai->dev);
        struct avs_dma_data *data;
 
+       if (rtd->dai_link->ignore_suspend)
+               adev->num_lp_paths--;
+
        data = snd_soc_dai_get_dma_data(dai, substream);
 
        snd_soc_dai_set_dma_data(dai, substream, NULL);
@@ -499,7 +550,7 @@ create_err:
        return ret;
 }
 
-static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+static int __avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
        struct avs_dma_data *data;
        struct hdac_ext_stream *host_stream;
@@ -523,9 +574,15 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so
        snd_hdac_stream_cleanup(hdac_stream(host_stream));
        hdac_stream(host_stream)->prepared = false;
 
-       ret = snd_pcm_lib_free_pages(substream);
-       if (ret < 0)
-               dev_dbg(dai->dev, "Failed to free pages!\n");
+       return ret;
+}
+
+static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       int ret;
+
+       ret = __avs_dai_fe_hw_free(substream, dai);
+       snd_pcm_lib_free_pages(substream);
 
        return ret;
 }
@@ -571,6 +628,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
 
 static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        struct avs_dma_data *data;
        struct hdac_ext_stream *host_stream;
        struct hdac_bus *bus;
@@ -582,17 +640,36 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
        bus = hdac_stream(host_stream)->bus;
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                spin_lock_irqsave(&bus->reg_lock, flags);
                snd_hdac_stream_start(hdac_stream(host_stream), true);
                spin_unlock_irqrestore(&bus->reg_lock, flags);
 
+               /* Timeout on DRSM poll shall not stop the resume so ignore the result. */
+               if (cmd == SNDRV_PCM_TRIGGER_RESUME)
+                       snd_hdac_stream_wait_drsm(hdac_stream(host_stream));
+
+               ret = avs_path_pause(data->path);
+               if (ret < 0) {
+                       dev_err(dai->dev, "pause FE path failed: %d\n", ret);
+                       break;
+               }
+
                ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
                if (ret < 0)
                        dev_err(dai->dev, "run FE path failed: %d\n", ret);
+
                break;
 
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (rtd->dai_link->ignore_suspend)
+                       break;
+               fallthrough;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_STOP:
                ret = avs_path_pause(data->path);
@@ -603,11 +680,9 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
                snd_hdac_stream_stop(hdac_stream(host_stream));
                spin_unlock_irqrestore(&bus->reg_lock, flags);
 
-               if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-                       ret = avs_path_reset(data->path);
-                       if (ret < 0)
-                               dev_err(dai->dev, "reset FE path failed: %d\n", ret);
-               }
+               ret = avs_path_reset(data->path);
+               if (ret < 0)
+                       dev_err(dai->dev, "reset FE path failed: %d\n", ret);
                break;
 
        default:
@@ -662,6 +737,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
        if (ret < 0)
                return ret;
 
+       avs_hda_power_gating_enable(adev, false);
        avs_hda_clock_gating_enable(adev, false);
        avs_hda_l1sen_enable(adev, false);
 
@@ -669,6 +745,7 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
 
        avs_hda_l1sen_enable(adev, true);
        avs_hda_clock_gating_enable(adev, true);
+       avs_hda_power_gating_enable(adev, true);
 
        if (!ret)
                ret = avs_module_info_init(adev, false);
@@ -752,33 +829,232 @@ static void avs_component_remove(struct snd_soc_component *component)
        }
 }
 
+static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_soc_pcm_runtime *rtd;
+       int ret;
+
+       substream = data->substream;
+       rtd = snd_pcm_substream_chip(substream);
+
+       ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai);
+       if (ret)
+               dev_err(dai->dev, "hw_params on resume failed: %d\n", ret);
+
+       return ret;
+}
+
+static int avs_dai_resume_fe_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+       struct hdac_ext_stream *host_stream;
+       struct hdac_stream *hstream;
+       struct hdac_bus *bus;
+       int ret;
+
+       host_stream = data->host_stream;
+       hstream = hdac_stream(host_stream);
+       bus = hdac_stream(host_stream)->bus;
+
+       /* Set DRSM before programming stream and position registers. */
+       snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+
+       ret = dai->driver->ops->prepare(data->substream, dai);
+       if (ret) {
+               dev_err(dai->dev, "prepare FE on resume failed: %d\n", ret);
+               return ret;
+       }
+
+       writel(host_stream->pphcllpl, host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+       writel(host_stream->pphcllpu, host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+       writel(host_stream->pphcldpl, host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+       writel(host_stream->pphcldpu, host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+       /* As per HW spec recommendation, program LPIB and DPIB to the same value. */
+       snd_hdac_stream_set_lpib(hstream, hstream->lpib);
+       snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+
+       return 0;
+}
+
+static int avs_dai_resume_be_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+       int ret;
+
+       ret = dai->driver->ops->prepare(data->substream, dai);
+       if (ret)
+               dev_err(dai->dev, "prepare BE on resume failed: %d\n", ret);
+
+       return ret;
+}
+
+static int avs_dai_suspend_fe_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+       struct hdac_ext_stream *host_stream;
+       int ret;
+
+       host_stream = data->host_stream;
+
+       /* Store position addresses so we can resume from them later on. */
+       hdac_stream(host_stream)->lpib = snd_hdac_stream_get_pos_lpib(hdac_stream(host_stream));
+       host_stream->pphcllpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPL);
+       host_stream->pphcllpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPU);
+       host_stream->pphcldpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPL);
+       host_stream->pphcldpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+       ret = __avs_dai_fe_hw_free(data->substream, dai);
+       if (ret < 0)
+               dev_err(dai->dev, "hw_free FE on suspend failed: %d\n", ret);
+
+       return ret;
+}
+
+static int avs_dai_suspend_be_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)
+{
+       int ret;
+
+       ret = dai->driver->ops->hw_free(data->substream, dai);
+       if (ret < 0)
+               dev_err(dai->dev, "hw_free BE on suspend failed: %d\n", ret);
+
+       return ret;
+}
+
+static int avs_component_pm_op(struct snd_soc_component *component, bool be,
+                              int (*op)(struct snd_soc_dai *, struct avs_dma_data *))
+{
+       struct snd_soc_pcm_runtime *rtd;
+       struct avs_dma_data *data;
+       struct snd_soc_dai *dai;
+       int ret;
+
+       for_each_component_dais(component, dai) {
+               data = dai->playback_dma_data;
+               if (data) {
+                       rtd = snd_pcm_substream_chip(data->substream);
+                       if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+                               ret = op(dai, data);
+                               if (ret < 0) {
+                                       __snd_pcm_set_state(data->substream->runtime,
+                                                           SNDRV_PCM_STATE_DISCONNECTED);
+                                       return ret;
+                               }
+                       }
+               }
+
+               data = dai->capture_dma_data;
+               if (data) {
+                       rtd = snd_pcm_substream_chip(data->substream);
+                       if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
+                               ret = op(dai, data);
+                               if (ret < 0) {
+                                       __snd_pcm_set_state(data->substream->runtime,
+                                                           SNDRV_PCM_STATE_DISCONNECTED);
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int avs_component_resume_hw_params(struct snd_soc_component *component, bool be)
+{
+       return avs_component_pm_op(component, be, &avs_dai_resume_hw_params);
+}
+
+static int avs_component_resume_prepare(struct snd_soc_component *component, bool be)
+{
+       int (*prepare_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+       if (be)
+               prepare_cb = &avs_dai_resume_be_prepare;
+       else
+               prepare_cb = &avs_dai_resume_fe_prepare;
+
+       return avs_component_pm_op(component, be, prepare_cb);
+}
+
+static int avs_component_suspend_hw_free(struct snd_soc_component *component, bool be)
+{
+       int (*hw_free_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);
+
+       if (be)
+               hw_free_cb = &avs_dai_suspend_be_hw_free;
+       else
+               hw_free_cb = &avs_dai_suspend_fe_hw_free;
+
+       return avs_component_pm_op(component, be, hw_free_cb);
+}
+
+static int avs_component_suspend(struct snd_soc_component *component)
+{
+       int ret;
+
+       /*
+        * When freeing paths, FEs need to be first as they perform
+        * path unbinding.
+        */
+       ret = avs_component_suspend_hw_free(component, false);
+       if (ret)
+               return ret;
+
+       return avs_component_suspend_hw_free(component, true);
+}
+
+static int avs_component_resume(struct snd_soc_component *component)
+{
+       int ret;
+
+       /*
+        * When creating paths, FEs need to be last as they perform
+        * path binding.
+        */
+       ret = avs_component_resume_hw_params(component, true);
+       if (ret)
+               return ret;
+
+       ret = avs_component_resume_hw_params(component, false);
+       if (ret)
+               return ret;
+
+       /* It is expected that the LINK stream is prepared first. */
+       ret = avs_component_resume_prepare(component, true);
+       if (ret)
+               return ret;
+
+       return avs_component_resume_prepare(component, false);
+}
+
+static const struct snd_pcm_hardware avs_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+       .buffer_bytes_max       = AZX_MAX_BUF_SIZE,
+       .period_bytes_min       = 128,
+       .period_bytes_max       = AZX_MAX_BUF_SIZE / 2,
+       .periods_min            = 2,
+       .periods_max            = AZX_MAX_FRAG,
+       .fifo_size              = 0,
+};
+
 static int avs_component_open(struct snd_soc_component *component,
                              struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct snd_pcm_hardware hwparams;
 
        /* only FE DAI links are handled here */
        if (rtd->dai_link->no_pcm)
                return 0;
 
-       hwparams.info = SNDRV_PCM_INFO_MMAP |
-                       SNDRV_PCM_INFO_MMAP_VALID |
-                       SNDRV_PCM_INFO_INTERLEAVED |
-                       SNDRV_PCM_INFO_PAUSE |
-                       SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
-
-       hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
-                          SNDRV_PCM_FMTBIT_S24_LE |
-                          SNDRV_PCM_FMTBIT_S32_LE;
-       hwparams.period_bytes_min = 128;
-       hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
-       hwparams.periods_min = 2;
-       hwparams.periods_max = AZX_MAX_FRAG;
-       hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
-       hwparams.fifo_size = 0;
-
-       return snd_soc_set_runtime_hwparams(substream, &hwparams);
+       return snd_soc_set_runtime_hwparams(substream, &avs_pcm_hardware);
 }
 
 static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
@@ -840,6 +1116,8 @@ static const struct snd_soc_component_driver avs_component_driver = {
        .name                   = "avs-pcm",
        .probe                  = avs_component_probe,
        .remove                 = avs_component_remove,
+       .suspend                = avs_component_suspend,
+       .resume                 = avs_component_resume,
        .open                   = avs_component_open,
        .pointer                = avs_component_pointer,
        .mmap                   = avs_component_mmap,
@@ -1016,10 +1294,8 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen
                if (!strstr(dai->driver->name, name))
                        continue;
 
-               if (dai->playback_widget)
-                       snd_soc_dapm_free_widget(dai->playback_widget);
-               if (dai->capture_widget)
-                       snd_soc_dapm_free_widget(dai->capture_widget);
+               snd_soc_dapm_free_widget(dai->playback_widget);
+               snd_soc_dapm_free_widget(dai->capture_widget);
                snd_soc_unregister_dai(dai);
        }
 }
@@ -1122,9 +1398,35 @@ static int avs_component_hda_open(struct snd_soc_component *component,
        struct hdac_ext_stream *link_stream;
        struct hda_codec *codec;
 
-       /* only BE DAI links are handled here */
-       if (!rtd->dai_link->no_pcm)
-               return avs_component_open(component, substream);
+       if (!rtd->dai_link->no_pcm) {
+               struct snd_pcm_hardware hwparams = avs_pcm_hardware;
+               struct snd_soc_pcm_runtime *be;
+               struct snd_soc_dpcm *dpcm;
+               int dir = substream->stream;
+
+               /*
+                * Support the DPCM reparenting while still fulfilling expectations of HDAudio
+                * common code - a valid stream pointer at substream->runtime->private_data -
+                * by having all FEs point to the same private data.
+                */
+               for_each_dpcm_be(rtd, dir, dpcm) {
+                       struct snd_pcm_substream *be_substream;
+
+                       be = dpcm->be;
+                       if (be->dpcm[dir].users == 1)
+                               break;
+
+                       be_substream = snd_soc_dpcm_get_substream(be, dir);
+                       substream->runtime->private_data = be_substream->runtime->private_data;
+                       break;
+               }
+
+               /* RESUME unsupported for de-coupled HD-Audio capture. */
+               if (dir == SNDRV_PCM_STREAM_CAPTURE)
+                       hwparams.info &= ~SNDRV_PCM_INFO_RESUME;
+
+               return snd_soc_set_runtime_hwparams(substream, &hwparams);
+       }
 
        codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
        link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,
@@ -1157,6 +1459,8 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
        .name                   = "avs-hda-pcm",
        .probe                  = avs_component_hda_probe,
        .remove                 = avs_component_hda_remove,
+       .suspend                = avs_component_suspend,
+       .resume                 = avs_component_resume,
        .open                   = avs_component_hda_open,
        .close                  = avs_component_hda_close,
        .pointer                = avs_component_pointer,
index bda5ec7..dc98b5c 100644 (file)
@@ -28,12 +28,12 @@ static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
 
        info->core_mask = resource_mask;
        if (enable)
-               for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0)) {
+               for_each_set_bit(i, &resource_mask, num_cores) {
                        info->logs_core[i].enable = enable;
                        info->logs_core[i].min_priority = *priorities++;
                }
        else
-               for_each_set_bit(i, &resource_mask, GENMASK(num_cores, 0))
+               for_each_set_bit(i, &resource_mask, num_cores)
                        info->logs_core[i].enable = enable;
 
        ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
index 8a9f9fc..e845eaf 100644 (file)
@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
        if (!le32_to_cpu(dw->priv.size))
                return 0;
 
+       if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+               dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+               w->ignore_suspend = false;
+       }
+
        tplg = acomp->tplg;
        mach = dev_get_platdata(comp->card->dev);
 
@@ -1442,6 +1447,11 @@ static int avs_dai_load(struct snd_soc_component *comp, int index,
 static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
                         struct snd_soc_tplg_link_config *cfg)
 {
+       if (link->ignore_suspend && !AVS_S0IX_SUPPORTED) {
+               dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
+               link->ignore_suspend = false;
+       }
+
        if (!link->no_pcm) {
                /* Stream control handled by IPCs. */
                link->nonatomic = true;
index aa12d7e..a472de1 100644 (file)
@@ -668,6 +668,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
        select SND_SOC_RT1308_SDW
        select SND_SOC_RT1308
        select SND_SOC_RT1316_SDW
+       select SND_SOC_RT1318_SDW
        select SND_SOC_RT715_SDW
        select SND_SOC_RT715_SDCA_SDW
        select SND_SOC_RT5682_SDW
index 53458e7..7e1a4ff 100644 (file)
@@ -37,8 +37,8 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
 snd-soc-ehl-rt5660-objs := ehl_rt5660.o
 snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
 snd-soc-sof-sdw-objs += sof_sdw.o                              \
-                       sof_sdw_max98373.o                      \
-                       sof_sdw_rt1308.o sof_sdw_rt1316.o       \
+                       sof_sdw_max98373.o sof_sdw_rt1308.o     \
+                       sof_sdw_rt1316.o sof_sdw_rt1318.o       \
                        sof_sdw_rt5682.o sof_sdw_rt700.o        \
                        sof_sdw_rt711.o sof_sdw_rt711_sdca.o    \
                        sof_sdw_rt715.o sof_sdw_rt715_sdca.o    \
index 67c3f49..d0682bc 100644 (file)
@@ -88,7 +88,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
        struct snd_interval *chan = hw_param_interval(params,
                                                      SNDRV_PCM_HW_PARAM_CHANNELS);
 
-       /* The ADSP will covert the FE rate to 48k, max 4-channels */
+       /* The ADSP will convert the FE rate to 48k, max 4-channels */
        rate->min = rate->max = 48000;
        chan->min = 2;
        chan->max = 4;
index 3148870..f3e08d2 100644 (file)
@@ -141,7 +141,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
        struct snd_interval *chan = hw_param_interval(params,
                                                      SNDRV_PCM_HW_PARAM_CHANNELS);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        chan->min = chan->max = 2;
 
index 7c6c95e..c593995 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/soc-acpi.h>
 #include "../../codecs/hdac_hdmi.h"
 #include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
 #include "../common/soc-intel-quirks.h"
 #include "hda_dsp_common.h"
 
@@ -259,7 +258,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3,
                         KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, &broxton_headset);
+       snd_soc_component_set_jack(component, &broxton_headset, NULL);
 
        snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
index 4bd93c3..bf89fe8 100644 (file)
@@ -210,7 +210,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
                                        SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        chan->min = chan->max = 2;
 
index ae89986..41cec67 100644 (file)
@@ -111,7 +111,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
                hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret;
 
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       /* The DSP will convert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 6432b83..cdcb448 100644 (file)
@@ -243,7 +243,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret, bits;
 
-       /* The DSP will covert the FE rate to 48k, stereo */
+       /* The DSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index fb9d9e2..6db07b2 100644 (file)
@@ -1390,7 +1390,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret, bits;
 
-       /* The DSP will covert the FE rate to 48k, stereo */
+       /* The DSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 2beb686..81ac6ee 100644 (file)
@@ -683,7 +683,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret, bits;
 
-       /* The DSP will covert the FE rate to 48k, stereo */
+       /* The DSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 45a6805..1669eb3 100644 (file)
@@ -248,7 +248,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                                                          SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret;
 
-       /* The DSP will covert the FE rate to 48k, stereo */
+       /* The DSP will convert the FE rate to 48k, stereo */
        rate->min = 48000;
        rate->max = 48000;
        channels->min = 2;
index 64eb735..2c086e9 100644 (file)
@@ -272,7 +272,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                return ret;
        }
 
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       /* The DSP will convert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 4c1d83b..af2d9a7 100644 (file)
@@ -136,7 +136,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        int ret;
 
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       /* The DSP will convert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 96501ae..25a054b 100644 (file)
@@ -344,7 +344,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        struct snd_interval *channels = hw_param_interval(params,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
 
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       /* The DSP will convert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index ca47f64..49d3da8 100644 (file)
@@ -270,7 +270,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
        int ret, bits;
 
-       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       /* The DSP will convert the FE rate to 48k, stereo, 24bits */
        rate->min = rate->max = 48000;
        channels->min = channels->max = 2;
 
index 329457e..18365ce 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/soc.h>
 #include "../../codecs/da7219.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
 
 #define KBL_DIALOG_CODEC_DAI "da7219-hifi"
 #define KBL_MAXIM_CODEC_DAI "HiFi"
@@ -207,7 +206,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
-       da7219_aad_jack_det(component, &ctx->kabylake_headset);
+       snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
 
        ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
        if (ret)
index 362579f..ad4223f 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/soc.h>
 #include "../../codecs/da7219.h"
 #include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219-aad.h"
 
 #define KBL_DIALOG_CODEC_DAI   "da7219-hifi"
 #define MAX98927_CODEC_DAI     "max98927-aif1"
@@ -382,7 +381,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, &ctx->kabylake_headset);
+       snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
 
        return 0;
 }
index 8dceb0b..e13a5a4 100644 (file)
@@ -154,7 +154,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
                        SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        chan->min = chan->max = 2;
 
index 62c0d46..575604d 100644 (file)
@@ -333,7 +333,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
-       /* The ADSP will covert the FE rate to 48k, stereo */
+       /* The ADSP will convert the FE rate to 48k, stereo */
        rate->min = rate->max = 48000;
        chan->min = chan->max = 2;
 
index 6e39eda..851c516 100644 (file)
@@ -155,7 +155,7 @@ static const char * const cs35l41_name_prefixes[] = { "WL", "WR", "TL", "TR" };
  */
 static int cs35l41_compute_codec_conf(void)
 {
-       const char * const uid_strings[] = { "0", "1", "2", "3" };
+       static const char * const uid_strings[] = { "0", "1", "2", "3" };
        unsigned int uid, sz = 0;
        struct acpi_device *adev;
        struct device *physdev;
index e048e78..740aa11 100644 (file)
@@ -7,13 +7,13 @@
 
 #include <linux/input.h>
 #include <linux/module.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/platform_device.h>
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include "../../codecs/da7219.h"
-#include "../../codecs/da7219-aad.h"
 #include "hda_dsp_common.h"
 
 #define DIALOG_CODEC_DAI       "da7219-hifi"
@@ -184,7 +184,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
-       da7219_aad_jack_det(component, jack);
+       snd_soc_component_set_jack(component, jack, NULL);
 
        return ret;
 }
index 5585c21..2788022 100644 (file)
@@ -47,6 +47,7 @@
 #define SOF_RT1019P_SPEAKER_AMP_PRESENT        BIT(14)
 #define SOF_MAX98373_SPEAKER_AMP_PRESENT       BIT(15)
 #define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(16)
+#define SOF_RT1015P_SPEAKER_AMP_PRESENT        BIT(17)
 
 static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
 
@@ -483,6 +484,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                } else if (sof_nau8825_quirk &
                                SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
                        max_98360a_dai_link(&links[id]);
+               } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
+                       sof_rt1015p_dai_link(&links[id]);
                } else {
                        goto devm_err;
                }
@@ -576,6 +579,8 @@ static int sof_audio_probe(struct platform_device *pdev)
 
        if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
                max_98373_set_codec_conf(&sof_audio_card_nau8825);
+       else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
+               sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
 
        if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
                sof_audio_card_nau8825.num_links++;
@@ -642,6 +647,16 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
 
        },
+       {
+               .name = "adl_rt1015p_nau8825",
+               .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT1015P_SPEAKER_AMP_PRESENT |
+                                       SOF_NAU8825_SSP_AMP(1) |
+                                       SOF_NAU8825_NUM_HDMIDEV(4) |
+                                       SOF_BT_OFFLOAD_SSP(2) |
+                                       SOF_SSP_BT_OFFLOAD_PRESENT),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
@@ -663,3 +678,4 @@ MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
index 2358be2..4a2f912 100644 (file)
@@ -867,10 +867,6 @@ static int sof_audio_probe(struct platform_device *pdev)
        if (acpi_dev_present("RTL5682", NULL, -1))
                sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
 
-       /* Detect the headset codec variant to support machines in DMI quirk */
-       if (acpi_dev_present("RTL5682", NULL, -1))
-               sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
-
        if (soc_intel_is_byt() || soc_intel_is_cht()) {
                is_legacy_cpu = 1;
                dmic_be_num = 0;
@@ -1092,10 +1088,9 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
        {
-               .name = "adl_rt1019_rt5682s",
+               .name = "adl_rt1019_rt5682",
                .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
                                        SOF_RT5682_SSP_CODEC(0) |
-                                       SOF_RT5682S_HEADPHONE_CODEC_PRESENT |
                                        SOF_SPEAKER_AMP_PRESENT |
                                        SOF_RT1019_SPEAKER_AMP_PRESENT |
                                        SOF_RT5682_SSP_AMP(1) |
index ee9857d..b58c7b3 100644 (file)
@@ -355,6 +355,47 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                .driver_data = (void *)(SOF_SDW_TGL_HDMI |
                                        RT711_JD2),
        },
+       /* RaptorLake devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
+               },
+               /* No Jack */
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
        /* MeteorLake devices */
        {
                .callback = sof_sdw_quirk_cb,
@@ -510,6 +551,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
                .dai_name = "rt1308-aif",
                .ops = &sof_sdw_rt1308_i2s_ops,
                .init = sof_sdw_rt1308_init,
+               .exit = sof_sdw_rt1308_exit,
                .codec_type = SOF_SDW_CODEC_TYPE_AMP,
        },
        {
@@ -517,6 +559,14 @@ static struct sof_sdw_codec_info codec_info_list[] = {
                .direction = {true, true},
                .dai_name = "rt1316-aif",
                .init = sof_sdw_rt1316_init,
+               .exit = sof_sdw_rt1316_exit,
+               .codec_type = SOF_SDW_CODEC_TYPE_AMP,
+       },
+       {
+               .part_id = 0x1318,
+               .direction = {true, true},
+               .dai_name = "rt1318-aif",
+               .init = sof_sdw_rt1318_init,
                .codec_type = SOF_SDW_CODEC_TYPE_AMP,
        },
        {
diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
new file mode 100644 (file)
index 0000000..4a3e6fd
--- /dev/null
@@ -0,0 +1,300 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ */
+
+/*
+ *  sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters
+ */
+
+#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H
+#define SND_SOC_SOF_SDW_AMP_COEFF_H
+
+#define RT1308_MAX_BQ_REG 480
+#define RT1316_MAX_BQ_REG 580
+
+static const u8 __maybe_unused dell_0a5d_bq_params[] = {
+       0xb0, 0xc5, 0x00,  /* address: 0xc5b0; data: 0x00 */
+       0xb1, 0xc5, 0x32,
+       0xb2, 0xc5, 0x44,
+       0xb3, 0xc5, 0x19,
+       0xc0, 0xc5, 0x04,
+       0xc1, 0xc5, 0x00,
+       0xc2, 0xc5, 0x00,
+       0xc3, 0xc5, 0x00,
+       0xd0, 0xc5, 0x02,
+       0xd1, 0xc5, 0x00,
+       0xd2, 0xc5, 0x00,
+       0xd3, 0xc5, 0x00,
+       0xe0, 0xc5, 0x01,
+       0xe1, 0xc5, 0xe8,
+       0xe2, 0xc5, 0x5f,
+       0xe3, 0xc5, 0x8a,
+       0xf0, 0xc5, 0x1f,
+       0xf1, 0xc5, 0x4e,
+       0xf2, 0xc5, 0x90,
+       0xf3, 0xc5, 0x11,
+       0x50, 0xc6, 0x01,
+       0x51, 0xc6, 0xff,
+       0x52, 0xc6, 0x45,
+       0x53, 0xc6, 0x41,
+       0x60, 0xc6, 0x1c,
+       0x61, 0xc6, 0x00,
+       0x62, 0xc6, 0x00,
+       0x63, 0xc6, 0x00,
+       0x70, 0xc6, 0x02,
+       0x71, 0xc6, 0x00,
+       0x72, 0xc6, 0x00,
+       0x73, 0xc6, 0x00,
+       0x80, 0xc6, 0x03,
+       0x81, 0xc6, 0xfe,
+       0x82, 0xc6, 0x89,
+       0x83, 0xc6, 0xfa,
+       0x90, 0xc6, 0x1e,
+       0x91, 0xc6, 0x01,
+       0x92, 0xc6, 0x74,
+       0x93, 0xc6, 0xf6,
+       0x00, 0xc6, 0x01,
+       0x01, 0xc6, 0xd9,
+       0x02, 0xc6, 0xfb,
+       0x03, 0xc6, 0xc4,
+       0x10, 0xc6, 0x1c,
+       0x11, 0xc6, 0x00,
+       0x12, 0xc6, 0x00,
+       0x13, 0xc6, 0x00,
+       0x20, 0xc6, 0x02,
+       0x21, 0xc6, 0x00,
+       0x22, 0xc6, 0x00,
+       0x23, 0xc6, 0x00,
+       0x30, 0xc6, 0x03,
+       0x31, 0xc6, 0xaf,
+       0x32, 0xc6, 0x23,
+       0x33, 0xc6, 0xcb,
+       0x40, 0xc6, 0x1e,
+       0x41, 0xc6, 0x47,
+       0x42, 0xc6, 0x34,
+       0x43, 0xc6, 0xba,
+       0xa0, 0xc6, 0x01,
+       0xa1, 0xc6, 0xff,
+       0xa2, 0xc6, 0x45,
+       0xa3, 0xc6, 0x41,
+       0xb0, 0xc6, 0x1c,
+       0xb1, 0xc6, 0x00,
+       0xb2, 0xc6, 0x00,
+       0xb3, 0xc6, 0x00,
+       0xc0, 0xc6, 0x02,
+       0xc1, 0xc6, 0x00,
+       0xc2, 0xc6, 0x00,
+       0xc3, 0xc6, 0x00,
+       0xd0, 0xc6, 0x03,
+       0xd1, 0xc6, 0xfe,
+       0xd2, 0xc6, 0x89,
+       0xd3, 0xc6, 0xfa,
+       0xe0, 0xc6, 0x1e,
+       0xe1, 0xc6, 0x01,
+       0xe2, 0xc6, 0x74,
+       0xe3, 0xc6, 0xf6,
+       0x40, 0xc5, 0x0d,
+       0x30, 0xc7, 0x15,
+       0x31, 0xc7, 0x7c,
+       0x32, 0xc7, 0x0f,
+       0x33, 0xc7, 0xa0,
+       0x40, 0xc7, 0x00,
+       0x41, 0xc7, 0x00,
+       0x42, 0xc7, 0xf8,
+       0x43, 0xc7, 0xf8,
+       0x50, 0xc7, 0x00,
+       0x51, 0xc7, 0x00,
+       0x52, 0xc7, 0x00,
+       0x53, 0xc7, 0x01,
+       0x90, 0xc7, 0x00,
+       0x91, 0xc7, 0x14,
+       0x92, 0xc7, 0x00,
+       0x93, 0xc7, 0x14,
+       0xa0, 0xc7, 0x00,
+       0xa1, 0xc7, 0x00,
+       0xa2, 0xc7, 0xf8,
+       0xa3, 0xc7, 0xf8,
+       0xb0, 0xc7, 0x00,
+       0xb1, 0xc7, 0x00,
+       0xb2, 0xc7, 0x00,
+       0xb3, 0xc7, 0x00,
+       0x60, 0xc7, 0x03,
+       0x61, 0xc7, 0xe8,
+       0x62, 0xc7, 0x03,
+       0x63, 0xc7, 0xb6,
+       0x70, 0xc7, 0x00,
+       0x71, 0xc7, 0x00,
+       0x72, 0xc7, 0xf8,
+       0x73, 0xc7, 0xf8,
+       0x80, 0xc7, 0x00,
+       0x81, 0xc7, 0x00,
+       0x82, 0xc7, 0x00,
+       0x83, 0xc7, 0x00,
+       0xc0, 0xc7, 0x00,
+       0xc1, 0xc7, 0x14,
+       0xc2, 0xc7, 0x00,
+       0xc3, 0xc7, 0x14,
+       0xd0, 0xc7, 0x00,
+       0xd1, 0xc7, 0x00,
+       0xd2, 0xc7, 0xf8,
+       0xd3, 0xc7, 0xf8,
+       0xe0, 0xc7, 0x00,
+       0xe1, 0xc7, 0x00,
+       0xe2, 0xc7, 0x00,
+       0xe3, 0xc7, 0x00,
+       0x60, 0xc5, 0x02,
+       0x61, 0xc5, 0x00,
+       0x62, 0xc5, 0x00,
+       0x63, 0xc5, 0x00,
+       0x70, 0xc5, 0x02,
+       0x71, 0xc5, 0x00,
+       0x72, 0xc5, 0x00,
+       0x73, 0xc5, 0x00,
+       0x80, 0xc5, 0x02,
+       0x81, 0xc5, 0x00,
+       0x82, 0xc5, 0x00,
+       0x83, 0xc5, 0x00,
+       0x90, 0xc5, 0x02,
+       0x91, 0xc5, 0x00,
+       0x92, 0xc5, 0x00,
+       0x93, 0xc5, 0x00,
+       0x50, 0xc5, 0x01,
+};
+
+static const u8 __maybe_unused dell_0b00_bq_params[] = {
+       0x03, 0xc2, 0x00,
+       0x04, 0xc2, 0xb2,
+       0x05, 0xc2, 0xe0,
+       0x06, 0xc2, 0x3a,
+       0x07, 0xc2, 0x01,
+       0x08, 0xc2, 0x65,
+       0x09, 0xc2, 0xc0,
+       0x0a, 0xc2, 0x75,
+       0x0b, 0xc2, 0x00,
+       0x0c, 0xc2, 0xb2,
+       0x0d, 0xc2, 0xe0,
+       0x0e, 0xc2, 0x3a,
+       0x0f, 0xc2, 0xf7,
+       0x10, 0xc2, 0x4d,
+       0x11, 0xc2, 0x5b,
+       0x12, 0xc2, 0xe9,
+       0x13, 0xc2, 0x03,
+       0x14, 0xc2, 0x7e,
+       0x15, 0xc2, 0x25,
+       0x16, 0xc2, 0x01,
+       0x17, 0xc2, 0x07,
+       0x18, 0xc2, 0xfd,
+       0x19, 0xc2, 0x15,
+       0x1a, 0xc2, 0x04,
+       0x1b, 0xc2, 0xf0,
+       0x1c, 0xc2, 0x05,
+       0x1d, 0xc2, 0xd5,
+       0x1e, 0xc2, 0xf7,
+       0x1f, 0xc2, 0x07,
+       0x20, 0xc2, 0xfd,
+       0x21, 0xc2, 0x15,
+       0x22, 0xc2, 0x04,
+       0x23, 0xc2, 0xf0,
+       0x24, 0xc2, 0x05,
+       0x25, 0xc2, 0xd8,
+       0x26, 0xc2, 0x17,
+       0x27, 0xc2, 0x07,
+       0x28, 0xc2, 0xfa,
+       0x29, 0xc2, 0x2c,
+       0x2a, 0xc2, 0x29,
+       0x2b, 0xc2, 0x07,
+       0x2c, 0xc2, 0x74,
+       0x2d, 0xc2, 0xe0,
+       0x2e, 0xc2, 0x33,
+       0x2f, 0xc2, 0xf1,
+       0x30, 0xc2, 0x16,
+       0x31, 0xc2, 0x3f,
+       0x32, 0xc2, 0x9b,
+       0x33, 0xc2, 0x07,
+       0x34, 0xc2, 0x74,
+       0x35, 0xc2, 0xe0,
+       0x36, 0xc2, 0x33,
+       0x37, 0xc2, 0xf1,
+       0x38, 0xc2, 0x29,
+       0x39, 0xc2, 0xb0,
+       0x3a, 0xc2, 0x4d,
+       0x3b, 0xc2, 0x06,
+       0x3c, 0xc2, 0xfd,
+       0x3d, 0xc2, 0x31,
+       0x3e, 0xc2, 0x18,
+       0x3f, 0xc2, 0x07,
+       0x40, 0xc2, 0xfd,
+       0x41, 0xc2, 0x15,
+       0x42, 0xc2, 0x04,
+       0x43, 0xc2, 0xf0,
+       0x44, 0xc2, 0x05,
+       0x45, 0xc2, 0xd5,
+       0x46, 0xc2, 0xf7,
+       0x47, 0xc2, 0x07,
+       0x48, 0xc2, 0xfd,
+       0x49, 0xc2, 0x15,
+       0x4a, 0xc2, 0x04,
+       0x4b, 0xc2, 0xf0,
+       0x4c, 0xc2, 0x05,
+       0x4d, 0xc2, 0xd8,
+       0x4e, 0xc2, 0x17,
+       0x4f, 0xc2, 0x07,
+       0x50, 0xc2, 0xfa,
+       0x51, 0xc2, 0x2c,
+       0x52, 0xc2, 0x29,
+       0x0b, 0xc0, 0x30,
+       0x80, 0xc3, 0x13,
+       0x81, 0xc3, 0x88,
+       0x82, 0xc3, 0x17,
+       0x83, 0xc3, 0x70,
+       0x84, 0xc3, 0x00,
+       0x85, 0xc3, 0x00,
+       0x86, 0xc3, 0xff,
+       0x87, 0xc3, 0xee,
+       0x88, 0xc3, 0x02,
+       0x92, 0xc3, 0x00,
+       0x93, 0xc3, 0x14,
+       0x94, 0xc3, 0x00,
+       0x95, 0xc3, 0x14,
+       0x96, 0xc3, 0x00,
+       0x97, 0xc3, 0x00,
+       0x98, 0xc3, 0x00,
+       0x99, 0xc3, 0x00,
+       0x9a, 0xc3, 0x01,
+       0x89, 0xc3, 0x03,
+       0x8a, 0xc3, 0xe8,
+       0x8b, 0xc3, 0x03,
+       0x8c, 0xc3, 0xb6,
+       0x8d, 0xc3, 0x00,
+       0x8e, 0xc3, 0x00,
+       0x8f, 0xc3, 0xff,
+       0x90, 0xc3, 0xee,
+       0x91, 0xc3, 0x01,
+       0x9b, 0xc3, 0x00,
+       0x9c, 0xc3, 0x14,
+       0x9d, 0xc3, 0x00,
+       0x9e, 0xc3, 0x14,
+       0x9f, 0xc3, 0x00,
+       0xa0, 0xc3, 0x00,
+       0xa1, 0xc3, 0x00,
+       0xa2, 0xc3, 0x00,
+       0xa3, 0xc3, 0x01,
+       0x61, 0xc2, 0x08,
+       0x62, 0xc2, 0x00,
+       0x63, 0xc2, 0x00,
+       0x64, 0xc2, 0x00,
+       0x65, 0xc2, 0x08,
+       0x66, 0xc2, 0x00,
+       0x67, 0xc2, 0x00,
+       0x68, 0xc2, 0x00,
+       0x69, 0xc2, 0x08,
+       0x6a, 0xc2, 0x00,
+       0x6b, 0xc2, 0x00,
+       0x6c, 0xc2, 0x00,
+       0x6d, 0xc2, 0x08,
+       0x6e, 0xc2, 0x00,
+       0x6f, 0xc2, 0x00,
+       0x70, 0xc2, 0x00,
+       0x00, 0xc2, 0xc0,
+};
+
+#endif
index e245773..54a50f7 100644 (file)
@@ -83,6 +83,7 @@ struct mc_private {
        bool idisp_codec;
        struct snd_soc_jack sdw_headset;
        struct device *headset_codec_dev; /* only one headset per card */
+       struct device *amp_dev1, *amp_dev2;
 };
 
 extern unsigned long sof_sdw_quirk;
@@ -132,6 +133,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
                        struct snd_soc_dai_link *dai_links,
                        struct sof_sdw_codec_info *info,
                        bool playback);
+int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
 
 /* RT1316 support */
 int sof_sdw_rt1316_init(struct snd_soc_card *card,
@@ -139,6 +141,14 @@ int sof_sdw_rt1316_init(struct snd_soc_card *card,
                        struct snd_soc_dai_link *dai_links,
                        struct sof_sdw_codec_info *info,
                        bool playback);
+int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
+
+/* RT1318 support */
+int sof_sdw_rt1318_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);
 
 /* RT715 support */
 int sof_sdw_rt715_init(struct snd_soc_card *card,
index f078fb1..a19b055 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/dmi.h>
 #include "sof_sdw_common.h"
+#include "sof_sdw_amp_coeff_tables.h"
 #include "../../codecs/rt1308.h"
 
+struct rt1308_platform_data {
+       const unsigned char *bq_params;
+       const unsigned int bq_params_cnt;
+};
+
+static const struct rt1308_platform_data dell_0a5d_platform_data = {
+       .bq_params = dell_0a5d_bq_params,
+       .bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params),
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+       /* CometLake devices */
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990")
+               },
+               .driver_data = (void *)&dell_0a5d_platform_data,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F")
+               },
+               .driver_data = (void *)&dell_0a5d_platform_data,
+       },
+       /* TigerLake devices */
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
+               },
+               .driver_data = (void *)&dell_0a5d_platform_data,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+               },
+               .driver_data = (void *)&dell_0a5d_platform_data,
+       },
+};
+
+static int rt1308_add_device_props(struct device *sdw_dev)
+{
+       struct property_entry props[3] = {};
+       struct fwnode_handle *fwnode;
+       const struct dmi_system_id *dmi_data;
+       const struct rt1308_platform_data *pdata;
+       unsigned char params[RT1308_MAX_BQ_REG];
+       int ret;
+
+       dmi_data = dmi_first_match(dmi_platform_data);
+       if (!dmi_data)
+               return 0;
+
+       pdata = dmi_data->driver_data;
+       memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
+
+       props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
+       props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
+
+       fwnode = fwnode_create_software_node(props, NULL);
+       if (IS_ERR(fwnode))
+               return PTR_ERR(fwnode);
+
+       ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+       fwnode_handle_put(fwnode);
+
+       return ret;
+}
+
 static const struct snd_soc_dapm_widget rt1308_widgets[] = {
        SND_SOC_DAPM_SPK("Speaker", NULL),
 };
@@ -127,12 +204,33 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
        .hw_params = rt1308_i2s_hw_params,
 };
 
+int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+       struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+       if (ctx->amp_dev1) {
+               device_remove_software_node(ctx->amp_dev1);
+               put_device(ctx->amp_dev1);
+       }
+
+       if (ctx->amp_dev2) {
+               device_remove_software_node(ctx->amp_dev2);
+               put_device(ctx->amp_dev2);
+       }
+
+       return 0;
+}
+
 int sof_sdw_rt1308_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)
 {
+       struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+       struct device *sdw_dev1, *sdw_dev2;
+       int ret;
+
        /* Count amp number and do init on playback link only. */
        if (!playback)
                return 0;
@@ -142,6 +240,28 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
                dai_links->init = first_spk_init;
 
        if (info->amp_num == 2) {
+               sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+               if (!sdw_dev1)
+                       return -EPROBE_DEFER;
+
+               ret = rt1308_add_device_props(sdw_dev1);
+               if (ret < 0) {
+                       put_device(sdw_dev1);
+                       return ret;
+               }
+               ctx->amp_dev1 = sdw_dev1;
+
+               sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+               if (!sdw_dev2)
+                       return -EPROBE_DEFER;
+
+               ret = rt1308_add_device_props(sdw_dev2);
+               if (ret < 0) {
+                       put_device(sdw_dev2);
+                       return ret;
+               }
+               ctx->amp_dev2 = sdw_dev2;
+
                /*
                 * if two 1308s are in one dai link, the init function
                 * in this dai link will be first set for the first speaker,
index 58194b3..f6bbea0 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-dapm.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/dmi.h>
 #include "sof_sdw_common.h"
+#include "sof_sdw_amp_coeff_tables.h"
+
+struct rt1316_platform_data {
+       const unsigned char *bq_params;
+       const unsigned int bq_params_cnt;
+};
+
+static const struct rt1316_platform_data dell_0b00_platform_data = {
+       .bq_params = dell_0b00_bq_params,
+       .bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+       /* AlderLake devices */
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
+               },
+               .driver_data = (void *)&dell_0b00_platform_data,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
+               },
+               .driver_data = (void *)&dell_0b00_platform_data,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
+               },
+               .driver_data = (void *)&dell_0b00_platform_data,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+               },
+               .driver_data = (void *)&dell_0b00_platform_data,
+       },
+};
+
+static int rt1316_add_device_props(struct device *sdw_dev)
+{
+       struct property_entry props[3] = {};
+       struct fwnode_handle *fwnode;
+       const struct dmi_system_id *dmi_data;
+       const struct rt1316_platform_data *pdata;
+       unsigned char params[RT1316_MAX_BQ_REG];
+       int ret;
+
+       dmi_data = dmi_first_match(dmi_platform_data);
+       if (!dmi_data)
+               return 0;
+
+       pdata = dmi_data->driver_data;
+       memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
+
+       props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
+       props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
+
+       fwnode = fwnode_create_software_node(props, NULL);
+       if (IS_ERR(fwnode))
+               return PTR_ERR(fwnode);
+
+       ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
+
+       fwnode_handle_put(fwnode);
+
+       return ret;
+}
 
 static const struct snd_soc_dapm_widget rt1316_widgets[] = {
        SND_SOC_DAPM_SPK("Speaker", NULL),
@@ -89,12 +165,33 @@ static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
        return second_spk_init(rtd);
 }
 
+int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+       struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+       if (ctx->amp_dev1) {
+               device_remove_software_node(ctx->amp_dev1);
+               put_device(ctx->amp_dev1);
+       }
+
+       if (ctx->amp_dev2) {
+               device_remove_software_node(ctx->amp_dev2);
+               put_device(ctx->amp_dev2);
+       }
+
+       return 0;
+}
+
 int sof_sdw_rt1316_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)
 {
+       struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+       struct device *sdw_dev1, *sdw_dev2;
+       int ret;
+
        /* Count amp number and do init on playback link only. */
        if (!playback)
                return 0;
@@ -104,6 +201,28 @@ int sof_sdw_rt1316_init(struct snd_soc_card *card,
                dai_links->init = first_spk_init;
 
        if (info->amp_num == 2) {
+               sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
+               if (!sdw_dev1)
+                       return -EPROBE_DEFER;
+
+               ret = rt1316_add_device_props(sdw_dev1);
+               if (ret < 0) {
+                       put_device(sdw_dev1);
+                       return ret;
+               }
+               ctx->amp_dev1 = sdw_dev1;
+
+               sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
+               if (!sdw_dev2)
+                       return -EPROBE_DEFER;
+
+               ret = rt1316_add_device_props(sdw_dev2);
+               if (ret < 0) {
+                       put_device(sdw_dev2);
+                       return ret;
+               }
+               ctx->amp_dev2 = sdw_dev2;
+
                /*
                 * if two 1316s are in one dai link, the init function
                 * in this dai link will be first set for the first speaker,
diff --git a/sound/soc/intel/boards/sof_sdw_rt1318.c b/sound/soc/intel/boards/sof_sdw_rt1318.c
new file mode 100644 (file)
index 0000000..dbee4bf
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2022 Intel Corporation
+
+/*
+ *  sof_sdw_rt1318 - Helpers to handle RT1318 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include "sof_sdw_common.h"
+
+static const struct snd_soc_dapm_widget rt1318_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/*
+ * dapm routes for rt1318 will be registered dynamically according
+ * to the number of rt1318 used. The first two entries will be registered
+ * for one codec case, and the last two entries are also registered
+ * if two 1318s are used.
+ */
+static const struct snd_soc_dapm_route rt1318_map[] = {
+       { "Speaker", NULL, "rt1318-1 SPOL" },
+       { "Speaker", NULL, "rt1318-1 SPOR" },
+       { "Speaker", NULL, "rt1318-2 SPOL" },
+       { "Speaker", NULL, "rt1318-2 SPOR" },
+};
+
+static const struct snd_kcontrol_new rt1318_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int first_spk_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:rt1318",
+                                         card->components);
+       if (!card->components)
+               return -ENOMEM;
+
+       ret = snd_soc_add_card_controls(card, rt1318_controls,
+                                       ARRAY_SIZE(rt1318_controls));
+       if (ret) {
+               dev_err(card->dev, "rt1318 controls addition failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dapm_new_controls(&card->dapm, rt1318_widgets,
+                                       ARRAY_SIZE(rt1318_widgets));
+       if (ret) {
+               dev_err(card->dev, "rt1318 widgets addition failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map, 2);
+       if (ret)
+               dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
+
+       return ret;
+}
+
+static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       int ret;
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map + 2, 2);
+       if (ret)
+               dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
+
+       return ret;
+}
+
+static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+
+       ret = first_spk_init(rtd);
+       if (ret)
+               return ret;
+
+       return second_spk_init(rtd);
+}
+
+int sof_sdw_rt1318_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)
+{
+       /* Count amp number and do init on playback link only. */
+       if (!playback)
+               return 0;
+
+       info->amp_num++;
+       if (info->amp_num == 1)
+               dai_links->init = first_spk_init;
+
+       if (info->amp_num == 2) {
+               /*
+                * if two 1318s are in one dai link, the init function
+                * in this dai link will be first set for the first speaker,
+                * and it should be reset to initialize all speakers when
+                * the second speaker is found.
+                */
+               if (dai_links->init)
+                       dai_links->init = all_spk_init;
+               else
+                       dai_links->init = second_spk_init;
+       }
+
+       return 0;
+}
index 9990d55..60aee56 100644 (file)
@@ -430,6 +430,11 @@ static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
        .codecs = {"10EC5682", "RTL5682"},
 };
 
+static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
+       .num_codecs = 1,
+       .codecs = {"RTL1015"}
+};
+
 static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
        .num_codecs = 1,
        .codecs = {"RTL1019"}
@@ -489,14 +494,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
                .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
        },
        {
-               .id = "RTL5682",
-               .drv_name = "adl_rt1019_rt5682s",
+               .comp_ids = &adl_rt5682_rt5682s_hp,
+               .drv_name = "adl_rt1019_rt5682",
                .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_rt1015p_nau8825",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &adl_rt1015p_amp,
+               .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
+       },
+       {
+               .id = "10508825",
                .drv_name = "sof_nau8825",
                .sof_tplg_filename = "sof-adl-nau8825.tplg",
        },
index 36c361f..b1a66a0 100644 (file)
@@ -39,6 +39,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = {
        .group_id = 0,
 };
 
+static const struct snd_soc_acpi_endpoint spk_l_endpoint = {
+       .num = 0,
+       .aggregated = 1,
+       .group_position = 0,
+       .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
+       .num = 0,
+       .aggregated = 1,
+       .group_position = 1,
+       .group_id = 1,
+};
+
 static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
        {
                .adr = 0x000030025D071101ull,
@@ -48,6 +62,45 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device mx8373_0_adr[] = {
+       {
+               .adr = 0x000023019F837300ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_l_endpoint,
+               .name_prefix = "Left"
+       },
+       {
+               .adr = 0x000027019F837300ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "Right"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = {
+       {
+               .adr = 0x000221025D568200ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt5682"
+       }
+};
+
+static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = {
+       /* Expected order: jack -> amp */
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt5682_2_adr),
+               .adr_d = rt5682_2_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(mx8373_0_adr),
+               .adr_d = mx8373_0_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
        {
                .mask = BIT(0),
@@ -84,6 +137,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-mtl-rt711.tplg",
        },
+       {
+               .link_mask = BIT(0) | BIT(2),
+               .links = rt5682_link2_max98373_link0,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg",
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
index 9ccf737..3c5229f 100644 (file)
@@ -56,6 +56,15 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt711_sdca_2_adr[] = {
+       {
+               .adr = 0x000230025D071101ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt711"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
        {
                .adr = 0x000131025D131601ull, /* unique ID is set for some reason */
@@ -65,6 +74,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = {
+       {
+               .adr = 0x000230025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "rt1316-2"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
        {
                .adr = 0x000330025D131601ull,
@@ -74,6 +92,51 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt1316_0_group2_adr[] = {
+       {
+               .adr = 0x000030025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_l_endpoint,
+               .name_prefix = "rt1316-1"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
+       {
+               .adr = 0x000131025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "rt1316-2"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+       {
+               .adr = 0x000131025D131801ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_l_endpoint,
+               .name_prefix = "rt1318-1"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+       {
+               .adr = 0x000230025D131801ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "rt1318-2"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+       {
+               .adr = 0x000030025D071401ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt714"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
        {
                .adr = 0x000230025D071401ull,
@@ -83,6 +146,15 @@ static const struct snd_soc_acpi_adr_device rt714_2_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt714_3_adr[] = {
+       {
+               .adr = 0x000330025D071401ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt714"
+       }
+};
+
 static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
        {
                .mask = BIT(0),
@@ -107,6 +179,73 @@ static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt714_link3[] = {
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
+               .adr_d = rt711_sdca_2_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+               .adr_d = rt1316_0_group2_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+               .adr_d = rt1316_1_group2_adr,
+       },
+       {
+               .mask = BIT(3),
+               .num_adr = ARRAY_SIZE(rt714_3_adr),
+               .adr_d = rt714_3_adr,
+       },
+       {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+               .adr_d = rt1318_1_group1_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+               .adr_d = rt1318_2_group1_adr,
+       },
+       {
+               .mask = BIT(3),
+               .num_adr = ARRAY_SIZE(rt714_3_adr),
+               .adr_d = rt714_3_adr,
+       },
+       {}
+};
+
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1316_1_group1_adr),
+               .adr_d = rt1316_1_group1_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+               .adr_d = rt1316_2_group1_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt714_0_adr),
+               .adr_d = rt714_0_adr,
+       },
+       {}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
        {},
 };
@@ -121,6 +260,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
                .sof_tplg_filename = "sof-rpl-rt711-l0-rt1316-l13-rt714-l2.tplg",
        },
        {
+               .link_mask = 0xF, /* 4 active links required */
+               .links = rpl_sdw_rt711_link2_rt1316_link01_rt714_link3,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01-rt714-l3.tplg",
+       },
+       {
+               .link_mask = 0xF, /* 4 active links required */
+               .links = rpl_sdw_rt711_link0_rt1318_link12_rt714_link3,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
+       },
+       {
+               .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
+               .links = rpl_sdw_rt1316_link12_rt714_link0,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
+       },
+       {
                .link_mask = 0x1, /* link0 required */
                .links = rpl_rvp,
                .drv_name = "sof_sdw",
index eaad180..5ab0917 100644 (file)
@@ -53,17 +53,15 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
        struct hdac_bus *bus = dev_get_drvdata(dev);
        struct hdac_stream *stream = snd_hdac_get_stream(bus,
                        SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
-       struct hdac_ext_stream *estream;
 
        if (!stream)
                return -EINVAL;
 
-       estream = stream_to_hdac_ext_stream(stream);
        /* enable/disable SPIB for this hdac stream */
-       snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
+       snd_hdac_stream_spbcap_enable(bus, enable, stream->index);
 
        /* set the spib value */
-       snd_hdac_ext_stream_set_spib(bus, estream, size);
+       snd_hdac_stream_set_spib(bus, stream, size);
 
        return 0;
 }
index 1015716..dc627d1 100644 (file)
@@ -190,16 +190,16 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
        dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
                format_val, params->s_freq, params->ch, params->format);
 
-       snd_hdac_ext_link_stream_reset(stream);
+       snd_hdac_ext_stream_reset(stream);
 
-       snd_hdac_ext_link_stream_setup(stream, format_val);
+       snd_hdac_ext_stream_setup(stream, format_val);
 
        stream_tag = hstream->stream_tag;
        if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
                list_for_each_entry(link, &bus->hlink_list, list) {
                        if (link->index == params->link_index)
-                               snd_hdac_ext_link_set_stream_id(link,
-                                                               stream_tag);
+                               snd_hdac_ext_bus_link_set_stream_id(link,
+                                                                   stream_tag);
                }
        }
 
@@ -467,6 +467,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
        struct skl_module_cfg *mconfig;
        struct hdac_bus *bus = get_bus_ctx(substream);
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+       struct hdac_stream *hstream = hdac_stream(stream);
        struct snd_soc_dapm_widget *w;
        int ret;
 
@@ -484,11 +485,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                         * dpib & lpib position to resume before starting the
                         * DMA
                         */
-                       snd_hdac_ext_stream_drsm_enable(bus, true,
-                                               hdac_stream(stream)->index);
-                       snd_hdac_ext_stream_set_dpibr(bus, stream,
-                                                       stream->lpib);
-                       snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+                       snd_hdac_stream_drsm_enable(bus, true, hstream->index);
+                       snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
+                       snd_hdac_stream_set_lpib(hstream, hstream->lpib);
                }
                fallthrough;
 
@@ -520,13 +519,13 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                ret = skl_decoupled_trigger(substream, cmd);
                if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
                        /* save the dpib and lpib positions */
-                       stream->dpib = readl(bus->remap_addr +
+                       hstream->dpib = readl(bus->remap_addr +
                                        AZX_REG_VS_SDXDPIB_XBASE +
                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                       hdac_stream(stream)->index));
+                                       hstream->index));
+
+                       hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream);
 
-                       stream->lpib = snd_hdac_stream_get_pos_lpib(
-                                                       hdac_stream(stream));
                        snd_hdac_ext_stream_decouple(bus, stream, false);
                }
                break;
@@ -558,7 +557,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
 
        snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
 
-       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
+       link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
        if (!link)
                return -EINVAL;
 
@@ -612,13 +611,13 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               snd_hdac_ext_link_stream_start(link_dev);
+               snd_hdac_ext_stream_start(link_dev);
                break;
 
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
-               snd_hdac_ext_link_stream_clear(link_dev);
+               snd_hdac_ext_stream_clear(link_dev);
                if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
                        snd_hdac_ext_stream_decouple(bus, stream, false);
                break;
@@ -643,13 +642,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
 
        link_dev->link_prepared = 0;
 
-       link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
+       link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
        if (!link)
                return -EINVAL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                stream_tag = hdac_stream(link_dev)->stream_tag;
-               snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+               snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag);
        }
 
        snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
index 3312b57..9bd9f98 100644 (file)
@@ -387,15 +387,6 @@ static int skl_resume(struct device *dev)
                        snd_hdac_bus_init_cmd_io(bus);
        } else {
                ret = _skl_resume(bus);
-
-               /* turn off the links which are off before suspend */
-               list_for_each_entry(hlink, &bus->hlink_list, list) {
-                       if (!hlink->ref_count)
-                               snd_hdac_ext_bus_link_power_down(hlink);
-               }
-
-               if (!bus->cmd_dma_state)
-                       snd_hdac_bus_stop_cmd_io(bus);
        }
 
        return ret;
@@ -445,7 +436,7 @@ static int skl_free(struct hdac_bus *bus)
                free_irq(bus->irq, (void *)bus);
        snd_hdac_bus_free_stream_pages(bus);
        snd_hdac_ext_stream_free_all(bus);
-       snd_hdac_link_free_all(bus);
+       snd_hdac_ext_link_free_all(bus);
 
        if (bus->remap_addr)
                iounmap(bus->remap_addr);
index e72f826..dd3b450 100644 (file)
@@ -3,6 +3,7 @@ config SND_JZ4740_SOC_I2S
        tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
        depends on MIPS || COMPILE_TEST
        depends on HAS_IOMEM
+       select REGMAP_MMIO
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
index c4c1e89..6d9cfe0 100644 (file)
@@ -3,19 +3,19 @@
  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
  */
 
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
-#include <linux/clk.h>
-#include <linux/delay.h>
-
-#include <linux/dma-mapping.h>
-
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -23,8 +23,6 @@
 #include <sound/initval.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "jz4740-i2s.h"
-
 #define JZ_REG_AIC_CONF                0x00
 #define JZ_REG_AIC_CTRL                0x04
 #define JZ_REG_AIC_I2S_FMT     0x10
 #define JZ_REG_AIC_CLK_DIV     0x30
 #define JZ_REG_AIC_FIFO                0x34
 
-#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
-#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf <<  8)
-#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
-#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
-#define JZ_AIC_CONF_I2S BIT(4)
-#define JZ_AIC_CONF_RESET BIT(3)
-#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
-#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
-#define JZ_AIC_CONF_ENABLE BIT(0)
-
-#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
-#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
-#define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
-#define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
-
-#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
-#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
-#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
-#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
-#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
-#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
-#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
-#define JZ_AIC_CTRL_FLUSH              BIT(8)
-#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
-#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
-#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
-#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
-#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
-#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
-#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
-
-#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
-#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET  16
-
-#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
-#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
-#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
-#define JZ_AIC_I2S_FMT_MSB BIT(0)
-
-#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
-
-#define JZ_AIC_CLK_DIV_MASK 0xf
-#define I2SDIV_DV_SHIFT 0
-#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
-#define I2SDIV_IDV_SHIFT 8
-#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
-
-enum jz47xx_i2s_version {
-       JZ_I2S_JZ4740,
-       JZ_I2S_JZ4760,
-       JZ_I2S_JZ4770,
-       JZ_I2S_JZ4780,
-};
+#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
+#define JZ_AIC_CONF_INTERNAL_CODEC     BIT(5)
+#define JZ_AIC_CONF_I2S                        BIT(4)
+#define JZ_AIC_CONF_RESET              BIT(3)
+#define JZ_AIC_CONF_BIT_CLK_MASTER     BIT(2)
+#define JZ_AIC_CONF_SYNC_CLK_MASTER    BIT(1)
+#define JZ_AIC_CONF_ENABLE             BIT(0)
+
+#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE GENMASK(21, 19)
+#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE  GENMASK(18, 16)
+#define JZ_AIC_CTRL_ENABLE_RX_DMA      BIT(15)
+#define JZ_AIC_CTRL_ENABLE_TX_DMA      BIT(14)
+#define JZ_AIC_CTRL_MONO_TO_STEREO     BIT(11)
+#define JZ_AIC_CTRL_SWITCH_ENDIANNESS  BIT(10)
+#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
+#define JZ_AIC_CTRL_TFLUSH             BIT(8)
+#define JZ_AIC_CTRL_RFLUSH             BIT(7)
+#define JZ_AIC_CTRL_ENABLE_ROR_INT     BIT(6)
+#define JZ_AIC_CTRL_ENABLE_TUR_INT     BIT(5)
+#define JZ_AIC_CTRL_ENABLE_RFS_INT     BIT(4)
+#define JZ_AIC_CTRL_ENABLE_TFS_INT     BIT(3)
+#define JZ_AIC_CTRL_ENABLE_LOOPBACK    BIT(2)
+#define JZ_AIC_CTRL_ENABLE_PLAYBACK    BIT(1)
+#define JZ_AIC_CTRL_ENABLE_CAPTURE     BIT(0)
+
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK        BIT(13)
+#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK  BIT(4)
+#define JZ_AIC_I2S_FMT_MSB             BIT(0)
+
+#define JZ_AIC_I2S_STATUS_BUSY         BIT(2)
 
 struct i2s_soc_info {
-       enum jz47xx_i2s_version version;
        struct snd_soc_dai_driver *dai;
+
+       struct reg_field field_rx_fifo_thresh;
+       struct reg_field field_tx_fifo_thresh;
+       struct reg_field field_i2sdiv_capture;
+       struct reg_field field_i2sdiv_playback;
+
+       bool shared_fifo_flush;
 };
 
 struct jz4740_i2s {
-       void __iomem *base;
+       struct regmap *regmap;
+
+       struct regmap_field *field_rx_fifo_thresh;
+       struct regmap_field *field_tx_fifo_thresh;
+       struct regmap_field *field_i2sdiv_capture;
+       struct regmap_field *field_i2sdiv_playback;
 
        struct clk *clk_aic;
        struct clk *clk_i2s;
@@ -104,40 +91,41 @@ struct jz4740_i2s {
        const struct i2s_soc_info *soc_info;
 };
 
-static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
-       unsigned int reg)
-{
-       return readl(i2s->base + reg);
-}
-
-static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
-       unsigned int reg, uint32_t value)
-{
-       writel(value, i2s->base + reg);
-}
-
 static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       uint32_t conf, ctrl;
        int ret;
 
+       /*
+        * When we can flush FIFOs independently, only flush the FIFO
+        * that is starting up. We can do this when the DAI is active
+        * because it does not disturb other active substreams.
+        */
+       if (!i2s->soc_info->shared_fifo_flush) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
+               else
+                       regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH);
+       }
+
        if (snd_soc_dai_active(dai))
                return 0;
 
-       ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
-       ctrl |= JZ_AIC_CTRL_FLUSH;
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+       /*
+        * When there is a shared flush bit for both FIFOs, the TFLUSH
+        * bit flushes both FIFOs. Flushing while the DAI is active would
+        * cause FIFO underruns in other active substreams so we have to
+        * guard this behind the snd_soc_dai_active() check.
+        */
+       if (i2s->soc_info->shared_fifo_flush)
+               regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
 
        ret = clk_prepare_enable(i2s->clk_i2s);
        if (ret)
                return ret;
 
-       conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-       conf |= JZ_AIC_CONF_ENABLE;
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
+       regmap_set_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
        return 0;
 }
 
@@ -145,14 +133,11 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       uint32_t conf;
 
        if (snd_soc_dai_active(dai))
                return;
 
-       conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-       conf &= ~JZ_AIC_CONF_ENABLE;
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+       regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
 
        clk_disable_unprepare(i2s->clk_i2s);
 }
@@ -161,8 +146,6 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       uint32_t ctrl;
        uint32_t mask;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -170,38 +153,30 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        else
                mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
 
-       ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ctrl |= mask;
+               regmap_set_bits(i2s->regmap, JZ_REG_AIC_CTRL, mask);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ctrl &= ~mask;
+               regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CTRL, mask);
                break;
        default:
                return -EINVAL;
        }
 
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
-
        return 0;
 }
 
 static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       uint32_t format = 0;
-       uint32_t conf;
-
-       conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-
-       conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
+       const unsigned int conf_mask = JZ_AIC_CONF_BIT_CLK_MASTER |
+                                      JZ_AIC_CONF_SYNC_CLK_MASTER;
+       unsigned int conf = 0, format = 0;
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
        case SND_SOC_DAIFMT_BP_FP:
@@ -237,8 +212,8 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-       jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
+       regmap_update_bits(i2s->regmap, JZ_REG_AIC_CONF, conf_mask, conf);
+       regmap_write(i2s->regmap, JZ_REG_AIC_I2S_FMT, format);
 
        return 0;
 }
@@ -247,123 +222,51 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       struct regmap_field *div_field;
        unsigned int sample_size;
-       uint32_t ctrl, div_reg;
+       uint32_t ctrl;
        int div;
 
-       ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
+       regmap_read(i2s->regmap, JZ_REG_AIC_CTRL, &ctrl);
 
-       div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
        div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                sample_size = 0;
                break;
-       case SNDRV_PCM_FORMAT_S16:
+       case SNDRV_PCM_FORMAT_S16_LE:
                sample_size = 1;
                break;
+       case SNDRV_PCM_FORMAT_S20_LE:
+               sample_size = 3;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               sample_size = 4;
+               break;
        default:
                return -EINVAL;
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
-               ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
+               ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE;
+               ctrl |= FIELD_PREP(JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE, sample_size);
+
                if (params_channels(params) == 1)
                        ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
                else
                        ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
 
-               div_reg &= ~I2SDIV_DV_MASK;
-               div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
+               div_field = i2s->field_i2sdiv_playback;
        } else {
-               ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
-               ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
-
-               if (i2s->soc_info->version >= JZ_I2S_JZ4770) {
-                       div_reg &= ~I2SDIV_IDV_MASK;
-                       div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
-               } else {
-                       div_reg &= ~I2SDIV_DV_MASK;
-                       div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
-               }
-       }
-
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
-
-       return 0;
-}
+               ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE;
+               ctrl |= FIELD_PREP(JZ_AIC_CTRL_INPUT_SAMPLE_SIZE, sample_size);
 
-static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-       unsigned int freq, int dir)
-{
-       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       struct clk *parent;
-       int ret = 0;
-
-       switch (clk_id) {
-       case JZ4740_I2S_CLKSRC_EXT:
-               parent = clk_get(NULL, "ext");
-               if (IS_ERR(parent))
-                       return PTR_ERR(parent);
-               clk_set_parent(i2s->clk_i2s, parent);
-               break;
-       case JZ4740_I2S_CLKSRC_PLL:
-               parent = clk_get(NULL, "pll half");
-               if (IS_ERR(parent))
-                       return PTR_ERR(parent);
-               clk_set_parent(i2s->clk_i2s, parent);
-               ret = clk_set_rate(i2s->clk_i2s, freq);
-               break;
-       default:
-               return -EINVAL;
-       }
-       clk_put(parent);
-
-       return ret;
-}
-
-static int jz4740_i2s_suspend(struct snd_soc_component *component)
-{
-       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
-       uint32_t conf;
-
-       if (snd_soc_component_active(component)) {
-               conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-               conf &= ~JZ_AIC_CONF_ENABLE;
-               jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
-               clk_disable_unprepare(i2s->clk_i2s);
+               div_field = i2s->field_i2sdiv_capture;
        }
 
-       clk_disable_unprepare(i2s->clk_aic);
-
-       return 0;
-}
-
-static int jz4740_i2s_resume(struct snd_soc_component *component)
-{
-       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
-       uint32_t conf;
-       int ret;
-
-       ret = clk_prepare_enable(i2s->clk_aic);
-       if (ret)
-               return ret;
-
-       if (snd_soc_component_active(component)) {
-               ret = clk_prepare_enable(i2s->clk_i2s);
-               if (ret) {
-                       clk_disable_unprepare(i2s->clk_aic);
-                       return ret;
-               }
-
-               conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
-               conf |= JZ_AIC_CONF_ENABLE;
-               jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-       }
+       regmap_write(i2s->regmap, JZ_REG_AIC_CTRL, ctrl);
+       regmap_field_write(div_field, div - 1);
 
        return 0;
 }
@@ -371,41 +274,10 @@ static int jz4740_i2s_resume(struct snd_soc_component *component)
 static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       uint32_t conf;
-       int ret;
-
-       ret = clk_prepare_enable(i2s->clk_aic);
-       if (ret)
-               return ret;
 
        snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
                &i2s->capture_dma_data);
 
-       if (i2s->soc_info->version >= JZ_I2S_JZ4760) {
-               conf = (7 << JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
-                       (8 << JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
-                       JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
-                       JZ_AIC_CONF_I2S |
-                       JZ_AIC_CONF_INTERNAL_CODEC;
-       } else {
-               conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
-                       (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
-                       JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
-                       JZ_AIC_CONF_I2S |
-                       JZ_AIC_CONF_INTERNAL_CODEC;
-       }
-
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
-       jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
-
-       return 0;
-}
-
-static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
-{
-       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
-       clk_disable_unprepare(i2s->clk_aic);
        return 0;
 }
 
@@ -415,25 +287,25 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
        .trigger = jz4740_i2s_trigger,
        .hw_params = jz4740_i2s_hw_params,
        .set_fmt = jz4740_i2s_set_fmt,
-       .set_sysclk = jz4740_i2s_set_sysclk,
 };
 
 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
-               SNDRV_PCM_FMTBIT_S16_LE)
+                        SNDRV_PCM_FMTBIT_S16_LE | \
+                        SNDRV_PCM_FMTBIT_S20_LE | \
+                        SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver jz4740_i2s_dai = {
        .probe = jz4740_i2s_dai_probe,
-       .remove = jz4740_i2s_dai_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_48000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .formats = JZ4740_I2S_FMTS,
        },
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_48000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .formats = JZ4740_I2S_FMTS,
        },
        .symmetric_rate = 1,
@@ -441,45 +313,123 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
 };
 
 static const struct i2s_soc_info jz4740_i2s_soc_info = {
-       .version = JZ_I2S_JZ4740,
-       .dai = &jz4740_i2s_dai,
+       .dai                    = &jz4740_i2s_dai,
+       .field_rx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 12, 15),
+       .field_tx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 8, 11),
+       .field_i2sdiv_capture   = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+       .field_i2sdiv_playback  = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+       .shared_fifo_flush      = true,
 };
 
 static const struct i2s_soc_info jz4760_i2s_soc_info = {
-       .version = JZ_I2S_JZ4760,
-       .dai = &jz4740_i2s_dai,
+       .dai                    = &jz4740_i2s_dai,
+       .field_rx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+       .field_tx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+       .field_i2sdiv_capture   = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
+       .field_i2sdiv_playback  = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
 };
 
 static struct snd_soc_dai_driver jz4770_i2s_dai = {
        .probe = jz4740_i2s_dai_probe,
-       .remove = jz4740_i2s_dai_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_48000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .formats = JZ4740_I2S_FMTS,
        },
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_48000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .formats = JZ4740_I2S_FMTS,
        },
        .ops = &jz4740_i2s_dai_ops,
 };
 
 static const struct i2s_soc_info jz4770_i2s_soc_info = {
-       .version = JZ_I2S_JZ4770,
-       .dai = &jz4770_i2s_dai,
+       .dai                    = &jz4770_i2s_dai,
+       .field_rx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+       .field_tx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+       .field_i2sdiv_capture   = REG_FIELD(JZ_REG_AIC_CLK_DIV, 8, 11),
+       .field_i2sdiv_playback  = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
 };
 
 static const struct i2s_soc_info jz4780_i2s_soc_info = {
-       .version = JZ_I2S_JZ4780,
-       .dai = &jz4770_i2s_dai,
+       .dai                    = &jz4770_i2s_dai,
+       .field_rx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 24, 27),
+       .field_tx_fifo_thresh   = REG_FIELD(JZ_REG_AIC_CONF, 16, 20),
+       .field_i2sdiv_capture   = REG_FIELD(JZ_REG_AIC_CLK_DIV, 8, 11),
+       .field_i2sdiv_playback  = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3),
 };
 
+static int jz4740_i2s_suspend(struct snd_soc_component *component)
+{
+       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+
+       if (snd_soc_component_active(component)) {
+               regmap_clear_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
+               clk_disable_unprepare(i2s->clk_i2s);
+       }
+
+       clk_disable_unprepare(i2s->clk_aic);
+
+       return 0;
+}
+
+static int jz4740_i2s_resume(struct snd_soc_component *component)
+{
+       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       ret = clk_prepare_enable(i2s->clk_aic);
+       if (ret)
+               return ret;
+
+       if (snd_soc_component_active(component)) {
+               ret = clk_prepare_enable(i2s->clk_i2s);
+               if (ret) {
+                       clk_disable_unprepare(i2s->clk_aic);
+                       return ret;
+               }
+
+               regmap_set_bits(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_ENABLE);
+       }
+
+       return 0;
+}
+
+static int jz4740_i2s_probe(struct snd_soc_component *component)
+{
+       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       ret = clk_prepare_enable(i2s->clk_aic);
+       if (ret)
+               return ret;
+
+       regmap_write(i2s->regmap, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
+
+       regmap_write(i2s->regmap, JZ_REG_AIC_CONF,
+                    JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+                    JZ_AIC_CONF_I2S | JZ_AIC_CONF_INTERNAL_CODEC);
+
+       regmap_field_write(i2s->field_rx_fifo_thresh, 7);
+       regmap_field_write(i2s->field_tx_fifo_thresh, 8);
+
+       return 0;
+}
+
+static void jz4740_i2s_remove(struct snd_soc_component *component)
+{
+       struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
+
+       clk_disable_unprepare(i2s->clk_aic);
+}
+
 static const struct snd_soc_component_driver jz4740_i2s_component = {
        .name                   = "jz4740-i2s",
+       .probe                  = jz4740_i2s_probe,
+       .remove                 = jz4740_i2s_remove,
        .suspend                = jz4740_i2s_suspend,
        .resume                 = jz4740_i2s_resume,
        .legacy_dai_naming      = 1,
@@ -494,11 +444,49 @@ static const struct of_device_id jz4740_of_matches[] = {
 };
 MODULE_DEVICE_TABLE(of, jz4740_of_matches);
 
+static int jz4740_i2s_init_regmap_fields(struct device *dev,
+                                        struct jz4740_i2s *i2s)
+{
+       i2s->field_rx_fifo_thresh =
+               devm_regmap_field_alloc(dev, i2s->regmap,
+                                       i2s->soc_info->field_rx_fifo_thresh);
+       if (IS_ERR(i2s->field_rx_fifo_thresh))
+               return PTR_ERR(i2s->field_rx_fifo_thresh);
+
+       i2s->field_tx_fifo_thresh =
+               devm_regmap_field_alloc(dev, i2s->regmap,
+                                       i2s->soc_info->field_tx_fifo_thresh);
+       if (IS_ERR(i2s->field_tx_fifo_thresh))
+               return PTR_ERR(i2s->field_tx_fifo_thresh);
+
+       i2s->field_i2sdiv_capture =
+               devm_regmap_field_alloc(dev, i2s->regmap,
+                                       i2s->soc_info->field_i2sdiv_capture);
+       if (IS_ERR(i2s->field_i2sdiv_capture))
+               return PTR_ERR(i2s->field_i2sdiv_capture);
+
+       i2s->field_i2sdiv_playback =
+               devm_regmap_field_alloc(dev, i2s->regmap,
+                                       i2s->soc_info->field_i2sdiv_playback);
+       if (IS_ERR(i2s->field_i2sdiv_playback))
+               return PTR_ERR(i2s->field_i2sdiv_playback);
+
+       return 0;
+}
+
+static const struct regmap_config jz4740_i2s_regmap_config = {
+       .reg_bits       = 32,
+       .reg_stride     = 4,
+       .val_bits       = 32,
+       .max_register   = JZ_REG_AIC_FIFO,
+};
+
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct jz4740_i2s *i2s;
        struct resource *mem;
+       void __iomem *regs;
        int ret;
 
        i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
@@ -507,9 +495,9 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 
        i2s->soc_info = device_get_match_data(dev);
 
-       i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
-       if (IS_ERR(i2s->base))
-               return PTR_ERR(i2s->base);
+       regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
 
        i2s->playback_dma_data.maxburst = 16;
        i2s->playback_dma_data.addr = mem->start + JZ_REG_AIC_FIFO;
@@ -525,6 +513,15 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
        if (IS_ERR(i2s->clk_i2s))
                return PTR_ERR(i2s->clk_i2s);
 
+       i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+                                           &jz4740_i2s_regmap_config);
+       if (IS_ERR(i2s->regmap))
+               return PTR_ERR(i2s->regmap);
+
+       ret = jz4740_i2s_init_regmap_fields(dev, i2s);
+       if (ret)
+               return ret;
+
        platform_set_drvdata(pdev, i2s);
 
        ret = devm_snd_soc_register_component(dev, &jz4740_i2s_component,
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
deleted file mode 100644 (file)
index 4da14ea..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef _JZ4740_I2S_H
-#define _JZ4740_I2S_H
-
-/* I2S clock source */
-#define JZ4740_I2S_CLKSRC_EXT 0
-#define JZ4740_I2S_CLKSRC_PLL 1
-
-#endif
index 2a4ffe9..afdf7d6 100644 (file)
        (SNDRV_PCM_FMTBIT_S16_LE | \
         SNDRV_PCM_FMTBIT_S24_LE)
 
+/* These registers are relative to the second register region -
+ * audio pll configuration.
+ */
+#define A38X_PLL_CONF_REG0                     0x0
+#define     A38X_PLL_FB_CLK_DIV_OFFSET         10
+#define     A38X_PLL_FB_CLK_DIV_MASK           0x7fc00
+#define A38X_PLL_CONF_REG1                     0x4
+#define     A38X_PLL_FREQ_OFFSET_MASK          0xffff
+#define     A38X_PLL_FREQ_OFFSET_VALID         BIT(16)
+#define     A38X_PLL_SW_RESET                  BIT(31)
+#define A38X_PLL_CONF_REG2                     0x8
+#define     A38X_PLL_AUDIO_POSTDIV_MASK                0x7f
+
+/* Bit below belongs to SoC control register corresponding to the third
+ * register region.
+ */
+#define A38X_SPDIF_MODE_ENABLE                 BIT(27)
+
+static int armada_38x_i2s_init_quirk(struct platform_device *pdev,
+                                    struct kirkwood_dma_data *priv,
+                                    struct snd_soc_dai_driver *dai_drv)
+{
+       struct device_node *np = pdev->dev.of_node;
+       u32 reg_val;
+       int i;
+
+       priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
+       if (IS_ERR(priv->pll_config))
+               return -ENOMEM;
+
+       priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
+       if (IS_ERR(priv->soc_control))
+               return -ENOMEM;
+
+       /* Select one of exceptive modes: I2S or S/PDIF */
+       reg_val = readl(priv->soc_control);
+       if (of_property_read_bool(np, "spdif-mode")) {
+               reg_val |= A38X_SPDIF_MODE_ENABLE;
+               dev_info(&pdev->dev, "using S/PDIF mode\n");
+       } else {
+               reg_val &= ~A38X_SPDIF_MODE_ENABLE;
+               dev_info(&pdev->dev, "using I2S mode\n");
+       }
+       writel(reg_val, priv->soc_control);
+
+       /* Update available rates of mclk's fs */
+       for (i = 0; i < 2; i++) {
+               dai_drv[i].playback.rates |= SNDRV_PCM_RATE_192000;
+               dai_drv[i].capture.rates |= SNDRV_PCM_RATE_192000;
+       }
+
+       return 0;
+}
+
+static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
+{
+       u32 reg_val;
+       u16 freq_offset = 0x22b0;
+       u8 audio_postdiv, fb_clk_div = 0x1d;
+
+       /* Set frequency offset value to not valid and enable PLL reset */
+       reg_val = readl(base + A38X_PLL_CONF_REG1);
+       reg_val &= ~A38X_PLL_FREQ_OFFSET_VALID;
+       reg_val &= ~A38X_PLL_SW_RESET;
+       writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+       udelay(1);
+
+       /* Update PLL parameters */
+       switch (rate) {
+       default:
+       case 44100:
+               freq_offset = 0x735;
+               fb_clk_div = 0x1b;
+               audio_postdiv = 0xc;
+               break;
+       case 48000:
+               audio_postdiv = 0xc;
+               break;
+       case 96000:
+               audio_postdiv = 0x6;
+               break;
+       case 192000:
+               audio_postdiv = 0x3;
+               break;
+       }
+
+       reg_val = readl(base + A38X_PLL_CONF_REG0);
+       reg_val &= ~A38X_PLL_FB_CLK_DIV_MASK;
+       reg_val |= (fb_clk_div << A38X_PLL_FB_CLK_DIV_OFFSET);
+       writel(reg_val, base + A38X_PLL_CONF_REG0);
+
+       reg_val = readl(base + A38X_PLL_CONF_REG2);
+       reg_val &= ~A38X_PLL_AUDIO_POSTDIV_MASK;
+       reg_val |= audio_postdiv;
+       writel(reg_val, base + A38X_PLL_CONF_REG2);
+
+       reg_val = readl(base + A38X_PLL_CONF_REG1);
+       reg_val &= ~A38X_PLL_FREQ_OFFSET_MASK;
+       reg_val |= freq_offset;
+       writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+       udelay(1);
+
+       /* Disable reset */
+       reg_val |= A38X_PLL_SW_RESET;
+       writel(reg_val, base + A38X_PLL_CONF_REG1);
+
+       /* Wait 50us for PLL to lock */
+       udelay(50);
+
+       /* Restore frequency offset value validity */
+       reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
+       writel(reg_val, base + A38X_PLL_CONF_REG1);
+}
+
 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
@@ -106,7 +222,10 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
                 * defined in kirkwood_i2s_dai */
                dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
                        __func__, rate);
-               kirkwood_set_dco(priv->io, rate);
+               if (priv->pll_config)
+                       armada_38x_set_pll(priv->pll_config, rate);
+               else
+                       kirkwood_set_dco(priv->io, rate);
 
                clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
        } else {
@@ -532,7 +651,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, priv);
 
-       priv->io = devm_platform_ioremap_resource(pdev, 0);
+       if (of_device_is_compatible(np, "marvell,armada-380-audio"))
+               priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
+       else
+               priv->io = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->io))
                return PTR_ERR(priv->io);
 
@@ -540,6 +662,14 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        if (priv->irq < 0)
                return priv->irq;
 
+       if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
+               err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
+               if (err < 0)
+                       return err;
+               /* Set initial pll frequency */
+               armada_38x_set_pll(priv->pll_config, 44100);
+       }
+
        if (np) {
                priv->burst = 128;              /* might be 32 or 128 */
        } else if (data) {
@@ -623,6 +753,7 @@ static const struct of_device_id mvebu_audio_of_match[] = {
        { .compatible = "marvell,kirkwood-audio" },
        { .compatible = "marvell,dove-audio" },
        { .compatible = "marvell,armada370-audio" },
+       { .compatible = "marvell,armada-380-audio" },
        { }
 };
 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
index a1733a6..79bb9aa 100644 (file)
 
 struct kirkwood_dma_data {
        void __iomem *io;
+       void __iomem *pll_config;
+       void __iomem *soc_control;
        struct clk *clk;
        struct clk *extclk;
        uint32_t ctl_play;
index d884bb7..1c28b41 100644 (file)
@@ -1038,11 +1038,9 @@ static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component,
        struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mtk_btcvsd_snd_write(bt, buf, count);
+               return mtk_btcvsd_snd_write(bt, buf, count);
        else
-               mtk_btcvsd_snd_read(bt, buf, count);
-
-       return 0;
+               return mtk_btcvsd_snd_read(bt, buf, count);
 }
 
 /* kcontrol */
index d9fd6eb..08ef109 100644 (file)
@@ -418,6 +418,7 @@ static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
        {.compatible = "mediatek,mt2701-cs42448-machine",},
        {}
 };
+MODULE_DEVICE_TABLE(of, mt2701_cs42448_machine_dt_match);
 #endif
 
 static struct platform_driver mt2701_cs42448_machine = {
index 0cdf2ae..a184032 100644 (file)
@@ -161,6 +161,7 @@ static const struct of_device_id mt2701_wm8960_machine_dt_match[] = {
        {.compatible = "mediatek,mt2701-wm8960-machine",},
        {}
 };
+MODULE_DEVICE_TABLE(of, mt2701_wm8960_machine_dt_match);
 #endif
 
 static struct platform_driver mt2701_wm8960_machine = {
index d2f6213..784c201 100644 (file)
@@ -242,6 +242,7 @@ static const struct of_device_id mt6797_mt6351_dt_match[] = {
        {.compatible = "mediatek,mt6797-mt6351-sound",},
        {}
 };
+MODULE_DEVICE_TABLE(of, mt6797_mt6351_dt_match);
 #endif
 
 static struct platform_driver mt6797_mt6351_driver = {
index 9f22d39..87bb048 100644 (file)
@@ -14,7 +14,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include "../../codecs/da7219-aad.h"
 #include "../../codecs/da7219.h"
 #include "../../codecs/rt1015.h"
 #include "../common/mtk-afe-platform-driver.h"
@@ -592,7 +591,7 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
        snd_jack_set_key(
                priv->headset_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, &priv->headset_jack);
+       snd_soc_component_set_jack(component, &priv->headset_jack, NULL);
 
        return 0;
 }
@@ -842,6 +841,7 @@ static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, mt8183_da7219_max98357_dt_match);
 #endif
 
 static struct platform_driver mt8183_da7219_max98357_driver = {
index a860852..8fb4735 100644 (file)
@@ -835,6 +835,7 @@ static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, mt8183_mt6358_ts3a227_max98357_dt_match);
 #endif
 
 static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
index cfca6bd..970b980 100644 (file)
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
+#include <sound/jack.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include "../../codecs/da7219-aad.h"
 #include "../../codecs/da7219.h"
 #include "../../codecs/mt6358.h"
 #include "../common/mtk-afe-platform-driver.h"
@@ -100,7 +100,7 @@ static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(cmpnt_codec, &priv->headset_jack);
+       snd_soc_component_set_jack(cmpnt_codec, &priv->headset_jack, NULL);
 
        return 0;
 }
@@ -192,7 +192,7 @@ static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *r
        struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv;
        int ret;
 
-       ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2");
+       ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
        if (ret) {
                dev_err(rtd->dev, "Failed to set up shared clocks\n");
                return ret;
@@ -1161,6 +1161,7 @@ static const struct of_device_id mt8186_mt6366_da7219_max98357_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, mt8186_mt6366_da7219_max98357_dt_match);
 #endif
 
 static struct platform_driver mt8186_mt6366_da7219_max98357_driver = {
index 2414c5b..8f77a0b 100644 (file)
@@ -7,6 +7,8 @@
 // Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
 //
 
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -39,6 +41,8 @@
 
 struct mt8186_mt6366_rt1019_rt5682s_priv {
        struct snd_soc_jack headset_jack, hdmi_jack;
+       struct gpio_desc *dmic_sel;
+       int dmic_switch;
 };
 
 /* Headset jack detection DAPM pins */
@@ -68,6 +72,94 @@ static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = {
        },
 };
 
+static int dmic_get(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct mtk_soc_card_data *soc_card_data =
+               snd_soc_card_get_drvdata(dapm->card);
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+
+       ucontrol->value.integer.value[0] = priv->dmic_switch;
+       return 0;
+}
+
+static int dmic_set(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct mtk_soc_card_data *soc_card_data =
+               snd_soc_card_get_drvdata(dapm->card);
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+
+       priv->dmic_switch = ucontrol->value.integer.value[0];
+       if (priv->dmic_sel) {
+               gpiod_set_value(priv->dmic_sel, priv->dmic_switch);
+               dev_info(dapm->card->dev, "dmic_set_value %d\n",
+                        priv->dmic_switch);
+       }
+       return 0;
+}
+
+static const char * const dmic_mux_text[] = {
+       "Front Mic",
+       "Rear Mic",
+};
+
+static SOC_ENUM_SINGLE_DECL(mt8186_dmic_enum,
+                           SND_SOC_NOPM, 0, dmic_mux_text);
+
+static const struct snd_kcontrol_new mt8186_dmic_mux_control =
+       SOC_DAPM_ENUM_EXT("DMIC Select Mux", mt8186_dmic_enum,
+                         dmic_get, dmic_set);
+
+static const struct snd_soc_dapm_widget dmic_widgets[] = {
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+       SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &mt8186_dmic_mux_control),
+};
+
+static const struct snd_soc_dapm_route dmic_map[] = {
+       /* digital mics */
+       {"Dmic Mux", "Front Mic", "DMIC"},
+       {"Dmic Mux", "Rear Mic", "DMIC"},
+};
+
+static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+       int ret;
+
+       ret = mt8186_mt6366_init(rtd);
+
+       if (ret) {
+               dev_err(card->dev, "mt8186_mt6366_init failed: %d\n", ret);
+               return ret;
+       }
+
+       if (!priv->dmic_sel) {
+               dev_info(card->dev, "dmic_sel is null\n");
+               return ret;
+       }
+
+       ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+                                       ARRAY_SIZE(dmic_widgets));
+       if (ret) {
+               dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
+               /* Don't need to add routes if widget addition failed */
+               return ret;
+       }
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+                                     ARRAY_SIZE(dmic_map));
+
+       if (ret)
+               dev_err(card->dev, "DMic map addition failed: %d\n", ret);
+
+       return ret;
+}
+
 static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_component *cmpnt_afe =
@@ -168,7 +260,7 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt
        struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
        int ret;
 
-       ret = mt8186_dai_i2s_set_share(afe, "I2S3", "I2S2");
+       ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
        if (ret) {
                dev_err(rtd->dev, "Failed to set up shared clocks\n");
                return ret;
@@ -775,7 +867,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
                .dpcm_playback = 1,
                .dpcm_capture = 1,
                .ignore_suspend = 1,
-               .init = mt8186_mt6366_init,
+               .init = primary_codec_init,
                SND_SOC_DAILINK_REG(adda),
        },
        {
@@ -1015,6 +1107,14 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
 
        soc_card_data->mach_priv = mach_priv;
 
+       mach_priv->dmic_sel = devm_gpiod_get_optional(&pdev->dev,
+                                                     "dmic", GPIOD_OUT_LOW);
+       if (IS_ERR(mach_priv->dmic_sel)) {
+               dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n",
+                       PTR_ERR(mach_priv->dmic_sel));
+               return PTR_ERR(mach_priv->dmic_sel);
+       }
+
        adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
        if (adsp_node) {
                struct mtk_sof_priv *sof_priv;
@@ -1137,6 +1237,7 @@ static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
 #endif
 
 static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = {
index b93c323..16660ed 100644 (file)
@@ -1261,6 +1261,7 @@ static const struct of_device_id mt8192_mt6359_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, mt8192_mt6359_dt_match);
 #endif
 
 static const struct dev_pm_ops mt8192_mt6359_pm_ops = {
index 480ed3e..61be66f 100644 (file)
@@ -1544,6 +1544,7 @@ static const struct of_device_id mt8195_mt6359_dt_match[] = {
        },
        {},
 };
+MODULE_DEVICE_TABLE(of, mt8195_mt6359_dt_match);
 
 static struct platform_driver mt8195_mt6359_driver = {
        .driver = {
index 88ac582..ad43cb2 100644 (file)
@@ -169,7 +169,7 @@ static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os,
 
        /*
         * Set the default system clock rate unless it is too fast for
-        * for the requested sample rate. In this case, the sample pointer
+        * the requested sample rate. In this case, the sample pointer
         * counter could overflow so set a lower system clock rate
         */
        if (sys_rate < priv->cfg->sys_rate)
index 5d520e1..99b245e 100644 (file)
@@ -98,7 +98,7 @@ static bool filter(struct dma_chan *chan, void *param)
 
        devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
                dma_data->ssp_id);
-       if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+       if (devname && (strcmp(dev_name(chan->device->dev), devname) == 0) &&
                (chan->chan_id == dma_data->dma_res->start)) {
                found = true;
        }
index 8c7398b..96a6d47 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig SND_SOC_QCOM
        tristate "ASoC support for QCOM platforms"
        depends on ARCH_QCOM || COMPILE_TEST
+       imply SND_SOC_QCOM_COMMON
        help
          Say Y or M if you want to add support to use audio devices
          in Qualcomm Technologies SOC-based platforms.
@@ -59,13 +60,14 @@ config SND_SOC_STORM
 config SND_SOC_APQ8016_SBC
        tristate "SoC Audio support for APQ8016 SBC platforms"
        select SND_SOC_LPASS_APQ8016
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        help
          Support for Qualcomm Technologies LPASS audio block in
          APQ8016 SOC-based systems.
          Say Y if you want to use audio devices on MI2S.
 
 config SND_SOC_QCOM_COMMON
+       depends on SOUNDWIRE
        tristate
 
 config SND_SOC_QDSP6_COMMON
@@ -142,7 +144,7 @@ config SND_SOC_MSM8996
        depends on QCOM_APR
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        help
          Support for Qualcomm Technologies LPASS audio block in
          APQ8096 SoC-based systems.
@@ -153,7 +155,7 @@ config SND_SOC_SDM845
        depends on QCOM_APR && I2C && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        select SND_SOC_RT5663
        select SND_SOC_MAX98927
        imply SND_SOC_CROS_EC_CODEC
@@ -167,7 +169,7 @@ config SND_SOC_SM8250
        depends on QCOM_APR && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        help
          To add support for audio on Qualcomm Technologies Inc.
          SM8250 SoC-based systems.
@@ -178,7 +180,7 @@ config SND_SOC_SC8280XP
        depends on QCOM_APR && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        help
          To add support for audio on Qualcomm Technologies Inc.
          SC8280XP SoC-based systems.
@@ -188,7 +190,7 @@ config SND_SOC_SC7180
        tristate "SoC Machine driver for SC7180 boards"
        depends on I2C && GPIOLIB
        depends on SOUNDWIRE || SOUNDWIRE=n
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        select SND_SOC_LPASS_SC7180
        select SND_SOC_MAX98357A
        select SND_SOC_RT5682_I2C
@@ -202,7 +204,7 @@ config SND_SOC_SC7180
 config SND_SOC_SC7280
        tristate "SoC Machine driver for SC7280 boards"
        depends on I2C && SOUNDWIRE
-       select SND_SOC_QCOM_COMMON
+       depends on SND_SOC_QCOM_COMMON
        select SND_SOC_LPASS_SC7280
        select SND_SOC_MAX98357A
        select SND_SOC_WCD938X_SDW
index 69dd3b5..49c74c1 100644 (file)
@@ -180,7 +180,6 @@ err_put_np:
 }
 EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
 
-#if IS_ENABLED(CONFIG_SOUNDWIRE)
 int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
                         struct sdw_stream_runtime *sruntime,
                         bool *stream_prepared)
@@ -294,7 +293,6 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
-#endif
 
 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
                            struct snd_soc_jack *jack, bool *jack_setup)
index c5472a6..3ef5bb6 100644 (file)
@@ -11,7 +11,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card);
 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
                            struct snd_soc_jack *jack, bool *jack_setup);
 
-#if IS_ENABLED(CONFIG_SOUNDWIRE)
 int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
                         struct sdw_stream_runtime *runtime,
                         bool *stream_prepared);
@@ -21,26 +20,4 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
 int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
                         struct sdw_stream_runtime *sruntime,
                         bool *stream_prepared);
-#else
-static inline int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
-                                      struct sdw_stream_runtime *runtime,
-                                      bool *stream_prepared)
-{
-       return -ENOTSUPP;
-}
-
-static inline int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
-                                        struct snd_pcm_hw_params *params,
-                                        struct sdw_stream_runtime **psruntime)
-{
-       return -ENOTSUPP;
-}
-
-static inline int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
-                                      struct sdw_stream_runtime *sruntime,
-                                      bool *stream_prepared)
-{
-       return -ENOTSUPP;
-}
-#endif
 #endif
index 77a556b..24a1c12 100644 (file)
@@ -131,6 +131,9 @@ static int sc7180_lpass_init(struct platform_device *pdev)
 
        drvdata->clks = devm_kcalloc(dev, variant->num_clks,
                                     sizeof(*drvdata->clks), GFP_KERNEL);
+       if (!drvdata->clks)
+               return -ENOMEM;
+
        drvdata->num_clks = variant->num_clks;
 
        for (i = 0; i < drvdata->num_clks; i++)
index 01dac32..1e0c918 100644 (file)
@@ -159,6 +159,8 @@ struct apm_module_hw_ep_mf_cfg {
 
 #define APM_HW_EP_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_mf_cfg), 8)
 
+#define APM_MFC_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4)
+
 struct apm_module_frame_size_factor_cfg {
        struct apm_module_param_data param_data;
        uint32_t frame_size_factor;
@@ -311,15 +313,6 @@ static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg,
        cfg->sid.scenario_id = sg->scenario_id;
 }
 
-static void apm_populate_connection_obj(struct apm_module_conn_obj *obj,
-                                       struct audioreach_module *module)
-{
-       obj->src_mod_inst_id = module->src_mod_inst_id;
-       obj->src_mod_op_port_id = module->src_mod_op_port_id;
-       obj->dst_mod_inst_id = module->instance_id;
-       obj->dst_mod_ip_port_id = module->in_port;
-}
-
 static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
                                         struct audioreach_module *module)
 {
@@ -332,63 +325,6 @@ static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
        obj->prop_id_port.max_op_port = module->max_op_port;
 }
 
-struct audioreach_module *audioreach_get_container_last_module(
-                                                       struct audioreach_container *container)
-{
-       struct audioreach_module *module;
-
-       list_for_each_entry(module, &container->modules_list, node) {
-               if (module->dst_mod_inst_id == 0)
-                       return module;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_last_module);
-
-static bool is_module_in_container(struct audioreach_container *container, int module_iid)
-{
-       struct audioreach_module *module;
-
-       list_for_each_entry(module, &container->modules_list, node) {
-               if (module->instance_id == module_iid)
-                       return true;
-       }
-
-       return false;
-}
-
-struct audioreach_module *audioreach_get_container_first_module(
-                                                       struct audioreach_container *container)
-{
-       struct audioreach_module *module;
-
-       /* get the first module from both connected or un-connected containers */
-       list_for_each_entry(module, &container->modules_list, node) {
-               if (module->src_mod_inst_id == 0 ||
-                   !is_module_in_container(container, module->src_mod_inst_id))
-                       return module;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_first_module);
-
-struct audioreach_module *audioreach_get_container_next_module(
-                                               struct audioreach_container *container,
-                                               struct audioreach_module *module)
-{
-       int nmodule_iid = module->dst_mod_inst_id;
-       struct audioreach_module *nmodule;
-
-       list_for_each_entry(nmodule, &container->modules_list, node) {
-               if (nmodule->instance_id == nmodule_iid)
-                       return nmodule;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_next_module);
-
 static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
                                         struct audioreach_container *container,
                                         int sub_graph_id)
@@ -400,14 +336,15 @@ static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
        obj->container_id = container->container_id;
        obj->num_modules = container->num_modules;
        i = 0;
-       list_for_each_container_module(module, container) {
+       list_for_each_entry(module, &container->modules_list, node) {
                obj->mod_cfg[i].module_id = module->module_id;
                obj->mod_cfg[i].instance_id = module->instance_id;
                i++;
        }
 }
 
-static void audioreach_populate_graph(struct apm_graph_open_params *open,
+static void audioreach_populate_graph(struct q6apm *apm, struct audioreach_graph_info *info,
+                                     struct apm_graph_open_params *open,
                                      struct list_head *sg_list,
                                      int num_sub_graphs)
 {
@@ -428,6 +365,16 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
 
        mlobj = &ml_data->mod_list_obj[0];
 
+
+       if (info->dst_mod_inst_id && info->src_mod_inst_id) {
+               conn_obj = &mc_data->conn_obj[nconn];
+               conn_obj->src_mod_inst_id = info->src_mod_inst_id;
+               conn_obj->src_mod_op_port_id = info->src_mod_op_port_id;
+               conn_obj->dst_mod_inst_id = info->dst_mod_inst_id;
+               conn_obj->dst_mod_ip_port_id = info->dst_mod_ip_port_id;
+               nconn++;
+       }
+
        list_for_each_entry(sg, sg_list, node) {
                struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++];
 
@@ -439,30 +386,38 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
                        apm_populate_container_config(cobj, container);
                        apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id);
 
-                       list_for_each_container_module(module, container) {
-                               uint32_t src_mod_inst_id;
-
-                               src_mod_inst_id = module->src_mod_inst_id;
+                       list_for_each_entry(module, &container->modules_list, node) {
+                               int pn;
 
-                               module_prop_obj = &mp_data->mod_prop_obj[nmodule];
+                               module_prop_obj = &mp_data->mod_prop_obj[nmodule++];
                                apm_populate_module_prop_obj(module_prop_obj, module);
 
-                               if (src_mod_inst_id) {
-                                       conn_obj = &mc_data->conn_obj[nconn];
-                                       apm_populate_connection_obj(conn_obj, module);
-                                       nconn++;
+                               if (!module->max_op_port)
+                                       continue;
+
+                               for (pn = 0; pn < module->max_op_port; pn++) {
+                                       if (module->dst_mod_inst_id[pn]) {
+                                               conn_obj = &mc_data->conn_obj[nconn];
+                                               conn_obj->src_mod_inst_id = module->instance_id;
+                                               conn_obj->src_mod_op_port_id =
+                                                               module->src_mod_op_port_id[pn];
+                                               conn_obj->dst_mod_inst_id =
+                                                               module->dst_mod_inst_id[pn];
+                                               conn_obj->dst_mod_ip_port_id =
+                                                               module->dst_mod_ip_port_id[pn];
+                                               nconn++;
+                                       }
                                }
-
-                               nmodule++;
                        }
-                       mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+                       mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj,
+                                                                       container->num_modules);
 
                        ncontainer++;
                }
        }
 }
 
-void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id)
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info *info)
 {
        int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz;
        struct apm_module_param_data  *param_data;
@@ -475,7 +430,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
        struct audioreach_module *module;
        struct audioreach_sub_graph *sgs;
        struct apm_mod_list_obj *mlobj;
-       int num_modules_per_list;
+       struct list_head *sg_list;
        int num_connections = 0;
        int num_containers = 0;
        int num_sub_graphs = 0;
@@ -484,24 +439,33 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
        struct gpr_pkt *pkt;
        void *p;
 
+       sg_list = &info->sg_list;
+       ml_sz = 0;
+
+       /* add FE-BE connections */
+       if (info->dst_mod_inst_id && info->src_mod_inst_id)
+               num_connections++;
+
        list_for_each_entry(sgs, sg_list, node) {
                num_sub_graphs++;
                list_for_each_entry(container, &sgs->container_list, node) {
                        num_containers++;
                        num_modules += container->num_modules;
-                       list_for_each_container_module(module, container) {
-                               if (module->src_mod_inst_id)
-                                       num_connections++;
+                       ml_sz = ml_sz + sizeof(struct apm_module_list_params) +
+                               APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+
+                       list_for_each_entry(module, &container->modules_list, node) {
+                               num_connections += module->num_connections;
                        }
                }
        }
 
        num_modules_list = num_containers;
-       num_modules_per_list = num_modules/num_containers;
        sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs);
        cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers);
-       ml_sz = ALIGN(sizeof(struct apm_module_list_params) +
-               num_modules_list * APM_MOD_LIST_OBJ_PSIZE(mlobj,  num_modules_per_list), 8);
+
+       ml_sz = ALIGN(ml_sz, 8);
+
        mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules);
        mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections);
 
@@ -536,7 +500,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
        param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
        param_data->param_id = APM_PARAM_ID_MODULE_LIST;
        param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE;
-       params.mod_list_data->num_modules_list = num_sub_graphs;
+       params.mod_list_data->num_modules_list = num_modules_list;
        p += ml_sz;
 
        /* Module Properties */
@@ -557,7 +521,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
        params.mod_conn_list_data->num_connections = num_connections;
        p += mc_sz;
 
-       audioreach_populate_graph(&params, sg_list, num_sub_graphs);
+       audioreach_populate_graph(apm, info, &params, sg_list, num_sub_graphs);
 
        return pkt;
 }
@@ -696,6 +660,160 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
        return rc;
 }
 
+static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
+                                        struct audioreach_module *module, bool enable)
+{
+       struct apm_module_param_data *param_data;
+       struct param_id_sal_limiter_enable *limiter_enable;
+       int payload_size;
+       struct gpr_pkt *pkt;
+       int rc;
+       void *p;
+
+       payload_size = sizeof(*limiter_enable) + APM_MODULE_PARAM_DATA_SIZE;
+
+       pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+       if (IS_ERR(pkt))
+               return PTR_ERR(pkt);
+
+       p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+       param_data = p;
+       param_data->module_instance_id = module->instance_id;
+       param_data->error_code = 0;
+       param_data->param_id = PARAM_ID_SAL_LIMITER_ENABLE;
+       param_data->param_size = sizeof(*limiter_enable);
+       p = p + APM_MODULE_PARAM_DATA_SIZE;
+       limiter_enable = p;
+
+       limiter_enable->enable_lim = enable;
+
+       rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+       kfree(pkt);
+
+       return rc;
+}
+
+static int audioreach_sal_set_media_format(struct q6apm_graph *graph,
+                                          struct audioreach_module *module,
+                                          struct audioreach_module_config *cfg)
+{
+       struct apm_module_param_data *param_data;
+       struct param_id_sal_output_config *media_format;
+       int payload_size;
+       struct gpr_pkt *pkt;
+       int rc;
+       void *p;
+
+       payload_size = sizeof(*media_format) + APM_MODULE_PARAM_DATA_SIZE;
+
+       pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+       if (IS_ERR(pkt))
+               return PTR_ERR(pkt);
+
+       p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+       param_data = p;
+       param_data->module_instance_id = module->instance_id;
+       param_data->error_code = 0;
+       param_data->param_id = PARAM_ID_SAL_OUTPUT_CFG;
+       param_data->param_size = sizeof(*media_format);
+       p = p + APM_MODULE_PARAM_DATA_SIZE;
+       media_format = p;
+
+       media_format->bits_per_sample = cfg->bit_width;
+
+       rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+       kfree(pkt);
+
+       return rc;
+}
+
+static int audioreach_module_enable(struct q6apm_graph *graph,
+                                   struct audioreach_module *module,
+                                   bool enable)
+{
+       struct apm_module_param_data *param_data;
+       struct param_id_module_enable *param;
+       int payload_size;
+       struct gpr_pkt *pkt;
+       int rc;
+       void *p;
+
+       payload_size = sizeof(*param) + APM_MODULE_PARAM_DATA_SIZE;
+
+       pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+       if (IS_ERR(pkt))
+               return PTR_ERR(pkt);
+
+       p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+       param_data = p;
+       param_data->module_instance_id = module->instance_id;
+       param_data->error_code = 0;
+       param_data->param_id = PARAM_ID_MODULE_ENABLE;
+       param_data->param_size = sizeof(*param);
+       p = p + APM_MODULE_PARAM_DATA_SIZE;
+       param = p;
+
+       param->enable = enable;
+
+       rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+       kfree(pkt);
+
+       return rc;
+}
+
+static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
+                                          struct audioreach_module *module,
+                                          struct audioreach_module_config *cfg)
+{
+       struct apm_module_param_data *param_data;
+       struct param_id_mfc_media_format *media_format;
+       uint32_t num_channels = cfg->num_channels;
+       int payload_size;
+       struct gpr_pkt *pkt;
+       int rc;
+       void *p;
+
+       payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
+               APM_MODULE_PARAM_DATA_SIZE;
+
+       pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+       if (IS_ERR(pkt))
+               return PTR_ERR(pkt);
+
+       p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+       param_data = p;
+       param_data->module_instance_id = module->instance_id;
+       param_data->error_code = 0;
+       param_data->param_id = PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+       param_data->param_size = APM_MFC_CFG_PSIZE(media_format, num_channels);
+       p = p + APM_MODULE_PARAM_DATA_SIZE;
+       media_format = p;
+
+       media_format->sample_rate = cfg->sample_rate;
+       media_format->bit_width = cfg->bit_width;
+       media_format->num_channels = cfg->num_channels;
+
+       if (num_channels == 1) {
+               media_format->channel_mapping[0] = PCM_CHANNEL_L;
+       } else if (num_channels == 2) {
+               media_format->channel_mapping[0] = PCM_CHANNEL_L;
+               media_format->channel_mapping[1] = PCM_CHANNEL_R;
+       }
+
+       rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+       kfree(pkt);
+
+       return rc;
+}
+
 static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
                                           struct audioreach_module *module,
                                           struct audioreach_module_config *cfg)
@@ -995,7 +1113,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
 
        switch (module->module_id) {
        case MODULE_ID_DATA_LOGGING:
-               rc = audioreach_logging_set_media_format(graph, module);
+               rc = audioreach_module_enable(graph, module, true);
+               if (!rc)
+                       rc = audioreach_logging_set_media_format(graph, module);
                break;
        case MODULE_ID_PCM_DEC:
        case MODULE_ID_PCM_ENC:
@@ -1016,6 +1136,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
        case MODULE_ID_CODEC_DMA_SOURCE:
                rc = audioreach_codec_dma_set_media_format(graph, module, cfg);
                break;
+       case MODULE_ID_SAL:
+               rc = audioreach_sal_set_media_format(graph, module, cfg);
+               if (!rc)
+                       rc = audioreach_sal_limiter_enable(graph, module, true);
+               break;
+       case MODULE_ID_MFC:
+               rc = audioreach_mfc_set_media_format(graph, module, cfg);
+               break;
        default:
                rc = 0;
        }
index 3ee8bfc..1d1d47d 100644 (file)
@@ -15,6 +15,8 @@ struct q6apm_graph;
 #define MODULE_ID_PCM_CNV              0x07001003
 #define MODULE_ID_PCM_ENC              0x07001004
 #define MODULE_ID_PCM_DEC              0x07001005
+#define MODULE_ID_SAL                  0x07001010
+#define MODULE_ID_MFC                  0x07001015
 #define MODULE_ID_CODEC_DMA_SINK       0x07001023
 #define MODULE_ID_CODEC_DMA_SOURCE     0x07001024
 #define MODULE_ID_I2S_SINK             0x0700100A
@@ -499,6 +501,16 @@ struct data_logging_config {
        uint32_t mode;
 } __packed;
 
+#define PARAM_ID_SAL_OUTPUT_CFG                        0x08001016
+struct param_id_sal_output_config {
+       uint32_t bits_per_sample;
+} __packed;
+
+#define PARAM_ID_SAL_LIMITER_ENABLE            0x0800101E
+struct param_id_sal_limiter_enable {
+       uint32_t enable_lim;
+} __packed;
+
 #define PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT       0x08001024
 
 struct param_id_mfc_media_format {
@@ -525,6 +537,11 @@ struct payload_media_fmt_pcm {
        uint8_t channel_mapping[];
 } __packed;
 
+#define PARAM_ID_MODULE_ENABLE                 0x08001026
+struct param_id_module_enable {
+       uint32_t enable;
+} __packed;
+
 #define PARAM_ID_CODEC_DMA_INTF_CFG            0x08001063
 
 struct param_id_codec_dma_intf_cfg {
@@ -595,7 +612,11 @@ struct audioreach_graph_info {
        int id;
        uint32_t num_sub_graphs;
        struct list_head sg_list;
-       struct list_head connection_list;
+       /* DPCM connection from FE Graph to BE graph */
+       uint32_t src_mod_inst_id;
+       uint32_t src_mod_op_port_id;
+       uint32_t dst_mod_inst_id;
+       uint32_t dst_mod_ip_port_id;
 };
 
 struct audioreach_sub_graph {
@@ -623,6 +644,8 @@ struct audioreach_container {
        struct audioreach_sub_graph *sub_graph;
 };
 
+#define AR_MAX_MOD_LINKS       8
+
 struct audioreach_module {
        uint32_t module_id;
        uint32_t instance_id;
@@ -633,11 +656,12 @@ struct audioreach_module {
        uint32_t in_port;
        uint32_t out_port;
 
+       uint32_t num_connections;
        /* Connections */
        uint32_t src_mod_inst_id;
-       uint32_t src_mod_op_port_id;
-       uint32_t dst_mod_inst_id;
-       uint32_t dst_mod_ip_port_id;
+       uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS];
+       uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS];
+       uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS];
 
        /* Format specifics */
        uint32_t ch_fmt;
@@ -694,9 +718,8 @@ void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token,
 void *audioreach_alloc_pkt(int payload_size, uint32_t opcode,
                           uint32_t token, uint32_t src_port,
                           uint32_t dest_port);
-void *audioreach_alloc_graph_pkt(struct q6apm *apm,
-                                struct list_head *sg_list,
-                                 int graph_id);
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info
+                                *info);
 /* Topology specific */
 int audioreach_tplg_init(struct snd_soc_component *component);
 
@@ -717,14 +740,4 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
 int audioreach_shared_memory_send_eos(struct q6apm_graph *graph);
 int audioreach_gain_set_vol_ctrl(struct q6apm *apm,
                                 struct audioreach_module *module, int vol);
-struct audioreach_module *audioreach_get_container_last_module(
-                               struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_first_module(
-                               struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_next_module(
-                               struct audioreach_container *container,
-                               struct audioreach_module *module);
-#define list_for_each_container_module(mod, cont) \
-       for (mod = audioreach_get_container_first_module(cont); mod != NULL; \
-            mod = audioreach_get_container_next_module(cont, mod))
 #endif /* __AUDIOREACH_H__ */
index 7940192..5beb898 100644 (file)
@@ -63,7 +63,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
        graph->info = info;
        graph->id = graph_id;
 
-       graph->graph = audioreach_alloc_graph_pkt(apm, &info->sg_list, graph_id);
+       graph->graph = audioreach_alloc_graph_pkt(apm, info);
        if (IS_ERR(graph->graph)) {
                void *err = graph->graph;
 
@@ -178,87 +178,6 @@ static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
        return NULL;
 }
 
-static struct audioreach_module *q6apm_graph_get_last_module(struct q6apm *apm, u32 sgid)
-{
-       struct audioreach_container *container;
-       struct audioreach_module *module;
-       struct audioreach_sub_graph *sg;
-
-       mutex_lock(&apm->lock);
-       sg = idr_find(&apm->sub_graphs_idr, sgid);
-       mutex_unlock(&apm->lock);
-       if (!sg)
-               return NULL;
-
-       container = list_last_entry(&sg->container_list, struct audioreach_container, node);
-       module = audioreach_get_container_last_module(container);
-
-       return module;
-}
-
-static struct audioreach_module *q6apm_graph_get_first_module(struct q6apm *apm, u32 sgid)
-{
-       struct audioreach_container *container;
-       struct audioreach_module *module;
-       struct audioreach_sub_graph *sg;
-
-       mutex_lock(&apm->lock);
-       sg = idr_find(&apm->sub_graphs_idr, sgid);
-       mutex_unlock(&apm->lock);
-       if (!sg)
-               return NULL;
-
-       container = list_first_entry(&sg->container_list, struct audioreach_container, node);
-       module = audioreach_get_container_first_module(container);
-
-       return module;
-}
-
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, u32 dst_sgid)
-{
-       struct audioreach_module *module;
-       u32 iid;
-
-       module = q6apm_graph_get_last_module(apm, src_sgid);
-       if (!module)
-               return false;
-
-       iid = module->instance_id;
-       module = q6apm_graph_get_first_module(apm, dst_sgid);
-       if (!module)
-               return false;
-
-       if (module->src_mod_inst_id == iid)
-               return true;
-
-       return false;
-}
-
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, bool connect)
-{
-       struct audioreach_module *module;
-       u32 iid;
-
-       if (connect) {
-               module = q6apm_graph_get_last_module(apm, src_sgid);
-               if (!module)
-                       return -ENODEV;
-
-               iid = module->instance_id;
-       } else {
-               iid = 0;
-       }
-
-       module = q6apm_graph_get_first_module(apm, dst_sgid);
-       if (!module)
-               return -ENODEV;
-
-       /* set src module in dst subgraph first module */
-       module->src_mod_inst_id = iid;
-
-       return 0;
-}
-
 int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
                                   struct audioreach_module_config *cfg)
 {
@@ -731,6 +650,7 @@ static int apm_probe(gpr_device_t *gdev)
        apm->gdev = gdev;
        init_waitqueue_head(&apm->wait);
 
+       INIT_LIST_HEAD(&apm->widget_list);
        idr_init(&apm->graph_idr);
        idr_init(&apm->graph_info_idr);
        idr_init(&apm->sub_graphs_idr);
index 54eadad..273f978 100644 (file)
@@ -58,6 +58,7 @@ struct q6apm {
        struct mutex lock;
        uint32_t state;
 
+       struct list_head widget_list;
        struct idr graph_idr;
        struct idr graph_info_idr;
        struct idr sub_graphs_idr;
@@ -141,12 +142,7 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
 /* Callback for graph specific */
 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
                                                    uint32_t mid);
-
 void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid,
-                            bool connect);
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid,
-                                  u32 dst_sgid);
 int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
 
 #endif /* __APM_GRAPH_ */
index cda33de..8aa1a21 100644 (file)
@@ -247,5 +247,5 @@ static gpr_driver_t prm_driver = {
 };
 
 module_gpr_driver(prm_driver);
-MODULE_DESCRIPTION("Audio Process Manager");
+MODULE_DESCRIPTION("Q6 Proxy Resource Manager");
 MODULE_LICENSE("GPL");
index bd649c2..cccc59b 100644 (file)
 #include "audioreach.h"
 
 struct snd_ar_control {
+       u32 graph_id; /* Graph ID */
        u32 sgid; /* Sub Graph ID */
+       u32 module_instance_id; /* Connected Module Instance ID */
+       struct snd_soc_dapm_widget *w;
+       struct list_head node;
        struct snd_soc_component *scomp;
 };
 
@@ -44,7 +48,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
        INIT_LIST_HEAD(&info->sg_list);
 
        mutex_lock(&apm->lock);
-       ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL);
+       ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL);
        mutex_unlock(&apm->lock);
 
        if (ret < 0) {
@@ -53,7 +57,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
                return ERR_PTR(ret);
        }
 
-       info->id = ret;
+       info->id = graph_id;
 
        return info;
 }
@@ -94,7 +98,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
        INIT_LIST_HEAD(&sg->container_list);
 
        mutex_lock(&apm->lock);
-       ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL);
+       ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL);
        mutex_unlock(&apm->lock);
 
        if (ret < 0) {
@@ -103,7 +107,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
                return ERR_PTR(ret);
        }
 
-       sg->sub_graph_id = ret;
+       sg->sub_graph_id = sub_graph_id;
 
        return sg;
 }
@@ -136,7 +140,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
        INIT_LIST_HEAD(&cont->modules_list);
 
        mutex_lock(&apm->lock);
-       ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL);
+       ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL);
        mutex_unlock(&apm->lock);
 
        if (ret < 0) {
@@ -145,7 +149,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
                return ERR_PTR(ret);
        }
 
-       cont->container_id = ret;
+       cont->container_id = container_id;
        cont->sub_graph = sg;
        /* add to container list */
        list_add_tail(&cont->node, &sg->container_list);
@@ -181,7 +185,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
                                       AR_MODULE_DYNAMIC_INSTANCE_ID_START,
                                       AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
        } else {
-               ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL);
+               ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL);
        }
        mutex_unlock(&apm->lock);
 
@@ -191,7 +195,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
                return ERR_PTR(ret);
        }
 
-       mod->instance_id = ret;
+       mod->instance_id = module_id;
        /* add to module list */
        list_add_tail(&mod->node, &cont->modules_list);
        mod->container = cont;
@@ -408,19 +412,25 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
                                                        struct snd_soc_dapm_widget *w)
 {
        uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
-       uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0;
-       uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0;
+       uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
+       uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
+       uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
+       uint32_t src_mod_inst_id = 0;
+
        int module_id = 0, instance_id = 0, tkn_count = 0;
        struct snd_soc_tplg_vendor_value_elem *mod_elem;
        struct snd_soc_tplg_vendor_array *mod_array;
        struct audioreach_module *mod = NULL;
+       uint32_t token;
        bool found;
+       int max_tokens;
 
        mod_array = audioreach_get_module_array(private);
        mod_elem = mod_array->value;
-
-       while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
-               switch (le32_to_cpu(mod_elem->token)) {
+       max_tokens = le32_to_cpu(mod_array->num_elems);
+       while (tkn_count <= (max_tokens - 1)) {
+               token = le32_to_cpu(mod_elem->token);
+               switch (token) {
                /* common module info */
                case AR_TKN_U32_MODULE_ID:
                        module_id = le32_to_cpu(mod_elem->value);
@@ -450,17 +460,80 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
                case AR_TKN_U32_MODULE_OUT_PORTS:
                        out_port = le32_to_cpu(mod_elem->value);
                        break;
-               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
-                       src_mod_op_port_id = le32_to_cpu(mod_elem->value);
-                       break;
                case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
                        src_mod_inst_id = le32_to_cpu(mod_elem->value);
                        break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
+                       src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
+                       src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
+                       src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
+                       src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
+                       src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
+                       src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
+                       src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
+                       src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
+                       break;
                case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
-                       dst_mod_inst_id = le32_to_cpu(mod_elem->value);
+                       dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
+                       dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
+                       dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
+                       dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
+                       dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
+                       dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
+                       dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
+                       dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
                        break;
                case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
-                       dst_mod_ip_port_id = le32_to_cpu(mod_elem->value);
+                       dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
+                       dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
+                       dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
+                       dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
+                       dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
+                       dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
+                       dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
+                       break;
+               case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
+                       dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
                        break;
                default:
                        break;
@@ -471,15 +544,23 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
        }
 
        if (mod) {
+               int pn, id = 0;
                mod->module_id = module_id;
                mod->max_ip_port = max_ip_port;
                mod->max_op_port = max_op_port;
                mod->in_port = in_port;
                mod->out_port = out_port;
                mod->src_mod_inst_id = src_mod_inst_id;
-               mod->src_mod_op_port_id = src_mod_op_port_id;
-               mod->dst_mod_inst_id = dst_mod_inst_id;
-               mod->dst_mod_ip_port_id = dst_mod_ip_port_id;
+               for (pn = 0; pn < mod->max_op_port; pn++) {
+                       if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
+                           dst_mod_ip_port_id[pn]) {
+                               mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
+                               mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
+                               mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
+                               id++;
+                               mod->num_connections = id;
+                       }
+               }
        }
 
        return mod;
@@ -692,6 +773,7 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
        struct snd_soc_tplg_vendor_value_elem *w_elem;
        struct snd_soc_tplg_vendor_array *w_array;
        struct snd_ar_control *scontrol;
+       struct q6apm *data = dev_get_drvdata(component->dev);
        struct snd_soc_dobj *dobj;
        int tkn_count = 0;
 
@@ -711,6 +793,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
                case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
                        scontrol->sgid = le32_to_cpu(w_elem->value);
                        break;
+               case AR_TKN_DAI_INDEX:
+                       scontrol->graph_id = le32_to_cpu(w_elem->value);
+                       break;
                default: /* ignore other tokens */
                        break;
                }
@@ -718,6 +803,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
                w_elem++;
        }
 
+       scontrol->w = w;
+       list_add_tail(&scontrol->node, &data->widget_list);
+
        return 0;
 }
 
@@ -819,7 +907,10 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
 
        if (w->id == snd_soc_dapm_mixer) {
                /* virtual widget */
-               kfree(dobj->private);
+               struct snd_ar_control *scontrol = dobj->private;
+
+               list_del(&scontrol->node);
+               kfree(scontrol);
                return 0;
        }
 
@@ -858,7 +949,21 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
        return 0;
 }
 
-static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp,
+static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
+                                                    const char *name)
+{
+       struct q6apm *apm = dev_get_drvdata(comp->dev);
+       struct snd_ar_control *control;
+
+       list_for_each_entry(control, &apm->widget_list, node) {
+               if (control->w && !strcmp(name, control->w->name))
+                       return control;
+       }
+
+       return NULL;
+}
+
+static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
                                                        const char *name)
 {
        struct q6apm *apm = dev_get_drvdata(comp->dev);
@@ -876,14 +981,41 @@ static struct audioreach_module *audioreach_find_widget(struct snd_soc_component
 static int audioreach_route_load(struct snd_soc_component *scomp, int index,
                                 struct snd_soc_dapm_route *route)
 {
-       struct audioreach_module *src, *sink;
-
-       src = audioreach_find_widget(scomp, route->source);
-       sink = audioreach_find_widget(scomp, route->sink);
+       struct audioreach_module *src_module, *sink_module;
+       struct snd_ar_control *control;
+       struct snd_soc_dapm_widget *w;
+       int i;
+
+       /* check if these are actual modules */
+       src_module = audioreach_find_module(scomp, route->source);
+       sink_module = audioreach_find_module(scomp, route->sink);
+
+       if (sink_module && !src_module) {
+               control = audioreach_find_widget(scomp, route->source);
+               if (control)
+                       control->module_instance_id = sink_module->instance_id;
+
+       } else if (!sink_module && src_module && route->control) {
+               /* check if this is a virtual mixer */
+               control = audioreach_find_widget(scomp, route->sink);
+               if (!control || !control->w)
+                       return 0;
+
+               w = control->w;
+
+               for (i = 0; i < w->num_kcontrols; i++) {
+                       if (!strcmp(route->control, w->kcontrol_news[i].name)) {
+                               struct soc_mixer_control *sm;
+                               struct snd_soc_dobj *dobj;
+                               struct snd_ar_control *scontrol;
+
+                               sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
+                               dobj = &sm->dobj;
+                               scontrol = dobj->private;
+                               scontrol->module_instance_id = src_module->instance_id;
+                       }
+               }
 
-       if (src && sink) {
-               src->dst_mod_inst_id = sink->instance_id;
-               sink->src_mod_inst_id = src->instance_id;
        }
 
        return 0;
@@ -914,6 +1046,48 @@ static int audioreach_link_load(struct snd_soc_component *component, int index,
        return 0;
 }
 
+static void audioreach_connect_sub_graphs(struct q6apm *apm,
+                                         struct snd_ar_control *m1,
+                                         struct snd_ar_control *m2,
+                                         bool connect)
+{
+       struct audioreach_graph_info *info;
+
+       mutex_lock(&apm->lock);
+       info = idr_find(&apm->graph_info_idr, m2->graph_id);
+       mutex_unlock(&apm->lock);
+
+       if (connect) {
+               info->src_mod_inst_id = m1->module_instance_id;
+               info->src_mod_op_port_id = 1;
+               info->dst_mod_inst_id = m2->module_instance_id;
+               info->dst_mod_ip_port_id = 2;
+
+       } else {
+               info->src_mod_inst_id = 0;
+               info->src_mod_op_port_id = 0;
+               info->dst_mod_inst_id = 0;
+               info->dst_mod_ip_port_id = 0;
+       }
+}
+
+static bool audioreach_is_vmixer_connected(struct q6apm *apm,
+                                          struct snd_ar_control *m1,
+                                          struct snd_ar_control *m2)
+{
+       struct audioreach_graph_info *info;
+
+       mutex_lock(&apm->lock);
+       info = idr_find(&apm->graph_info_idr, m2->graph_id);
+       mutex_unlock(&apm->lock);
+
+       if (info->dst_mod_inst_id == m2->module_instance_id &&
+           info->src_mod_inst_id == m1->module_instance_id)
+               return true;
+
+       return false;
+}
+
 static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
@@ -926,7 +1100,7 @@ static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
        struct q6apm *data = dev_get_drvdata(c->dev);
        bool connected;
 
-       connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid);
+       connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
        if (connected)
                ucontrol->value.integer.value[0] = 1;
        else
@@ -947,10 +1121,10 @@ static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
        struct q6apm *data = dev_get_drvdata(c->dev);
 
        if (ucontrol->value.integer.value[0]) {
-               q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true);
+               audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
        } else {
-               q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false);
+               audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
        }
        return 0;
@@ -998,6 +1172,9 @@ static int audioreach_control_load_mix(struct snd_soc_component *scomp,
                case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
                        scontrol->sgid = le32_to_cpu(c_elem->value);
                        break;
+               case AR_TKN_DAI_INDEX:
+                       scontrol->graph_id = le32_to_cpu(c_elem->value);
+                       break;
                default:
                        /* Ignore other tokens */
                        break;
index 2540b9b..5e52e9d 100644 (file)
@@ -21,7 +21,6 @@
 #include <sound/soc.h>
 #include "rockchip_i2s.h"
 #include "../codecs/da7219.h"
-#include "../codecs/da7219-aad.h"
 #include "../codecs/rt5514.h"
 
 #define DRV_NAME "rk3399-gru-sound"
@@ -226,7 +225,7 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
        snd_jack_set_key(
                rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-       da7219_aad_jack_det(component, &rockchip_sound_jack);
+       snd_soc_component_set_jack(component, &rockchip_sound_jack, NULL);
 
        return 0;
 }
index 7e380d7..2d269ac 100644 (file)
@@ -1518,7 +1518,8 @@ static int rsnd_hw_params(struct snd_soc_component *component,
                int stream = substream->stream;
 
                for_each_dpcm_be(fe, stream, dpcm) {
-                       struct snd_pcm_hw_params *be_params = &dpcm->hw_params;
+                       struct snd_soc_pcm_runtime *be = dpcm->be;
+                       struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params;
 
                        if (params_channels(hw_params) != params_channels(be_params))
                                io->converted_chan = params_channels(be_params);
@@ -1581,9 +1582,9 @@ static int rsnd_hw_params(struct snd_soc_component *component,
                                hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
                        } else if (params_rate(hw_params) * k_up < io->converted_rate) {
                                hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
-                                       (io->converted_rate + k_up - 1) / k_up;
+                                       DIV_ROUND_UP(io->converted_rate, k_up);
                                hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
-                                       (io->converted_rate + k_up - 1) / k_up;
+                                       DIV_ROUND_UP(io->converted_rate, k_up);
                                hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
                        }
 
index 12a82f5..d8b092f 100644 (file)
@@ -447,7 +447,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
         */
        rtd = devm_kzalloc(dev,
                           sizeof(*rtd) +
-                          sizeof(*component) * (dai_link->num_cpus +
+                          sizeof(component) * (dai_link->num_cpus +
                                                 dai_link->num_codecs +
                                                 dai_link->num_platforms),
                           GFP_KERNEL);
@@ -939,9 +939,6 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
 {
        lockdep_assert_held(&client_mutex);
 
-       /* release machine specific resources */
-       snd_soc_link_exit(rtd);
-
        /*
         * Notify the machine driver for extra destruction
         */
@@ -1890,6 +1887,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
 
        snd_soc_dapm_shutdown(card);
 
+       /* release machine specific resources */
+       for_each_card_rtds(card, rtd)
+               snd_soc_link_exit(rtd);
        /* remove and free each DAI */
        soc_remove_link_dais(card);
        soc_remove_link_components(card);
index 49752af..29a75fd 100644 (file)
@@ -386,23 +386,16 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
                          struct snd_pcm_substream *substream,
                          struct snd_pcm_hw_params *params)
 {
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        int ret = 0;
 
        if (dai->driver->ops &&
-           dai->driver->ops->hw_params) {
-               /* perform any topology hw_params fixups before DAI  */
-               ret = snd_soc_link_be_hw_params_fixup(rtd, params);
-               if (ret < 0)
-                       goto end;
-
+           dai->driver->ops->hw_params)
                ret = dai->driver->ops->hw_params(substream, params, dai);
-       }
 
        /* mark substream if succeeded */
        if (ret == 0)
                soc_dai_mark_push(dai, substream, hw_params);
-end:
+
        return soc_dai_ret(dai, ret);
 }
 
index d515e7a..954ca9a 100644 (file)
@@ -71,9 +71,9 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_pinctrl] = 2,
        [snd_soc_dapm_clock_supply] = 2,
        [snd_soc_dapm_supply] = 3,
+       [snd_soc_dapm_dai_link] = 3,
        [snd_soc_dapm_micbias] = 4,
        [snd_soc_dapm_vmid] = 4,
-       [snd_soc_dapm_dai_link] = 3,
        [snd_soc_dapm_dai_in] = 5,
        [snd_soc_dapm_dai_out] = 5,
        [snd_soc_dapm_aif_in] = 5,
@@ -652,10 +652,8 @@ static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
 }
 
 static struct snd_soc_dapm_widget *
-dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
+dapm_wcache_lookup(struct snd_soc_dapm_widget *w, const char *name)
 {
-       struct snd_soc_dapm_widget *w = wcache->widget;
-
        if (w) {
                struct list_head *wlist = &w->dapm->card->widgets;
                const int depth = 2;
@@ -673,12 +671,6 @@ dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
        return NULL;
 }
 
-static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
-                                     struct snd_soc_dapm_widget *w)
-{
-       wcache->widget = w;
-}
-
 /**
  * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
  * @dapm: The DAPM context for which to set the level
@@ -1881,58 +1873,52 @@ static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
                dapm_mark_dirty(peer, "peer state change");
 }
 
-static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
+static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
                                  struct list_head *up_list,
                                  struct list_head *down_list)
 {
        struct snd_soc_dapm_path *path;
+       int power;
+
+       switch (w->id) {
+       case snd_soc_dapm_pre:
+               power = 0;
+               goto end;
+       case snd_soc_dapm_post:
+               power = 1;
+               goto end;
+       default:
+               break;
+       }
+
+       power = dapm_widget_power_check(w);
 
        if (w->power == power)
                return;
 
        trace_snd_soc_dapm_widget_power(w, power);
 
-       /* If we changed our power state perhaps our neigbours changed
-        * also.
+       /*
+        * If we changed our power state perhaps our neigbours
+        * changed also.
         */
        snd_soc_dapm_widget_for_each_source_path(w, path)
                dapm_widget_set_peer_power(path->source, power, path->connect);
 
-       /* Supplies can't affect their outputs, only their inputs */
-       if (!w->is_supply) {
+       /*
+        * Supplies can't affect their outputs, only their inputs
+        */
+       if (!w->is_supply)
                snd_soc_dapm_widget_for_each_sink_path(w, path)
-                       dapm_widget_set_peer_power(path->sink, power,
-                                                  path->connect);
-       }
+                       dapm_widget_set_peer_power(path->sink, power, path->connect);
 
+end:
        if (power)
                dapm_seq_insert(w, up_list, true);
        else
                dapm_seq_insert(w, down_list, false);
 }
 
-static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
-                                 struct list_head *up_list,
-                                 struct list_head *down_list)
-{
-       int power;
-
-       switch (w->id) {
-       case snd_soc_dapm_pre:
-               dapm_seq_insert(w, down_list, false);
-               break;
-       case snd_soc_dapm_post:
-               dapm_seq_insert(w, up_list, true);
-               break;
-
-       default:
-               power = dapm_widget_power_check(w);
-
-               dapm_widget_set_power(w, power, up_list, down_list);
-               break;
-       }
-}
-
 static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
 {
        if (dapm->idle_bias_off)
@@ -2497,6 +2483,9 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
        struct snd_soc_dapm_path *p, *next_p;
        enum snd_soc_dapm_direction dir;
 
+       if (!w)
+               return;
+
        list_del(&w->list);
        list_del(&w->dirty);
        /*
@@ -2516,12 +2505,6 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free_widget);
 
-void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
-{
-       dapm->path_sink_cache.widget = NULL;
-       dapm->path_source_cache.widget = NULL;
-}
-
 /* free all dapm widgets and resources */
 static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
@@ -2532,7 +2515,9 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                        continue;
                snd_soc_dapm_free_widget(w);
        }
-       snd_soc_dapm_reset_cache(dapm);
+
+       dapm->wcache_sink       = NULL;
+       dapm->wcache_source     = NULL;
 }
 
 static struct snd_soc_dapm_widget *dapm_find_widget(
@@ -2838,7 +2823,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        int (*connected)(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink))
 {
-       struct snd_soc_dapm_widget *widgets[2];
        enum snd_soc_dapm_direction dir;
        struct snd_soc_dapm_path *path;
        int ret;
@@ -2874,8 +2858,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
 
        path->node[SND_SOC_DAPM_DIR_IN] = wsource;
        path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
-       widgets[SND_SOC_DAPM_DIR_IN] = wsource;
-       widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
 
        path->connected = connected;
        INIT_LIST_HEAD(&path->list);
@@ -2917,12 +2899,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        }
 
        list_add(&path->list, &dapm->card->paths);
+
        snd_soc_dapm_for_each_direction(dir)
-               list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
+               list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
 
        snd_soc_dapm_for_each_direction(dir) {
-               dapm_update_widget_flags(widgets[dir]);
-               dapm_mark_dirty(widgets[dir], "Route added");
+               dapm_update_widget_flags(path->node[dir]);
+               dapm_mark_dirty(path->node[dir], "Route added");
        }
 
        if (dapm->card->instantiated && path->connect)
@@ -2961,8 +2944,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
                source = route->source;
        }
 
-       wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
-       wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
+       wsource = dapm_wcache_lookup(dapm->wcache_source, source);
+       wsink   = dapm_wcache_lookup(dapm->wcache_sink,   sink);
 
        if (wsink && wsource)
                goto skip_search;
@@ -3006,30 +2989,27 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        if (!wsource)
                wsource = wtsource;
 
-       if (wsource == NULL) {
-               dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
-                       route->source);
-               return -ENODEV;
-       }
-       if (wsink == NULL) {
-               dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
-                       route->sink);
-               return -ENODEV;
-       }
+       ret = -ENODEV;
+       if (!wsource)
+               goto err;
+       if (!wsink)
+               goto err;
 
 skip_search:
-       dapm_wcache_update(&dapm->path_sink_cache, wsink);
-       dapm_wcache_update(&dapm->path_source_cache, wsource);
+       /* update cache */
+       dapm->wcache_sink       = wsink;
+       dapm->wcache_source     = wsource;
 
        ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
                route->connected);
-       if (ret)
-               goto err;
-
-       return 0;
 err:
-       dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
-                source, route->control, sink);
+       if (ret)
+               dev_err(dapm->dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
+                       source, !wsource ? "(*)" : "",
+                       !route->control ? "" : "> [",
+                       !route->control ? "" : route->control,
+                       !route->control ? "" : "] -",
+                       sink,  !wsink ? "(*)" : "");
        return ret;
 }
 
@@ -3115,13 +3095,8 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        for (i = 0; i < num; i++) {
                int r = snd_soc_dapm_add_route(dapm, route);
-               if (r < 0) {
-                       dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
-                               route->source,
-                               route->control ? route->control : "direct",
-                               route->sink);
+               if (r < 0)
                        ret = r;
-               }
                route++;
        }
        mutex_unlock(&dapm->card->dapm_mutex);
@@ -4157,56 +4132,53 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dapm_widget template;
        struct snd_soc_dapm_widget *w;
+       const struct snd_kcontrol_new *kcontrol_news;
+       int num_kcontrols;
        const char **w_param_text;
        unsigned long private_value = 0;
        char *link_name;
-       int ret;
+       int ret = -ENOMEM;
 
        link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
                                   rtd->dai_link->name, id);
        if (!link_name)
-               return ERR_PTR(-ENOMEM);
-
-       memset(&template, 0, sizeof(template));
-       template.reg = SND_SOC_NOPM;
-       template.id = snd_soc_dapm_dai_link;
-       template.name = link_name;
-       template.event = snd_soc_dai_link_event;
-       template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
-       template.kcontrol_news = NULL;
+               goto name_fail;
 
        /* allocate memory for control, only in case of multiple configs */
+       w_param_text    = NULL;
+       kcontrol_news   = NULL;
+       num_kcontrols   = 0;
        if (rtd->dai_link->num_params > 1) {
                w_param_text = devm_kcalloc(card->dev,
                                            rtd->dai_link->num_params,
                                            sizeof(char *), GFP_KERNEL);
-               if (!w_param_text) {
-                       ret = -ENOMEM;
+               if (!w_param_text)
                        goto param_fail;
-               }
 
-               template.num_kcontrols = 1;
-               template.kcontrol_news =
-                                       snd_soc_dapm_alloc_kcontrol(card,
-                                               link_name,
-                                               rtd->dai_link->params,
-                                               rtd->dai_link->num_params,
-                                               w_param_text, &private_value);
-               if (!template.kcontrol_news) {
-                       ret = -ENOMEM;
+               num_kcontrols = 1;
+               kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, link_name,
+                                                           rtd->dai_link->params,
+                                                           rtd->dai_link->num_params,
+                                                           w_param_text, &private_value);
+               if (!kcontrol_news)
                        goto param_fail;
-               }
-       } else {
-               w_param_text = NULL;
        }
+
+       memset(&template, 0, sizeof(template));
+       template.reg            = SND_SOC_NOPM;
+       template.id             = snd_soc_dapm_dai_link;
+       template.name           = link_name;
+       template.event          = snd_soc_dai_link_event;
+       template.event_flags    = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                                 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
+       template.kcontrol_news  = kcontrol_news;
+       template.num_kcontrols  = num_kcontrols;
+
        dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
 
        w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
        if (IS_ERR(w)) {
                ret = PTR_ERR(w);
-               dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n",
-                       link_name, ret);
                goto outfree_kcontrol_news;
        }
 
@@ -4220,6 +4192,9 @@ outfree_kcontrol_news:
                                   rtd->dai_link->num_params, w_param_text);
 param_fail:
        devm_kfree(card->dev, link_name);
+name_fail:
+       dev_err(rtd->dev, "ASoC: Failed to create %s-%s widget: %d\n",
+               rtd->dai_link->name, id, ret);
        return ERR_PTR(ret);
 }
 
index fb87d6d..d8e4677 100644 (file)
@@ -155,7 +155,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
 
        for_each_dpcm_be(fe, stream, dpcm) {
                struct snd_soc_pcm_runtime *be = dpcm->be;
-               params = &dpcm->hw_params;
+               params = &be->dpcm[stream].hw_params;
 
                offset += scnprintf(buf + offset, size - offset,
                                   "- %s\n", be->dai_link->name);
@@ -1980,6 +1980,8 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
        int ret;
 
        for_each_dpcm_be(fe, stream, dpcm) {
+               struct snd_pcm_hw_params hw_params;
+
                be = dpcm->be;
                be_substream = snd_soc_dpcm_get_substream(be, stream);
 
@@ -1988,16 +1990,16 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
                        continue;
 
                /* copy params for each dpcm */
-               memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+               memcpy(&hw_params, &fe->dpcm[stream].hw_params,
                                sizeof(struct snd_pcm_hw_params));
 
                /* perform any hw_params fixups */
-               ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
+               ret = snd_soc_link_be_hw_params_fixup(be, &hw_params);
                if (ret < 0)
                        goto unwind;
 
                /* copy the fixed-up hw params for BE dai */
-               memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
+               memcpy(&be->dpcm[stream].hw_params, &hw_params,
                       sizeof(struct snd_pcm_hw_params));
 
                /* only allow hw_params() if no connected FEs are running */
@@ -2012,7 +2014,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
                dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
                        be->dai_link->name);
 
-               ret = __soc_pcm_hw_params(be, be_substream, &dpcm->hw_params);
+               ret = __soc_pcm_hw_params(be, be_substream, &hw_params);
                if (ret < 0)
                        goto unwind;
 
index a3b6df2..a4dba0b 100644 (file)
@@ -264,7 +264,7 @@ int __init snd_soc_util_init(void)
        return ret;
 }
 
-void __exit snd_soc_util_exit(void)
+void snd_soc_util_exit(void)
 {
        platform_driver_unregister(&soc_dummy_driver);
        platform_device_unregister(soc_dummy_dev);
index 37f7df5..0b9beb7 100644 (file)
@@ -97,13 +97,13 @@ config SND_SOC_SOF_NOCODEC
        tristate
 
 config SND_SOC_SOF_NOCODEC_SUPPORT
-       bool "SOF nocodec mode support"
+       bool "SOF nocodec static mode support"
        help
          This adds support for a dummy/nocodec machine driver fallback
          option if no known codec is detected. This is typically only
          enabled for developers or devices where the sound card is
          controlled externally.
-         This option is mutually exclusive with the Intel HDAudio support.
+         This option is mutually exclusive at build time with the Intel HDAudio support.
          Selecting it may have negative impacts and prevent e.g. microphone
          functionality from being enabled on Intel CoffeeLake and later
          platforms.
@@ -136,6 +136,19 @@ config SND_SOC_SOF_DEBUG
 
 if SND_SOC_SOF_DEBUG
 
+config SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
+       bool "SOF nocodec debug mode support"
+       depends on !SND_SOC_SOF_NOCODEC_SUPPORT
+       help
+         This adds support for a dummy/nocodec machine driver fallback
+         option.
+         Unlike the SND_SOC_SOF_NOCODEC_SUPPORT, this option is NOT
+         mutually exclusive at build with the Intel HDAudio support. The
+         selection will be done depending on command line or modprobe.d settings
+         Distributions should not select this option!
+         Say Y if you need this nocodec debug fallback option.
+         If unsure select "N".
+
 config SND_SOC_SOF_FORCE_NOCODEC_MODE
        bool "SOF force nocodec Mode"
        depends on SND_SOC_SOF_NOCODEC_SUPPORT
@@ -239,6 +252,7 @@ config SND_SOC_SOF
        tristate
        select SND_SOC_TOPOLOGY
        select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
+       select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level.
index eab7cc5..308d876 100644 (file)
@@ -27,6 +27,12 @@ snd-sof-of-objs := sof-of-dev.o
 snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
 snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
 snd-sof-probes-objs := sof-client-probes.o
+ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
+snd-sof-probes-objs += sof-client-probes-ipc3.o
+endif
+ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
+snd-sof-probes-objs += sof-client-probes-ipc4.o
+endif
 
 snd-sof-nocodec-objs := nocodec.o
 
index d1e74ba..090c8b1 100644 (file)
@@ -48,7 +48,6 @@ EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON);
 int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
                        u32 offset, void *src, size_t size)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
        struct pci_dev *pci = to_pci_dev(sdev->dev);
        const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
        struct acp_dev_data *adata;
@@ -61,7 +60,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
        switch (blk_type) {
        case SOF_FW_BLK_TYPE_IRAM:
                if (!adata->bin_buf) {
-                       size_fw = plat_data->fw->size;
+                       size_fw = sdev->basefw.fw->size;
                        page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
                        dma_size = page_count * ACP_PAGE_SIZE;
                        adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
@@ -152,7 +151,6 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev
 int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
 {
        struct pci_dev *pci = to_pci_dev(sdev->dev);
-       struct snd_sof_pdata *plat_data = sdev->pdata;
        struct acp_dev_data *adata;
        unsigned int src_addr, size_fw;
        u32 page_count, dma_size;
@@ -186,7 +184,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
                dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
 
        /* Free memory once DMA is complete */
-       dma_size =  (PAGE_ALIGN(plat_data->fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
+       dma_size =  (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
        dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
        dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr);
        adata->bin_buf = NULL;
index 7af495f..36a0e2b 100644 (file)
@@ -277,7 +277,7 @@ if SND_SOC_SOF_HDA_COMMON
 
 config SND_SOC_SOF_HDA_LINK
        bool "SOF support for HDA Links(HDA/HDMI)"
-       depends on SND_SOC_SOF_NOCODEC=n
+       depends on SND_SOC_SOF_NOCODEC_SUPPORT=n
        select SND_SOC_SOF_PROBE_WORK_QUEUE
        help
          This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
index 8b8ea03..8201cbd 100644 (file)
@@ -5,7 +5,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o
 
 snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
                                 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
-                                hda-dai.o hda-bus.o \
+                                hda-dai.o hda-bus.o hda-mlink.o \
                                 skl.o hda-loader-skl.o \
                                 apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
 
index 1549ca7..0e7a7e4 100644 (file)
@@ -62,6 +62,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
 
                ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5;
 
+               /* External library loading support */
+               ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
                /* doorbell */
                sof_apl_ops.irq_thread  = hda_dsp_ipc4_irq_thread;
 
@@ -106,6 +109,7 @@ const struct sof_intel_dsp_desc apl_chip_info = {
        .rom_init_timeout       = 150,
        .ssp_count = APL_SSP_COUNT,
        .ssp_base_offset = APL_SSP_BASE_OFFSET,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
        .quirks = SOF_INTEL_PROCEN_FMT_QUIRK,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
index a446154..812a49b 100644 (file)
@@ -575,11 +575,7 @@ static struct snd_sof_dsp_ops sof_bdw_ops = {
        .run            = bdw_run,
        .reset          = bdw_reset,
 
-       /* Register IO */
-       .write          = sof_io_write,
-       .read           = sof_io_read,
-       .write64        = sof_io_write64,
-       .read64         = sof_io_read64,
+       /* Register IO uses direct mmio */
 
        /* Block IO */
        .block_read     = sof_block_read,
index e6dc4ff..faf223b 100644 (file)
@@ -225,11 +225,7 @@ static struct snd_sof_dsp_ops sof_byt_ops = {
        .run            = atom_run,
        .reset          = atom_reset,
 
-       /* Register IO */
-       .write          = sof_io_write,
-       .read           = sof_io_read,
-       .write64        = sof_io_write64,
-       .read64         = sof_io_read64,
+       /* Register IO uses direct mmio */
 
        /* Block IO */
        .block_read     = sof_block_read,
@@ -304,11 +300,7 @@ static struct snd_sof_dsp_ops sof_cht_ops = {
        .run            = atom_run,
        .reset          = atom_reset,
 
-       /* Register IO */
-       .write          = sof_io_write,
-       .read           = sof_io_read,
-       .write64        = sof_io_write64,
-       .read64         = sof_io_read64,
+       /* Register IO uses direct mmio */
 
        /* Block IO */
        .block_read     = sof_block_read,
index 19d0b19..6b075bb 100644 (file)
@@ -37,10 +37,12 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
 {
        struct sof_ipc4_msg notification_data = {{ 0 }};
        struct snd_sof_dev *sdev = context;
+       bool ack_received = false;
        bool ipc_irq = false;
        u32 hipcida, hipctdr;
 
        hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
+       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
        if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) {
                /* DSP received the message */
                snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
@@ -49,9 +51,9 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
                cnl_ipc_dsp_done(sdev);
 
                ipc_irq = true;
+               ack_received = true;
        }
 
-       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
        if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
                /* Message from DSP (reply or notification) */
                u32 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -70,6 +72,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
                                spin_lock_irq(&sdev->ipc_lock);
 
                                snd_sof_ipc_get_reply(sdev);
+                               cnl_ipc_host_done(sdev);
                                snd_sof_ipc_reply(sdev, data->primary);
 
                                spin_unlock_irq(&sdev->ipc_lock);
@@ -86,10 +89,10 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
                        sdev->ipc->msg.rx_data = &notification_data;
                        snd_sof_ipc_msgs_rx(sdev);
                        sdev->ipc->msg.rx_data = NULL;
-               }
 
-               /* Let DSP know that we have finished processing the message */
-               cnl_ipc_host_done(sdev);
+                       /* Let DSP know that we have finished processing the message */
+                       cnl_ipc_host_done(sdev);
+               }
 
                ipc_irq = true;
        }
@@ -98,6 +101,13 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
                /* This interrupt is not shared so no need to return IRQ_NONE. */
                dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
 
+       if (ack_received) {
+               struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+               if (hdev->delayed_ipc_tx_msg)
+                       cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -251,8 +261,16 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
 
 int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
 {
+       struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
        struct sof_ipc4_msg *msg_data = msg->msg_data;
 
+       if (hda_ipc4_tx_is_busy(sdev)) {
+               hdev->delayed_ipc_tx_msg = msg;
+               return 0;
+       }
+
+       hdev->delayed_ipc_tx_msg = NULL;
+
        /* send the message via mailbox */
        if (msg_data->data_size)
                sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -389,6 +407,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
 
                ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8;
 
+               /* External library loading support */
+               ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
                /* doorbell */
                sof_cnl_ops.irq_thread  = cnl_ipc4_irq_thread;
 
@@ -435,6 +456,9 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
@@ -467,6 +491,9 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
index 0862ff8..acb4b85 100644 (file)
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 #include "../../codecs/hdac_hda.h"
 #define sof_hda_ext_ops        snd_soc_hdac_hda_get_ops()
-#else
-#define sof_hda_ext_ops        NULL
-#endif
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power)
 {
        unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN);
@@ -70,11 +66,13 @@ static const struct hdac_bus_ops bus_core_ops = {
 /*
  * This can be used for both with/without hda link support.
  */
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
+void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
 {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
        snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
-#else /* CONFIG_SND_SOC_SOF_HDA */
+#else /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
        memset(bus, 0, sizeof(*bus));
        bus->dev = dev;
 
@@ -89,5 +87,14 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev)
        bus->idx = 0;
 
        spin_lock_init(&bus->reg_lock);
-#endif /* CONFIG_SND_SOC_SOF_HDA */
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
+}
+
+void sof_hda_bus_exit(struct snd_sof_dev *sdev)
+{
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       snd_hdac_ext_bus_exit(bus);
+#endif
 }
index f2ec2a6..8a5e99a 100644 (file)
@@ -1,7 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// This file is provided under a dual BSD/GPLv2 license.  When using or
-// redistributing this file, you may do so under either license.
+// SPDX-License-Identifier: GPL-2.0-only
 //
 // Copyright(c) 2018 Intel Corporation. All rights reserved.
 //
 #include <sound/sof.h>
 #include "../ops.h"
 #include "hda.h"
+
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 #include "../../codecs/hdac_hda.h"
-#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
 
 #define CODEC_PROBE_RETRIES    3
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 #define IDISP_VID_INTEL        0x80860000
 
+static int hda_codec_mask = -1;
+module_param_named(codec_mask, hda_codec_mask, int, 0444);
+MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
+
 /* load the legacy HDA codec driver */
 static int request_codec_module(struct hda_codec *codec)
 {
@@ -72,6 +72,10 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
        struct hda_codec *codec;
        unsigned int mask = 0;
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
        if (enable) {
                list_for_each_codec(codec, hbus)
                        if (codec->jacktbl.used)
@@ -80,6 +84,7 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
 
        snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
 }
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
 
 /* check jack status after resuming from suspend mode */
 void hda_codec_jack_check(struct snd_sof_dev *sdev)
@@ -87,6 +92,10 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
        struct hda_bus *hbus = sof_to_hbus(sdev);
        struct hda_codec *codec;
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
        list_for_each_codec(codec, hbus)
                /*
                 * Wake up all jack-detecting codecs regardless whether an event
@@ -95,12 +104,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
                if (codec->jacktbl.used)
                        pm_request_resume(&codec->core.dev);
 }
-#else
-void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) {}
-void hda_codec_jack_check(struct snd_sof_dev *sdev) {}
-#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
-EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
-EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
 
 #if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
 #define is_generic_config(bus) \
@@ -133,13 +137,9 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i
 }
 
 /* probe individual codec */
-static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
-                          bool hda_codec_use_common_hdmi)
+static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
 {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
        struct hdac_hda_priv *hda_priv;
-       int type = HDA_DEV_LEGACY;
-#endif
        struct hda_bus *hbus = sof_to_hbus(sdev);
        struct hda_codec *codec;
        u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
@@ -159,16 +159,11 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
        dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
                address, resp);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
        hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL);
        if (!hda_priv)
                return -ENOMEM;
 
-       /* only probe ASoC codec drivers for HDAC-HDMI */
-       if (!hda_codec_use_common_hdmi && (resp & 0xFFFF0000) == IDISP_VID_INTEL)
-               type = HDA_DEV_ASOC;
-
-       codec = hda_codec_device_init(&hbus->core, address, type);
+       codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_LEGACY);
        ret = PTR_ERR_OR_ZERO(codec);
        if (ret < 0)
                return ret;
@@ -191,43 +186,40 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
        else
                codec->probe_id = 0;
 
-       if (type == HDA_DEV_LEGACY) {
-               ret = hda_codec_load_module(codec);
-               /*
-                * handle ret==0 (no driver bound) as an error, but pass
-                * other return codes without modification
-                */
-               if (ret == 0)
-                       ret = -ENOENT;
-       }
+       ret = hda_codec_load_module(codec);
+       /*
+        * handle ret==0 (no driver bound) as an error, but pass
+        * other return codes without modification
+        */
+       if (ret == 0)
+               ret = -ENOENT;
 
 out:
        if (ret < 0) {
                snd_hdac_device_unregister(&codec->core);
                put_device(&codec->core.dev);
        }
-#else
-       codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_ASOC);
-       ret = PTR_ERR_OR_ZERO(codec);
-#endif
 
        return ret;
 }
 
 /* Codec initialization */
-void hda_codec_probe_bus(struct snd_sof_dev *sdev,
-                        bool hda_codec_use_common_hdmi)
+void hda_codec_probe_bus(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        int i, ret;
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
        /* probe codecs in avail slots */
        for (i = 0; i < HDA_MAX_CODECS; i++) {
 
                if (!(bus->codec_mask & (1 << i)))
                        continue;
 
-               ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi);
+               ret = hda_codec_probe(sdev, i);
                if (ret < 0) {
                        dev_warn(bus->dev, "codec #%d probe error, ret: %d\n",
                                 i, ret);
@@ -235,27 +227,193 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev,
                }
        }
 }
-EXPORT_SYMBOL_NS(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       unsigned int codec_mask;
+
+       codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+       if (codec_mask) {
+               hda_codec_jack_check(sdev);
+               snd_hdac_chip_writew(bus, STATESTS, codec_mask);
+       }
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_detect_mask(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* Accept unsolicited responses */
+       snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+
+       /* detect codecs */
+       if (!bus->codec_mask) {
+               bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+               dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+       }
+
+       if (hda_codec_mask != -1) {
+               bus->codec_mask &= hda_codec_mask;
+               dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
+                       bus->codec_mask);
+       }
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* initialize the codec command I/O */
+       snd_hdac_bus_init_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* set up CORB/RIRB buffers if was on before suspend */
+       if (bus->cmd_dma_state)
+               snd_hdac_bus_init_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* initialize the codec command I/O */
+       snd_hdac_bus_stop_cmd_io(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* stop the CORB/RIRB DMA if it is On */
+       if (bus->cmd_dma_state)
+               snd_hdac_bus_stop_cmd_io(bus);
+
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* clear rirb status */
+       snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       snd_hdac_set_codec_wakeup(bus, status);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       bool active = false;
+       u32 rirb_status;
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return false;
+
+       rirb_status = snd_hdac_chip_readb(bus, RIRBSTS);
+       if (rirb_status & RIRB_INT_MASK) {
+               /*
+                * Clearing the interrupt status here ensures
+                * that no interrupt gets masked after the RIRB
+                * wp is read in snd_hdac_bus_update_rirb.
+                */
+               snd_hdac_chip_writeb(bus, RIRBSTS,
+                                    RIRB_INT_MASK);
+               active = true;
+               if (rirb_status & RIRB_INT_RESPONSE)
+                       snd_hdac_bus_update_rirb(bus);
+       }
+       return active;
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+void hda_codec_device_remove(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
+       /* codec removal, invoke bus_device_remove */
+       snd_hdac_ext_bus_device_remove(bus);
+}
+EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC);
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
 
-#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \
-       IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
 
 void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return;
+
        if (HDA_IDISP_CODEC(bus->codec_mask)) {
                dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable);
                snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
        }
 }
-EXPORT_SYMBOL_NS(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
 
 int hda_codec_i915_init(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        int ret;
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return 0;
+
        /* i915 exposes a HDA codec for HDMI audio */
        ret = snd_hdac_i915_init(bus);
        if (ret < 0)
@@ -266,12 +424,16 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
 
        return 0;
 }
-EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
 
 int hda_codec_i915_exit(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
 
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+           sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+               return 0;
+
        if (!bus->audio_component)
                return 0;
 
@@ -280,7 +442,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
 
        return snd_hdac_i915_exit(bus);
 }
-EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
 
 #endif
 
index b232639..397303b 100644 (file)
@@ -19,11 +19,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
        .probe          = hda_dsp_probe,
        .remove         = hda_dsp_remove,
 
-       /* Register IO */
-       .write          = sof_io_write,
-       .read           = sof_io_read,
-       .write64        = sof_io_write64,
-       .read64         = sof_io_read64,
+       /* Register IO uses direct mmio */
 
        /* Block IO */
        .block_read     = sof_block_read,
index 0c29bb1..3aea36c 100644 (file)
 #include "../ops.h"
 #include "hda.h"
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-static int hda_codec_mask = -1;
-module_param_named(codec_mask, hda_codec_mask, int, 0444);
-MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
-#endif
-
 /*
  * HDA Operations.
  */
@@ -182,72 +176,40 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
        return 0;
 }
 
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_ext_link *hlink;
-#endif
        struct hdac_stream *stream;
        int sd_offset, ret = 0;
 
        if (bus->chip_init)
                return 0;
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       snd_hdac_set_codec_wakeup(bus, true);
-#endif
-       hda_dsp_ctrl_misc_clock_gating(sdev, false);
+       hda_codec_set_codec_wakeup(sdev, true);
 
-       if (full_reset) {
-               /* reset HDA controller */
-               ret = hda_dsp_ctrl_link_reset(sdev, true);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: failed to reset HDA controller\n");
-                       goto err;
-               }
-
-               usleep_range(500, 1000);
-
-               /* exit HDA controller reset */
-               ret = hda_dsp_ctrl_link_reset(sdev, false);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
-                       goto err;
-               }
-
-               usleep_range(1000, 1200);
-       }
+       hda_dsp_ctrl_misc_clock_gating(sdev, false);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* check to see if controller is ready */
-       if (!snd_hdac_chip_readb(bus, GCTL)) {
-               dev_dbg(bus->dev, "controller not ready!\n");
-               ret = -EBUSY;
+       /* reset HDA controller */
+       ret = hda_dsp_ctrl_link_reset(sdev, true);
+       if (ret < 0) {
+               dev_err(sdev->dev, "error: failed to reset HDA controller\n");
                goto err;
        }
 
-       /* Accept unsolicited responses */
-       snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
-       /* detect codecs */
-       if (!bus->codec_mask) {
-               bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
-               dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+       /* exit HDA controller reset */
+       ret = hda_dsp_ctrl_link_reset(sdev, false);
+       if (ret < 0) {
+               dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
+               goto err;
        }
 
-       if (hda_codec_mask != -1) {
-               bus->codec_mask &= hda_codec_mask;
-               dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
-                       bus->codec_mask);
-       }
-#endif
+       hda_codec_detect_mask(sdev);
 
        /* clear stream status */
        list_for_each_entry(stream, &bus->stream_list, list) {
                sd_offset = SOF_STREAM_SD_OFFSET(stream);
                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                                 sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+                                 sd_offset + SOF_HDA_ADSP_REG_SD_STS,
                                  SOF_HDA_CL_DMA_SD_INT_MASK);
        }
 
@@ -255,19 +217,13 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
                          SOF_HDA_WAKESTS_INT_MASK);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* clear rirb status */
-       snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
-#endif
+       hda_codec_rirb_status_clear(sdev);
 
        /* clear interrupt status register */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
                          SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* initialize the codec command I/O */
-       snd_hdac_bus_init_cmd_io(bus);
-#endif
+       hda_codec_init_cmd_io(sdev);
 
        /* enable CIE and GIE interrupts */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
@@ -282,19 +238,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
                                  upper_32_bits(bus->posbuf.addr));
        }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* Reset stream-to-link mapping */
-       list_for_each_entry(hlink, &bus->hlink_list, list)
-               writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
-#endif
+       hda_bus_ml_reset_losidv(bus);
 
        bus->chip_init = true;
 
 err:
        hda_dsp_ctrl_misc_clock_gating(sdev, true);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       snd_hdac_set_codec_wakeup(bus, false);
-#endif
+
+       hda_codec_set_codec_wakeup(sdev, false);
 
        return ret;
 }
@@ -313,7 +264,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
                sd_offset = SOF_STREAM_SD_OFFSET(stream);
                snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                        sd_offset +
-                                       SOF_HDA_ADSP_REG_CL_SD_CTL,
+                                       SOF_HDA_ADSP_REG_SD_CTL,
                                        SOF_HDA_CL_DMA_SD_INT_MASK,
                                        0);
        }
@@ -331,7 +282,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
        list_for_each_entry(stream, &bus->stream_list, list) {
                sd_offset = SOF_STREAM_SD_OFFSET(stream);
                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                                 sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+                                 sd_offset + SOF_HDA_ADSP_REG_SD_STS,
                                  SOF_HDA_CL_DMA_SD_INT_MASK);
        }
 
@@ -339,19 +290,14 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
                          SOF_HDA_WAKESTS_INT_MASK);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* clear rirb status */
-       snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
-#endif
+       hda_codec_rirb_status_clear(sdev);
 
        /* clear interrupt status register */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
                          SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* disable CORB/RIRB */
-       snd_hdac_bus_stop_cmd_io(bus);
-#endif
+       hda_codec_stop_cmd_io(sdev);
+
        /* disable position buffer */
        if (bus->use_posbuf && bus->posbuf.addr) {
                snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
index 556e883..1c3d488 100644 (file)
@@ -27,16 +27,13 @@ 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");
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 
 struct hda_pipe_params {
        u32 ch;
        u32 s_freq;
-       u32 s_fmt;
-       u8 linktype;
        snd_pcm_format_t format;
        int link_index;
-       int stream;
        unsigned int link_bps;
 };
 
@@ -138,27 +135,27 @@ hda_link_stream_assign(struct hdac_bus *bus,
 }
 
 static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
-                               struct hdac_stream *hstream,
+                               struct hdac_ext_stream *hext_stream,
                                struct snd_soc_dai *cpu_dai,
                                struct snd_soc_dai *codec_dai,
                                bool trigger_suspend_stop)
 {
-       struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       struct hdac_stream *hstream = &hext_stream->hstream;
        struct hdac_bus *bus = hstream->bus;
        struct sof_intel_hda_stream *hda_stream;
-       struct hdac_ext_link *link;
+       struct hdac_ext_link *hlink;
        int stream_tag;
 
-       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
-       if (!link)
+       hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+       if (!hlink)
                return -EINVAL;
 
        if (trigger_suspend_stop)
-               snd_hdac_ext_link_stream_clear(hext_stream);
+               snd_hdac_ext_stream_clear(hext_stream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                stream_tag = hdac_stream(hext_stream)->stream_tag;
-               snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+               snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
        }
        snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
        snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
@@ -177,10 +174,10 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
        struct hdac_stream *hstream = &hext_stream->hstream;
        unsigned char stream_tag = hstream->stream_tag;
        struct hdac_bus *bus = hstream->bus;
-       struct hdac_ext_link *link;
+       struct hdac_ext_link *hlink;
        unsigned int format_val;
 
-       snd_hdac_ext_link_stream_reset(hext_stream);
+       snd_hdac_ext_stream_reset(hext_stream);
 
        format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
                                                 params->format,
@@ -189,13 +186,13 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
        dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
                format_val, params->s_freq, params->ch, params->format);
 
-       snd_hdac_ext_link_stream_setup(hext_stream, format_val);
+       snd_hdac_ext_stream_setup(hext_stream, format_val);
 
        if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
-               list_for_each_entry(link, &bus->hlink_list, list) {
-                       if (link->index == params->link_index)
-                               snd_hdac_ext_link_set_stream_id(link,
-                                                               stream_tag);
+               list_for_each_entry(hlink, &bus->hlink_list, list) {
+                       if (hlink->index == params->link_index)
+                               snd_hdac_ext_bus_link_set_stream_id(hlink,
+                                                                   stream_tag);
                }
        }
 
@@ -207,14 +204,17 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
 static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params)
 {
-       struct hdac_stream *hstream = substream->runtime->private_data;
-       struct hdac_ext_stream *hext_stream;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        struct hda_pipe_params p_params = {0};
-       struct hdac_bus *bus = hstream->bus;
-       struct hdac_ext_link *link;
+       struct hdac_ext_stream *hext_stream;
+       struct hdac_ext_link *hlink;
+       struct snd_sof_dev *sdev;
+       struct hdac_bus *bus;
+
+       sdev = snd_soc_component_get_drvdata(cpu_dai->component);
+       bus = sof_to_bus(sdev);
 
        hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
        if (!hext_stream) {
@@ -225,18 +225,16 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
                snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
        }
 
-       link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
-       if (!link)
+       hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
+       if (!hlink)
                return -EINVAL;
 
        /* set the hdac_stream in the codec dai */
        snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);
 
-       p_params.s_fmt = snd_pcm_format_width(params_format(params));
        p_params.ch = params_channels(params);
        p_params.s_freq = params_rate(params);
-       p_params.stream = substream->stream;
-       p_params.link_index = link->index;
+       p_params.link_index = hlink->index;
        p_params.format = params_format(params);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -257,7 +255,6 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
 
 static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct hdac_stream *hstream = substream->runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -270,17 +267,17 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               snd_hdac_ext_link_stream_start(hext_stream);
+               snd_hdac_ext_stream_start(hext_stream);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
-               ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, true);
+               ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, true);
                if (ret < 0)
                        return ret;
 
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               snd_hdac_ext_link_stream_clear(hext_stream);
+               snd_hdac_ext_stream_clear(hext_stream);
 
                break;
        default:
@@ -291,7 +288,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 
 static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
 {
-       struct hdac_stream *hstream = substream->runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -301,7 +297,7 @@ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
        if (!hext_stream)
                return 0;
 
-       return hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+       return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
 }
 
 static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
@@ -458,14 +454,12 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
        struct snd_sof_widget *swidget;
        struct snd_soc_dapm_widget *w;
        struct snd_soc_dai *codec_dai;
-       struct hdac_stream *hstream;
        struct snd_soc_dai *cpu_dai;
        int ret;
 
        dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
                dai->name, substream->stream);
 
-       hstream = substream->runtime->private_data;
        rtd = asoc_substream_to_rtd(substream);
        cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        codec_dai = asoc_rtd_to_codec(rtd, 0);
@@ -476,7 +470,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               snd_hdac_ext_link_stream_start(hext_stream);
+               snd_hdac_ext_stream_start(hext_stream);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
@@ -484,23 +478,23 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
                struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
                struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_PAUSED);
                if (ret < 0)
                        return ret;
 
                pipeline->state = SOF_IPC4_PIPE_PAUSED;
 
-               snd_hdac_ext_link_stream_clear(hext_stream);
+               snd_hdac_ext_stream_clear(hext_stream);
 
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_RESET);
                if (ret < 0)
                        return ret;
 
                pipeline->state = SOF_IPC4_PIPE_RESET;
 
-               ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+               ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
                if (ret < 0) {
                        dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
                        return ret;
@@ -512,14 +506,14 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
                struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
                struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_PAUSED);
                if (ret < 0)
                        return ret;
 
                pipeline->state = SOF_IPC4_PIPE_PAUSED;
 
-               snd_hdac_ext_link_stream_clear(hext_stream);
+               snd_hdac_ext_stream_clear(hext_stream);
                break;
        }
        default:
@@ -575,7 +569,8 @@ static int hda_dai_suspend(struct hdac_bus *bus)
                        cpu_dai = asoc_rtd_to_cpu(rtd, 0);
                        codec_dai = asoc_rtd_to_codec(rtd, 0);
 
-                       ret = hda_link_dma_cleanup(hext_stream->link_substream, s,
+                       ret = hda_link_dma_cleanup(hext_stream->link_substream,
+                                                  hext_stream,
                                                   cpu_dai, codec_dai, false);
                        if (ret < 0)
                                return ret;
@@ -726,20 +721,20 @@ static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stre
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_PAUSED);
                if (ret < 0)
                        return ret;
                pipeline->state = SOF_IPC4_PIPE_PAUSED;
 
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_RESET);
                if (ret < 0)
                        return ret;
                pipeline->state = SOF_IPC4_PIPE_RESET;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+               ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_PAUSED);
                if (ret < 0)
                        return ret;
@@ -777,7 +772,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
                                ops->drv[i].ops = &ipc3_ssp_dai_ops;
                                continue;
                        }
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
                        if (strstr(ops->drv[i].name, "iDisp") ||
                            strstr(ops->drv[i].name, "Analog") ||
                            strstr(ops->drv[i].name, "Digital"))
@@ -798,7 +793,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
                                ops->drv[i].ops = &ipc4_ssp_dai_ops;
                                continue;
                        }
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
                        if (strstr(ops->drv[i].name, "iDisp") ||
                            strstr(ops->drv[i].name, "Analog") ||
                            strstr(ops->drv[i].name, "Digital"))
@@ -916,7 +911,7 @@ struct snd_soc_dai_driver skl_dai[] = {
                .channels_max = 4,
        },
 },
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 {
        .name = "iDisp1 Pin",
        .playback = {
@@ -989,7 +984,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
         * Since the component suspend is called last, we can trap this corner case
         * and force the DAIs to release their resources.
         */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
        int ret;
 
        ret = hda_dai_suspend(sof_to_bus(sdev));
index 3c76f84..5fa29df 100644 (file)
@@ -347,10 +347,13 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
 
 static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev)
 {
-       struct hdac_bus *bus = sof_to_bus(sdev);
        int retry = HDA_DSP_REG_POLL_RETRY_COUNT;
+       struct snd_sof_pdata *pdata = sdev->pdata;
+       const struct sof_intel_dsp_desc *chip;
 
-       while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) {
+       chip = get_chip_info(pdata);
+       while (snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset) &
+               SOF_HDA_VS_D0I3C_CIP) {
                if (!retry--)
                        return -ETIMEDOUT;
                usleep_range(10, 15);
@@ -378,27 +381,33 @@ static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags)
 
 static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value)
 {
-       struct hdac_bus *bus = sof_to_bus(sdev);
+       struct snd_sof_pdata *pdata = sdev->pdata;
+       const struct sof_intel_dsp_desc *chip;
        int ret;
+       u8 reg;
+
+       chip = get_chip_info(pdata);
 
        /* Write to D0I3C after Command-In-Progress bit is cleared */
        ret = hda_dsp_wait_d0i3c_done(sdev);
        if (ret < 0) {
-               dev_err(bus->dev, "CIP timeout before D0I3C update!\n");
+               dev_err(sdev->dev, "CIP timeout before D0I3C update!\n");
                return ret;
        }
 
        /* Update D0I3C register */
-       snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value);
+       snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset,
+                           SOF_HDA_VS_D0I3C_I3, value);
 
        /* Wait for cmd in progress to be cleared before exiting the function */
        ret = hda_dsp_wait_d0i3c_done(sdev);
        if (ret < 0) {
-               dev_err(bus->dev, "CIP timeout after D0I3C update!\n");
+               dev_err(sdev->dev, "CIP timeout after D0I3C update!\n");
                return ret;
        }
 
-       trace_sof_intel_D0I3C_updated(sdev, snd_hdac_chip_readb(bus, VS_D0I3C));
+       reg = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset);
+       trace_sof_intel_D0I3C_updated(sdev, reg);
 
        return 0;
 }
@@ -612,9 +621,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
 {
        struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        const struct sof_intel_dsp_desc *chip = hda->desc;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
        struct hdac_bus *bus = sof_to_bus(sdev);
-#endif
        int ret, j;
 
        /*
@@ -633,12 +640,10 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
        if (ret < 0)
                return ret;
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
        hda_codec_jack_wake_enable(sdev, runtime_suspend);
 
-       /* power down all hda link */
-       snd_hdac_ext_bus_link_power_down_all(bus);
-#endif
+       /* power down all hda links */
+       hda_bus_ml_suspend(bus);
 
        ret = chip->power_down_dsp(sdev);
        if (ret < 0) {
@@ -677,10 +682,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
 
 static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
 {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_bus *bus = sof_to_bus(sdev);
-       struct hdac_ext_link *hlink = NULL;
-#endif
        int ret;
 
        /* display codec must be powered before link reset */
@@ -693,14 +694,13 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
        snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
 
        /* reset and start hda controller */
-       ret = hda_dsp_ctrl_init_chip(sdev, true);
+       ret = hda_dsp_ctrl_init_chip(sdev);
        if (ret < 0) {
                dev_err(sdev->dev,
                        "error: failed to start controller after resume\n");
                goto cleanup;
        }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
        /* check jack status */
        if (runtime_resume) {
                hda_codec_jack_wake_enable(sdev, false);
@@ -708,17 +708,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
                        hda_codec_jack_check(sdev);
        }
 
-       /* turn off the links that were off before suspend */
-       list_for_each_entry(hlink, &bus->hlink_list, list) {
-               if (!hlink->ref_count)
-                       snd_hdac_ext_bus_link_power_down(hlink);
-       }
-
-       /* check dma status and clean up CORB/RIRB buffers */
-       if (!bus->cmd_dma_state)
-               snd_hdac_bus_stop_cmd_io(bus);
-#endif
-
        /* enable ppcap interrupt */
        hda_dsp_ctrl_ppcap_enable(sdev, true);
        hda_dsp_ctrl_ppcap_int_enable(sdev, true);
@@ -733,37 +722,26 @@ cleanup:
 int hda_dsp_resume(struct snd_sof_dev *sdev)
 {
        struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       struct hdac_bus *bus = sof_to_bus(sdev);
        struct pci_dev *pci = to_pci_dev(sdev->dev);
        const struct sof_dsp_power_state target_state = {
                .state = SOF_DSP_PM_D0,
                .substate = SOF_HDA_DSP_PM_D0I0,
        };
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_bus *bus = sof_to_bus(sdev);
-       struct hdac_ext_link *hlink = NULL;
-#endif
        int ret;
 
        /* resume from D0I3 */
        if (sdev->dsp_power_state.state == SOF_DSP_PM_D0) {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-               /* power up links that were active before suspend */
-               list_for_each_entry(hlink, &bus->hlink_list, list) {
-                       if (hlink->ref_count) {
-                               ret = snd_hdac_ext_bus_link_power_up(hlink);
-                               if (ret < 0) {
-                                       dev_err(sdev->dev,
-                                               "error %d in %s: failed to power up links",
-                                               ret, __func__);
-                                       return ret;
-                               }
-                       }
+               ret = hda_bus_ml_resume(bus);
+               if (ret < 0) {
+                       dev_err(sdev->dev,
+                               "error %d in %s: failed to power up links",
+                               ret, __func__);
+                       return ret;
                }
 
                /* set up CORB/RIRB buffers if was on before suspend */
-               if (bus->cmd_dma_state)
-                       snd_hdac_bus_init_cmd_io(bus);
-#endif
+               hda_codec_resume_cmd_io(sdev);
 
                /* Set DSP power state */
                ret = snd_sof_dsp_set_power_state(sdev, &target_state);
@@ -872,20 +850,17 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
                                                HDA_VS_INTEL_EM2_L1SEN,
                                                HDA_VS_INTEL_EM2_L1SEN);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
                /* stop the CORB/RIRB DMA if it is On */
-               if (bus->cmd_dma_state)
-                       snd_hdac_bus_stop_cmd_io(bus);
+               hda_codec_suspend_cmd_io(sdev);
 
                /* no link can be powered in s0ix state */
-               ret = snd_hdac_ext_bus_link_power_down_all(bus);
+               ret = hda_bus_ml_suspend(bus);
                if (ret < 0) {
                        dev_err(sdev->dev,
                                "error %d in %s: failed to power down links",
                                ret, __func__);
                        return ret;
                }
-#endif
 
                /* enable the system waking up via IPC IRQ */
                enable_irq_wake(pci->irq);
index 9b3667c..a7c454e 100644 (file)
@@ -69,8 +69,16 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
 
 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
 {
+       struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
        struct sof_ipc4_msg *msg_data = msg->msg_data;
 
+       if (hda_ipc4_tx_is_busy(sdev)) {
+               hdev->delayed_ipc_tx_msg = msg;
+               return 0;
+       }
+
+       hdev->delayed_ipc_tx_msg = NULL;
+
        /* send the message via mailbox */
        if (msg_data->data_size)
                sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -122,10 +130,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
 {
        struct sof_ipc4_msg notification_data = {{ 0 }};
        struct snd_sof_dev *sdev = context;
+       bool ack_received = false;
        bool ipc_irq = false;
        u32 hipcie, hipct;
 
        hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+       hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+
        if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
                /* DSP received the message */
                snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
@@ -133,9 +144,9 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
                hda_dsp_ipc_dsp_done(sdev);
 
                ipc_irq = true;
+               ack_received = true;
        }
 
-       hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
        if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
                /* Message from DSP (reply or notification) */
                u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -158,6 +169,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
                                spin_lock_irq(&sdev->ipc_lock);
 
                                snd_sof_ipc_get_reply(sdev);
+                               hda_dsp_ipc_host_done(sdev);
                                snd_sof_ipc_reply(sdev, data->primary);
 
                                spin_unlock_irq(&sdev->ipc_lock);
@@ -174,10 +186,10 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
                        sdev->ipc->msg.rx_data = &notification_data;
                        snd_sof_ipc_msgs_rx(sdev);
                        sdev->ipc->msg.rx_data = NULL;
-               }
 
-               /* Let DSP know that we have finished processing the message */
-               hda_dsp_ipc_host_done(sdev);
+                       /* Let DSP know that we have finished processing the message */
+                       hda_dsp_ipc_host_done(sdev);
+               }
 
                ipc_irq = true;
        }
@@ -186,6 +198,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
                /* This interrupt is not shared so no need to return IRQ_NONE. */
                dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
 
+       if (ack_received) {
+               struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+               if (hdev->delayed_ipc_tx_msg)
+                       hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+       }
+
        return IRQ_HANDLED;
 }
 
index 0193fb3..69fdef8 100644 (file)
@@ -141,7 +141,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable)
        u32 run = enable ? 0x1 : 0;
 
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
                                HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run));
 
        retries = 300;
@@ -150,7 +150,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable)
 
                /* waiting for hardware to report the stream Run bit set */
                val = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                      sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL);
+                                      sd_offset + SOF_HDA_ADSP_REG_SD_CTL);
                val &= HDA_CL_SD_CTL_RUN(1);
                if (enable && val)
                        break;
@@ -174,23 +174,23 @@ static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev)
         * Descriptor Error Interrupt and set the cldma stream number to 0.
         */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
                                HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0));
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
                                HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0));
 
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, HDA_CL_SD_BDLPLBA(0));
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(0));
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
 
        /* Set the Cyclic Buffer Length to 0. */
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_CBL, 0);
        /* Set the Last Valid Index. */
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0);
 }
 
 static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev,
@@ -240,27 +240,27 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev,
 
        /* setting the stream register */
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
                          HDA_CL_SD_BDLPLBA(dmab_bdl->addr));
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
                          HDA_CL_SD_BDLPUBA(dmab_bdl->addr));
 
        /* Set the Cyclic Buffer Length. */
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_CBL, max_size);
        /* Set the Last Valid Index. */
        snd_sof_dsp_write(sdev, HDA_DSP_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_LVI, count - 1);
 
        /* Set the Interrupt On Completion, FIFO Error Interrupt,
         * Descriptor Error Interrupt and the cldma stream number.
         */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
                                HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1));
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_CTL,
                                HDA_CL_SD_CTL_STRM(0xf),
                                HDA_CL_SD_CTL_STRM(1));
 }
@@ -439,7 +439,7 @@ static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev,
 
        /* now check DMA interrupt status */
        cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                             sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS);
+                                             sd_offset + SOF_HDA_ADSP_REG_SD_STS);
 
        if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) {
                dev_err(sdev->dev, "cldma copy failed\n");
@@ -494,14 +494,13 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev,
                          struct snd_dma_buffer *dmab)
 
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
-       const struct firmware *fw =  plat_data->fw;
+       const struct firmware *fw =  sdev->basefw.fw;
        struct firmware stripped_firmware;
        unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;
        int ret;
 
-       stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
-       stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+       stripped_firmware.data = fw->data + sdev->basefw.payload_offset;
+       stripped_firmware.size = fw->size - sdev->basefw.payload_offset;
 
        dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize);
 
index 98812d5..d680562 100644 (file)
@@ -19,7 +19,9 @@
 #include <sound/hdaudio_ext.h>
 #include <sound/hda_register.h>
 #include <sound/sof.h>
+#include <sound/sof/ipc4/header.h>
 #include "ext_manifest.h"
+#include "../ipc4-priv.h"
 #include "../ops.h"
 #include "../sof-priv.h"
 #include "hda.h"
@@ -263,9 +265,9 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
 
        /* reset BDL address */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0);
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
 
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
        snd_dma_free_pages(dmab);
@@ -318,10 +320,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
 
 int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
        struct hdac_ext_stream *iccmax_stream;
        struct hdac_bus *bus = sof_to_bus(sdev);
-       struct firmware stripped_firmware;
        struct snd_dma_buffer dmab_bdl;
        int ret, ret1;
        u8 original_gb;
@@ -329,15 +329,11 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
        /* save the original LTRP guardband value */
        original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK;
 
-       if (plat_data->fw->size <= plat_data->fw_offset) {
-               dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
-               return -EINVAL;
-       }
-
-       stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
-
-       /* prepare capture stream for ICCMAX */
-       iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
+       /*
+        * Prepare capture stream for ICCMAX. We do not need to store
+        * the data, so use a buffer of PAGE_SIZE for receiving.
+        */
+       iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
                                              &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
        if (IS_ERR(iccmax_stream)) {
                dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
@@ -397,21 +393,25 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
                dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
                hda->boot_iteration = 0;
                ret = hda_dsp_boot_imr(sdev);
-               if (!ret)
+               if (!ret) {
+                       hda->booted_from_imr = true;
                        return 0;
+               }
 
                dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
        }
 
+       hda->booted_from_imr = false;
+
        chip_info = desc->chip_info;
 
-       if (plat_data->fw->size <= plat_data->fw_offset) {
+       if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) {
                dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
                return -EINVAL;
        }
 
-       stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset;
-       stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
+       stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
+       stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
 
        /* init for booting wait */
        init_waitqueue_head(&sdev->boot_wait);
@@ -515,6 +515,70 @@ cleanup:
        return ret;
 }
 
+int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
+                             struct sof_ipc4_fw_library *fw_lib, bool reload)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       struct hdac_ext_stream *hext_stream;
+       struct firmware stripped_firmware;
+       struct sof_ipc4_msg msg = {};
+       struct snd_dma_buffer dmab;
+       int ret, ret1;
+
+       /* IMR booting will restore the libraries as well, skip the loading */
+       if (reload && hda->booted_from_imr)
+               return 0;
+
+       /* the fw_lib has been verified during loading, we can trust the validity here */
+       stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
+       stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;
+
+       /* prepare DMA for code loader stream */
+       hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
+                                           stripped_firmware.size,
+                                           &dmab, SNDRV_PCM_STREAM_PLAYBACK);
+       if (IS_ERR(hext_stream)) {
+               dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
+               return PTR_ERR(hext_stream);
+       }
+
+       memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size);
+
+       msg.primary = hext_stream->hstream.stream_tag - 1;
+       msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+       msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);
+
+       ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
+       if (ret < 0) {
+               dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
+               goto cleanup;
+       }
+
+       ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+
+       ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
+       if (ret1 < 0) {
+               dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
+               if (!ret)
+                       ret = ret1;
+       }
+
+cleanup:
+       /* clean up even in case of error and return the first error */
+       ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
+       if (ret1 < 0) {
+               dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
+
+               /* set return value to indicate cleanup failure */
+               if (!ret)
+                       ret = ret1;
+       }
+
+       return ret;
+}
+
 /* pre fw run operations */
 int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
 {
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
new file mode 100644 (file)
index 0000000..76ab9a2
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+
+/*
+ * Management of HDaudio multi-link (capabilities, power, coupling)
+ */
+
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_register.h>
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/intel-dsp-config.h>
+#include <sound/intel-nhlt.h>
+#include <sound/sof.h>
+#include <sound/sof/xtensa.h>
+#include "../sof-audio.h"
+#include "../sof-pci-dev.h"
+#include "../ops.h"
+#include "hda.h"
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+
+void hda_bus_ml_get_capabilities(struct hdac_bus *bus)
+{
+       if (bus->mlcap)
+               snd_hdac_ext_bus_get_ml_capabilities(bus);
+}
+
+void hda_bus_ml_free(struct hdac_bus *bus)
+{
+       struct hdac_ext_link *hlink;
+
+       if (!bus->mlcap)
+               return;
+
+       while (!list_empty(&bus->hlink_list)) {
+               hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
+               list_del(&hlink->list);
+               kfree(hlink);
+       }
+}
+
+void hda_bus_ml_put_all(struct hdac_bus *bus)
+{
+       struct hdac_ext_link *hlink;
+
+       list_for_each_entry(hlink, &bus->hlink_list, list)
+               snd_hdac_ext_bus_link_put(bus, hlink);
+}
+
+void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
+{
+       struct hdac_ext_link *hlink;
+
+       /* Reset stream-to-link mapping */
+       list_for_each_entry(hlink, &bus->hlink_list, list)
+               writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
+}
+
+int hda_bus_ml_resume(struct hdac_bus *bus)
+{
+       struct hdac_ext_link *hlink;
+       int ret;
+
+       /* power up links that were active before suspend */
+       list_for_each_entry(hlink, &bus->hlink_list, list) {
+               if (hlink->ref_count) {
+                       ret = snd_hdac_ext_bus_link_power_up(hlink);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+int hda_bus_ml_suspend(struct hdac_bus *bus)
+{
+       return snd_hdac_ext_bus_link_power_down_all(bus);
+}
+
+#endif
index 0a9c802..dc0b359 100644 (file)
@@ -142,7 +142,6 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
 int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
 {
        struct hdac_stream *hstream = substream->runtime->private_data;
-       struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        ssize_t appl_pos, buf_size;
        u32 spib;
@@ -156,7 +155,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea
        if (!spib)
                spib = buf_size;
 
-       sof_io_write(sdev, hext_stream->spib_addr, spib);
+       sof_io_write(sdev, hstream->spib_addr, spib);
 
        return 0;
 }
index be60e77..7f0fd05 100644 (file)
@@ -173,7 +173,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
                                enable << hstream->index);
 
        /* set the SPIB value */
-       sof_io_write(sdev, hext_stream->spib_addr, size);
+       sof_io_write(sdev, hstream->spib_addr, size);
 
        return 0;
 }
@@ -367,7 +367,7 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
 
                if (ret >= 0) {
                        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+                                         sd_offset + SOF_HDA_ADSP_REG_SD_STS,
                                          SOF_HDA_CL_DMA_SD_INT_MASK);
 
                        hstream->running = false;
@@ -398,7 +398,6 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
                                    struct snd_dma_buffer *dmab,
                                    struct snd_pcm_hw_params *params)
 {
-       struct hdac_bus *bus = sof_to_bus(sdev);
        struct hdac_stream *hstream = &hext_stream->hstream;
        int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
        int ret;
@@ -419,10 +418,10 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
 
        /* reset BDL address */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
                          0x0);
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
                          0x0);
 
        hstream->frags = 0;
@@ -435,20 +434,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
 
        /* program BDL address */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
                          (u32)hstream->bdl.addr);
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
                          upper_32_bits(hstream->bdl.addr));
 
        /* program cyclic buffer length */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_CBL,
                          hstream->bufsize);
 
        /* program last valid index */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_LVI,
                                0xffff, (hstream->frags - 1));
 
        /* decouple host and link DMA, enable DSP features */
@@ -456,7 +455,8 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
                                mask, mask);
 
        /* Follow HW recommendation to set the guardband value to 95us during FW boot */
-       snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US);
+       snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_LTRP,
+                           HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US);
 
        /* start DMA */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
@@ -520,7 +520,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
        }
 
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_STS,
                                SOF_HDA_CL_DMA_SD_INT_MASK,
                                SOF_HDA_CL_DMA_SD_INT_MASK);
 
@@ -534,10 +534,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
 
        /* reset BDL address */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
                          0x0);
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
                          0x0);
 
        /* clear stream status */
@@ -562,7 +562,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
        }
 
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_STS,
                                SOF_HDA_CL_DMA_SD_INT_MASK,
                                SOF_HDA_CL_DMA_SD_INT_MASK);
 
@@ -582,7 +582,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
 
        /* program cyclic buffer length */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_CBL,
                          hstream->bufsize);
 
        /*
@@ -606,7 +606,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
        /* program stream format */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                sd_offset +
-                               SOF_HDA_ADSP_REG_CL_SD_FORMAT,
+                               SOF_HDA_ADSP_REG_SD_FORMAT,
                                0xffff, hstream->format_val);
 
        if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) {
@@ -617,15 +617,15 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
 
        /* program last valid index */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
-                               sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI,
+                               sd_offset + SOF_HDA_ADSP_REG_SD_LVI,
                                0xffff, (hstream->frags - 1));
 
        /* program BDL address */
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL,
                          (u32)hstream->bdl.addr);
        snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
-                         sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
+                         sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU,
                          upper_32_bits(hstream->bdl.addr));
 
        /* enable position buffer, if needed */
@@ -649,7 +649,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
                hstream->fifo_size =
                        snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
                                         sd_offset +
-                                        SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE);
+                                        SOF_HDA_ADSP_REG_SD_FIFOSIZE);
                hstream->fifo_size &= 0xffff;
                hstream->fifo_size += 1;
        } else {
@@ -697,7 +697,8 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
        /* The function can be called at irq thread, so use spin_lock_irq */
        spin_lock_irq(&bus->reg_lock);
 
-       status = snd_hdac_chip_readl(bus, INTSTS);
+       status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
+
        trace_sof_intel_hda_dsp_check_stream_irq(sdev, status);
 
        /* if Register inaccessible, ignore it.*/
@@ -735,11 +736,11 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
 
        list_for_each_entry(s, &bus->stream_list, list) {
                if (status & BIT(s->index) && s->opened) {
-                       sd_status = snd_hdac_stream_readb(s, SD_STS);
+                       sd_status = readb(s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
 
                        trace_sof_intel_hda_dsp_stream_status(bus->dev, s, sd_status);
 
-                       snd_hdac_stream_writeb(s, SD_STS, sd_status);
+                       writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
 
                        active = true;
                        if ((!s->substream && !s->cstream) ||
@@ -764,9 +765,6 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
 {
        struct snd_sof_dev *sdev = context;
        struct hdac_bus *bus = sof_to_bus(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       u32 rirb_status;
-#endif
        bool active;
        u32 status;
        int i;
@@ -778,29 +776,15 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
        for (i = 0, active = true; i < 10 && active; i++) {
                spin_lock_irq(&bus->reg_lock);
 
-               status = snd_hdac_chip_readl(bus, INTSTS);
+               status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
 
                /* check streams */
                active = hda_dsp_stream_check(bus, status);
 
                /* check and clear RIRB interrupt */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
                if (status & AZX_INT_CTRL_EN) {
-                       rirb_status = snd_hdac_chip_readb(bus, RIRBSTS);
-                       if (rirb_status & RIRB_INT_MASK) {
-                               /*
-                                * Clearing the interrupt status here ensures
-                                * that no interrupt gets masked after the RIRB
-                                * wp is read in snd_hdac_bus_update_rirb.
-                                */
-                               snd_hdac_chip_writeb(bus, RIRBSTS,
-                                                    RIRB_INT_MASK);
-                               active = true;
-                               if (rirb_status & RIRB_INT_RESPONSE)
-                                       snd_hdac_bus_update_rirb(bus);
-                       }
+                       active |= hda_codec_check_rirb_status(sdev);
                }
-#endif
                spin_unlock_irq(&bus->reg_lock);
        }
 
@@ -853,15 +837,16 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
                return -ENOMEM;
        }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* mem alloc for the CORB/RIRB ringbuffers */
+       /*
+        * mem alloc for the CORB/RIRB ringbuffers - this will be used only for
+        * HDAudio codecs
+        */
        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
                                  PAGE_SIZE, &bus->rb);
        if (ret < 0) {
                dev_err(sdev->dev, "error: RB alloc failed\n");
                return -ENOMEM;
        }
-#endif
 
        /* create capture streams */
        for (i = 0; i < num_capture; i++) {
@@ -883,18 +868,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
                        SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
                        SOF_HDA_PPLC_INTERVAL * i;
 
+               hstream = &hext_stream->hstream;
+
                /* do we support SPIB */
                if (sdev->bar[HDA_DSP_SPIB_BAR]) {
-                       hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+                       hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
                                SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
                                SOF_HDA_SPIB_SPIB;
 
-                       hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+                       hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
                                SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
                                SOF_HDA_SPIB_MAXFIFO;
                }
 
-               hstream = &hext_stream->hstream;
                hstream->bus = bus;
                hstream->sd_int_sta_mask = 1 << i;
                hstream->index = i;
@@ -939,18 +925,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
                        SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
                        SOF_HDA_PPLC_INTERVAL * i;
 
+               hstream = &hext_stream->hstream;
+
                /* do we support SPIB */
                if (sdev->bar[HDA_DSP_SPIB_BAR]) {
-                       hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+                       hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
                                SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
                                SOF_HDA_SPIB_SPIB;
 
-                       hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
+                       hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
                                SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
                                SOF_HDA_SPIB_MAXFIFO;
                }
 
-               hstream = &hext_stream->hstream;
                hstream->bus = bus;
                hstream->sd_int_sta_mask = 1 << i;
                hstream->index = i;
@@ -992,11 +979,9 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
        if (bus->posbuf.area)
                snd_dma_free_pages(&bus->posbuf);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* free position buffer */
+       /* free CORB/RIRB buffer - only used for HDaudio codecs */
        if (bus->rb.area)
                snd_dma_free_pages(&bus->rb);
-#endif
 
        list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
                /* TODO: decouple */
index 1188ec5..14a2f87 100644 (file)
@@ -155,9 +155,27 @@ struct sdw_intel_ops sdw_callback = {
        .free_stream = sdw_free_stream,
 };
 
+void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+       struct sof_intel_hda_dev *hdev;
+
+       hdev = sdev->pdata->hw_pdata;
+
+       if (!hdev->sdw)
+               return;
+
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
+                               HDA_DSP_REG_ADSPIC2_SNDW,
+                               enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
+}
+
 void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
 {
-       sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable);
+       const struct sof_intel_dsp_desc *chip;
+
+       chip = get_chip_info(sdev->pdata);
+       if (chip && chip->enable_sdw_irq)
+               chip->enable_sdw_irq(sdev, enable);
 }
 
 static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
@@ -220,10 +238,45 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
        return 0;
 }
 
+int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
+{
+       struct sof_intel_hda_dev *hdev;
+       struct sdw_intel_ctx *ctx;
+       u32 caps;
+
+       hdev = sdev->pdata->hw_pdata;
+       ctx = hdev->sdw;
+
+       caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
+       caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
+
+       /* Check HW supported vs property value */
+       if (caps < ctx->count) {
+               dev_err(sdev->dev,
+                       "BIOS master count %d is larger than hardware capabilities %d\n",
+                       ctx->count, caps);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
+{
+       const struct sof_intel_dsp_desc *chip;
+
+       chip = get_chip_info(sdev->pdata);
+       if (chip && chip->read_sdw_lcount)
+               return chip->read_sdw_lcount(sdev);
+
+       return 0;
+}
+
 int hda_sdw_startup(struct snd_sof_dev *sdev)
 {
        struct sof_intel_hda_dev *hdev;
        struct snd_sof_pdata *pdata = sdev->pdata;
+       int ret;
 
        hdev = sdev->pdata->hw_pdata;
 
@@ -233,6 +286,10 @@ int hda_sdw_startup(struct snd_sof_dev *sdev)
        if (pdata->machine && !pdata->machine->mach_params.link_mask)
                return 0;
 
+       ret = hda_sdw_check_lcount(sdev);
+       if (ret < 0)
+               return ret;
+
        return sdw_intel_startup(hdev->sdw);
 }
 
@@ -383,12 +440,6 @@ static int mclk_id_override = -1;
 module_param_named(mclk_id, mclk_id_override, int, 0444);
 MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
-module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
-MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
-#endif
-
 static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
        {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
        {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
@@ -625,7 +676,6 @@ static bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
 
 void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
 {
-       struct hdac_bus *bus = sof_to_bus(sdev);
        u32 adspis;
        u32 intsts;
        u32 intctl;
@@ -637,7 +687,7 @@ void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
        intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
        intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL);
        ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS);
-       rirbsts = snd_hdac_chip_readb(bus, RIRBSTS);
+       rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS);
 
        dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n",
                intsts, intctl, rirbsts);
@@ -681,6 +731,17 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev)
                hipci, hipcie, hipct, hipcte, hipcctl);
 }
 
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+       u32 val;
+
+       val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
+
+       return !!(val & chip->ipc_req_mask);
+}
+
 static int hda_init(struct snd_sof_dev *sdev)
 {
        struct hda_bus *hbus;
@@ -692,7 +753,7 @@ static int hda_init(struct snd_sof_dev *sdev)
        bus = sof_to_bus(sdev);
 
        /* HDA bus init */
-       sof_hda_bus_init(bus, &pci->dev);
+       sof_hda_bus_init(sdev, &pci->dev);
 
        if (sof_hda_position_quirk == SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS)
                bus->use_posbuf = 0;
@@ -787,7 +848,7 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
        return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 
 static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
                                   const char *sof_tplg_filename,
@@ -867,9 +928,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        struct snd_sof_pdata *pdata = sdev->pdata;
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_ext_link *hlink;
-#endif
        struct sof_intel_hda_dev *hdev = pdata->hw_pdata;
        u32 link_mask;
        int ret = 0;
@@ -879,13 +937,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
                dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
 
        /* Init HDA controller after i915 init */
-       ret = hda_dsp_ctrl_init_chip(sdev, true);
+       ret = hda_dsp_ctrl_init_chip(sdev);
        if (ret < 0) {
                dev_err(bus->dev, "error: init chip failed with ret: %d\n",
                        ret);
                return ret;
        }
 
+       hda_bus_ml_get_capabilities(bus);
+
        /* scan SoundWire capabilities exposed by DSDT */
        ret = hda_sdw_acpi_scan(sdev);
        if (ret < 0) {
@@ -914,37 +974,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
 
 skip_soundwire:
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       if (bus->mlcap)
-               snd_hdac_ext_bus_get_ml_capabilities(bus);
-
        /* create codec instances */
-       hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi);
+       hda_codec_probe_bus(sdev);
 
        if (!HDA_IDISP_CODEC(bus->codec_mask))
                hda_codec_i915_display_power(sdev, false);
 
-       /*
-        * we are done probing so decrement link counts
-        */
-       list_for_each_entry(hlink, &bus->hlink_list, list)
-               snd_hdac_ext_bus_link_put(bus, hlink);
-#endif
-       return 0;
-}
+       hda_bus_ml_put_all(bus);
 
-static void hda_check_for_state_change(struct snd_sof_dev *sdev)
-{
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       struct hdac_bus *bus = sof_to_bus(sdev);
-       unsigned int codec_mask;
-
-       codec_mask = snd_hdac_chip_readw(bus, STATESTS);
-       if (codec_mask) {
-               hda_codec_jack_check(sdev);
-               snd_hdac_chip_writew(bus, STATESTS, codec_mask);
-       }
-#endif
+       return 0;
 }
 
 static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
@@ -996,7 +1034,7 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
                hda_sdw_process_wakeen(sdev);
        }
 
-       hda_check_for_state_change(sdev);
+       hda_codec_check_for_state_change(sdev);
 
        /* enable GIE interrupt */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
@@ -1192,10 +1230,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
        /* cancel any attempt for DSP D0I3 */
        cancel_delayed_work_sync(&hda->d0i3_work);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       /* codec removal, invoke bus_device_remove */
-       snd_hdac_ext_bus_device_remove(bus);
-#endif
+       hda_codec_device_remove(sdev);
 
        hda_sdw_exit(sdev);
 
@@ -1223,16 +1258,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
                pci_free_irq_vectors(pci);
 
        hda_dsp_stream_free(sdev);
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       snd_hdac_link_free_all(bus);
-#endif
+
+       hda_bus_ml_free(sof_to_bus(sdev));
 
        iounmap(sdev->bar[HDA_DSP_BAR]);
        iounmap(bus->remap_addr);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       snd_hdac_ext_bus_exit(bus);
-#endif
+       sof_hda_bus_exit(sdev);
+
        hda_codec_i915_exit(sdev);
 
        return 0;
@@ -1246,7 +1279,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev)
        return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
 }
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 static void hda_generic_machine_select(struct snd_sof_dev *sdev,
                                       struct snd_soc_acpi_mach **mach)
 {
@@ -1325,7 +1358,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
        if (*mach) {
                mach_params = &(*mach)->mach_params;
                mach_params->codec_mask = bus->codec_mask;
-               mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
+               mach_params->common_hdmi_codec_drv = true;
        }
 }
 #else
index 2ab3c38..022ce80 100644 (file)
 #define SOF_HDA_ADSP_DPLBASE_ENABLE            0x01
 
 /* Stream Registers */
-#define SOF_HDA_ADSP_REG_CL_SD_CTL             0x00
-#define SOF_HDA_ADSP_REG_CL_SD_STS             0x03
-#define SOF_HDA_ADSP_REG_CL_SD_LPIB            0x04
-#define SOF_HDA_ADSP_REG_CL_SD_CBL             0x08
-#define SOF_HDA_ADSP_REG_CL_SD_LVI             0x0C
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOW           0x0E
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE                0x10
-#define SOF_HDA_ADSP_REG_CL_SD_FORMAT          0x12
-#define SOF_HDA_ADSP_REG_CL_SD_FIFOL           0x14
-#define SOF_HDA_ADSP_REG_CL_SD_BDLPL           0x18
-#define SOF_HDA_ADSP_REG_CL_SD_BDLPU           0x1C
+#define SOF_HDA_ADSP_REG_SD_CTL                        0x00
+#define SOF_HDA_ADSP_REG_SD_STS                        0x03
+#define SOF_HDA_ADSP_REG_SD_LPIB               0x04
+#define SOF_HDA_ADSP_REG_SD_CBL                        0x08
+#define SOF_HDA_ADSP_REG_SD_LVI                        0x0C
+#define SOF_HDA_ADSP_REG_SD_FIFOW              0x0E
+#define SOF_HDA_ADSP_REG_SD_FIFOSIZE           0x10
+#define SOF_HDA_ADSP_REG_SD_FORMAT             0x12
+#define SOF_HDA_ADSP_REG_SD_FIFOL              0x14
+#define SOF_HDA_ADSP_REG_SD_BDLPL              0x18
+#define SOF_HDA_ADSP_REG_SD_BDLPU              0x1C
 #define SOF_HDA_ADSP_SD_ENTRY_SIZE             0x20
 
 /* CL: Software Position Based FIFO Capability Registers */
 #define HDA_DSP_REG_ADSPIC2            (HDA_DSP_GEN_BASE + 0x10)
 #define HDA_DSP_REG_ADSPIS2            (HDA_DSP_GEN_BASE + 0x14)
 
+#define HDA_DSP_REG_ADSPIC2_SNDW       BIT(5)
 #define HDA_DSP_REG_ADSPIS2_SNDW       BIT(5)
 
 /* Intel HD Audio Inter-Processor Communication Registers */
 /* Intel Vendor Specific Registers */
 #define HDA_VS_INTEL_EM2               0x1030
 #define HDA_VS_INTEL_EM2_L1SEN         BIT(13)
+#define HDA_VS_INTEL_LTRP              0x1048
 #define HDA_VS_INTEL_LTRP_GB_MASK      0x3F
 
 /*  HIPCI */
@@ -481,6 +483,7 @@ enum sof_hda_D0_substate {
 struct sof_intel_hda_dev {
        bool imrboot_supported;
        bool skip_imr_boot;
+       bool booted_from_imr;
 
        int boot_iteration;
 
@@ -521,6 +524,14 @@ struct sof_intel_hda_dev {
 
        /* Intel NHLT information */
        struct nhlt_acpi_table *nhlt;
+
+       /*
+        * Pointing to the IPC message if immediate sending was not possible
+        * because the downlink communication channel was BUSY at the time.
+        * The message will be re-tried when the channel becomes free (the ACK
+        * is received from the DSP for the previous message)
+        */
+       struct snd_sof_ipc_msg *delayed_ipc_tx_msg;
 };
 
 static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@@ -693,27 +704,51 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable);
 int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
 void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
 int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset);
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev);
 void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
 /*
  * HDA bus operations.
  */
-void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev);
+void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev);
+void sof_hda_bus_exit(struct snd_sof_dev *sdev);
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 /*
  * HDA Codec operations.
  */
-void hda_codec_probe_bus(struct snd_sof_dev *sdev,
-                        bool hda_codec_use_common_hdmi);
+void hda_codec_probe_bus(struct snd_sof_dev *sdev);
 void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable);
 void hda_codec_jack_check(struct snd_sof_dev *sdev);
+void hda_codec_check_for_state_change(struct snd_sof_dev *sdev);
+void hda_codec_init_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev);
+void hda_codec_detect_mask(struct snd_sof_dev *sdev);
+void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev);
+bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev);
+void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status);
+void hda_codec_device_remove(struct snd_sof_dev *sdev);
 
-#endif /* CONFIG_SND_SOC_SOF_HDA */
+#else
+
+static inline void hda_codec_probe_bus(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) { }
+static inline void hda_codec_jack_check(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_detect_mask(struct snd_sof_dev *sdev) { }
+static inline void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) { }
+static inline bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) { return false; }
+static inline void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) { }
+static inline void hda_codec_device_remove(struct snd_sof_dev *sdev) { }
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && \
-       (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \
-        IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
 
 void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable);
 int hda_codec_i915_init(struct snd_sof_dev *sdev);
@@ -721,13 +756,32 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev);
 
 #else
 
-static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev,
-                                               bool enable) { }
+static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) { }
 static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; }
 static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; }
 
 #endif
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+
+void hda_bus_ml_get_capabilities(struct hdac_bus *bus);
+void hda_bus_ml_free(struct hdac_bus *bus);
+void hda_bus_ml_put_all(struct hdac_bus *bus);
+void hda_bus_ml_reset_losidv(struct hdac_bus *bus);
+int hda_bus_ml_resume(struct hdac_bus *bus);
+int hda_bus_ml_suspend(struct hdac_bus *bus);
+
+#else
+
+static inline void hda_bus_ml_get_capabilities(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_free(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { }
+static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { }
+static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; }
+static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; }
+
+#endif /* CONFIG_SND_SOC_SOF_HDA */
+
 /*
  * Trace Control.
  */
@@ -741,18 +795,29 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
  */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 
+int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev);
 int hda_sdw_startup(struct snd_sof_dev *sdev);
+void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
 void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
 void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
 bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
 
 #else
 
+static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
+{
+       return 0;
+}
+
 static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
 {
        return 0;
 }
 
+static inline void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+}
+
 static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
 {
 }
@@ -852,8 +917,12 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask);
 irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
 int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
 irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev);
 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
 void hda_ipc4_dump(struct snd_sof_dev *sdev);
 extern struct sdw_intel_ops sdw_callback;
 
+struct sof_ipc4_fw_library;
+int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
+                             struct sof_ipc4_fw_library *fw_lib, bool reload);
 #endif
index 6d58771..435941a 100644 (file)
@@ -130,6 +130,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
 
                ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
 
+               /* External library loading support */
+               ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
                /* doorbell */
                sof_icl_ops.irq_thread  = cnl_ipc4_irq_thread;
 
@@ -177,6 +180,9 @@ const struct sof_intel_dsp_desc icl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
index 1029853..904ae42 100644 (file)
@@ -90,8 +90,16 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
 
 static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
 {
+       struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
        struct sof_ipc4_msg *msg_data = msg->msg_data;
 
+       if (hda_ipc4_tx_is_busy(sdev)) {
+               hdev->delayed_ipc_tx_msg = msg;
+               return 0;
+       }
+
+       hdev->delayed_ipc_tx_msg = NULL;
+
        /* send the message via mailbox */
        if (msg_data->data_size)
                sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
@@ -126,111 +134,79 @@ static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
                                MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
 }
 
-static int mtl_enable_interrupts(struct snd_sof_dev *sdev)
+static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
 {
-       u32 hfintipptr;
-       u32 irqinten;
-       u32 host_ipc;
        u32 hipcie;
+       u32 mask;
+       u32 val;
        int ret;
 
-       /* read Interrupt IP Pointer */
-       hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+       /* Enable/Disable SoundWire interrupt */
+       mask = MTL_DSP_REG_HfSNDWIE_IE_MASK;
+       if (enable)
+               val = mask;
+       else
+               val = 0;
 
-       /* Enable Host IPC and SOUNDWIRE */
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
-                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK,
-                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK);
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val);
 
        /* check if operation was successful */
-       host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
-       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
-                                           (irqinten & host_ipc) == host_ipc,
-                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
-       if (ret < 0) {
-               dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n");
-               return ret;
-       }
-
-       /* Set Host IPC interrupt enable */
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
-                               MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK);
-
-       /* check if operation was successful */
-       host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
-       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
-                                           (hipcie & host_ipc) == host_ipc,
-                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
-       if (ret < 0) {
-               dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n");
-               return ret;
-       }
-
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
-                               MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK);
-       host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
-                                           (hipcie & host_ipc) == host_ipc,
+                                           (hipcie & mask) == val,
                                            HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
        if (ret < 0)
-               dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n");
-
-       return ret;
+               dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",
+                       enable ? "enable" : "disable");
 }
 
-static int mtl_disable_interrupts(struct snd_sof_dev *sdev)
+static int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
 {
        u32 hfintipptr;
        u32 irqinten;
-       u32 host_ipc;
        u32 hipcie;
-       int ret1;
+       u32 mask;
+       u32 val;
        int ret;
 
        /* read Interrupt IP Pointer */
        hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
 
-       /* Disable Host IPC and SOUNDWIRE */
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
-                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0);
+       /* Enable/Disable Host IPC and SOUNDWIRE */
+       mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
+       if (enable)
+               val = mask;
+       else
+               val = 0;
+
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val);
 
        /* check if operation was successful */
-       host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
-                                           (irqinten & host_ipc) == 0,
+                                           (irqinten & mask) == val,
                                            HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
-       /* Continue to disable other interrupts when error happens */
-       if (ret < 0)
-               dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n");
+       if (ret < 0) {
+               dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",
+                       enable ? "enable" : "disable");
+               return ret;
+       }
 
-       /* Set Host IPC interrupt disable */
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
-                               MTL_DSP_REG_HfHIPCIE_IE_MASK, 0);
+       /* Enable/Disable Host IPC interrupt*/
+       mask = MTL_DSP_REG_HfHIPCIE_IE_MASK;
+       if (enable)
+               val = mask;
+       else
+               val = 0;
 
-       /* check if operation was successful */
-       host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
-       ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
-                                            (hipcie & host_ipc) == 0,
-                                            HDA_DSP_REG_POLL_INTERVAL_US,
-                                            HDA_DSP_RESET_TIMEOUT_US);
-       if (ret1 < 0) {
-               dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n");
-               if (!ret)
-                       ret = ret1;
-       }
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val);
 
-       /* Set SoundWire IPC interrupt disable */
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
-                               MTL_DSP_REG_HfSNDWIE_IE_MASK, 0);
-       host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
-       ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
-                                            (hipcie & host_ipc) == 0,
-                                            HDA_DSP_REG_POLL_INTERVAL_US,
-                                            HDA_DSP_RESET_TIMEOUT_US);
-       if (ret1 < 0) {
-               dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n");
-               if (!ret)
-                       ret = ret1;
+       /* check if operation was successful */
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
+                                           (hipcie & mask) == val,
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0) {
+               dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",
+                       enable ? "enable" : "disable");
+               return ret;
        }
 
        return ret;
@@ -385,7 +361,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
                                MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);
 
-       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
        usleep_range(1000, 1010);
 
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
@@ -414,7 +390,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev)
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
                                MTL_HFDSSCS_SPA_MASK, 0);
 
-       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
        usleep_range(1000, 1010);
 
        /* poll with timeout to check if operation successful */
@@ -465,7 +441,7 @@ static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_bo
                                       chip->ipc_ack_mask);
 
        /* step 4: enable interrupts */
-       ret = mtl_enable_interrupts(sdev);
+       ret = mtl_enable_interrupts(sdev, true);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__);
@@ -492,11 +468,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
 {
        struct sof_ipc4_msg notification_data = {{ 0 }};
        struct snd_sof_dev *sdev = context;
+       bool ack_received = false;
        bool ipc_irq = false;
        u32 hipcida;
        u32 hipctdr;
 
        hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
+       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
 
        /* reply message from DSP */
        if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {
@@ -507,9 +485,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
                mtl_ipc_dsp_done(sdev);
 
                ipc_irq = true;
+               ack_received = true;
        }
 
-       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
        if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
                /* Message from DSP (reply or notification) */
                u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
@@ -530,6 +508,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
                                spin_lock_irq(&sdev->ipc_lock);
 
                                snd_sof_ipc_get_reply(sdev);
+                               mtl_ipc_host_done(sdev);
                                snd_sof_ipc_reply(sdev, data->primary);
 
                                spin_unlock_irq(&sdev->ipc_lock);
@@ -546,9 +525,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
                        sdev->ipc->msg.rx_data = &notification_data;
                        snd_sof_ipc_msgs_rx(sdev);
                        sdev->ipc->msg.rx_data = NULL;
-               }
 
-               mtl_ipc_host_done(sdev);
+                       mtl_ipc_host_done(sdev);
+               }
 
                ipc_irq = true;
        }
@@ -558,6 +537,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
                dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
        }
 
+       if (ack_received) {
+               struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+               if (hdev->delayed_ipc_tx_msg)
+                       mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -590,8 +576,9 @@ static void mtl_ipc_dump(struct snd_sof_dev *sdev)
 
 static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
 {
+       mtl_enable_sdw_irq(sdev, false);
        mtl_disable_ipc_interrupts(sdev);
-       return mtl_disable_interrupts(sdev);
+       return mtl_enable_interrupts(sdev, false);
 }
 
 /* Meteorlake ops */
@@ -641,6 +628,9 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
 
        ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
 
+       /* External library loading support */
+       ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
        /* set DAI ops */
        hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
 
@@ -663,6 +653,9 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE_ACE,
        .sdw_alh_base = SDW_ALH_BASE_ACE,
+       .d0i3_offset = MTL_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = mtl_enable_sdw_irq,
        .check_sdw_irq = mtl_dsp_check_sdw_irq,
        .check_ipc_irq = mtl_dsp_check_ipc_irq,
        .cl_init = mtl_dsp_cl_init,
index 788bf0e..0fd4e6f 100644 (file)
@@ -21,6 +21,8 @@
 #define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6)
 #define MTL_HFINTIPPTR_PTR_MASK                GENMASK(20, 0)
 
+#define MTL_HDA_VS_D0I3C               0x1D4A
+
 #define MTL_DSP2CXCAP_PRIMARY_CORE     0x178D00
 #define MTL_DSP2CXCTL_PRIMARY_CORE     0x178D04
 #define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0)
index 998e219..69279dc 100644 (file)
@@ -33,6 +33,9 @@ static const struct sof_dev_desc bxt_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/apl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/apl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -61,6 +64,9 @@ static const struct sof_dev_desc glk_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/glk",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/glk",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
index c797356..8db3f8d 100644 (file)
@@ -34,6 +34,9 @@ static const struct sof_dev_desc cnl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/cnl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc cfl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/cnl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -91,6 +97,9 @@ static const struct sof_dev_desc cml_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/cnl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
index 48f24f8..d6cf75e 100644 (file)
@@ -34,6 +34,9 @@ static const struct sof_dev_desc icl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/icl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/icl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc jsl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/jsl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/jsl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
index 9f39da9..6e4e6d4 100644 (file)
@@ -34,6 +34,9 @@ static const struct sof_dev_desc mtl_desc = {
        .default_fw_path = {
                [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/sof-ipc4-lib/mtl",
+       },
        .default_tplg_path = {
                [SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
        },
index 4cfe4f2..e80c4df 100644 (file)
@@ -34,6 +34,9 @@ static const struct sof_dev_desc tgl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/tgl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/tgl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -62,6 +65,9 @@ static const struct sof_dev_desc tglh_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/tgl-h",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/tgl-h",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -90,6 +96,9 @@ static const struct sof_dev_desc ehl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/ehl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/ehl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -118,6 +127,9 @@ static const struct sof_dev_desc adls_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/adl-s",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/adl-s",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -146,6 +158,9 @@ static const struct sof_dev_desc adl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/adl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/adl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -174,6 +189,9 @@ static const struct sof_dev_desc adl_n_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/adl-n",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/adl-n",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -202,6 +220,9 @@ static const struct sof_dev_desc rpls_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/rpl-s",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/rpl-s",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
@@ -230,6 +251,9 @@ static const struct sof_dev_desc rpl_desc = {
                [SOF_IPC] = "intel/sof",
                [SOF_INTEL_IPC4] = "intel/avs/rpl",
        },
+       .default_lib_path = {
+               [SOF_INTEL_IPC4] = "intel/avs-lib/rpl",
+       },
        .default_tplg_path = {
                [SOF_IPC] = "intel/sof-tplg",
                [SOF_INTEL_IPC4] = "intel/avs-tplg",
index f0f6d9b..5b2b409 100644 (file)
@@ -144,11 +144,7 @@ struct snd_sof_dsp_ops sof_tng_ops = {
        .run            = atom_run,
        .reset          = atom_reset,
 
-       /* Register IO */
-       .write          = sof_io_write,
-       .read           = sof_io_read,
-       .write64        = sof_io_write64,
-       .read64         = sof_io_read64,
+       /* Register IO uses direct mmio */
 
        /* Block IO */
        .block_read     = sof_block_read,
index 3ceba5c..48428cc 100644 (file)
@@ -182,8 +182,11 @@ struct sof_intel_dsp_desc {
        int ssp_base_offset;            /* base address of the SSPs */
        u32 sdw_shim_base;
        u32 sdw_alh_base;
+       u32 d0i3_offset;
        u32 quirks;
        enum sof_intel_hw_ip_version hw_ip_version;
+       int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
+       void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
        bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
        bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
        int (*power_down_dsp)(struct snd_sof_dev *sdev);
index 9ae2890..30f2f49 100644 (file)
@@ -85,6 +85,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
 
                ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
 
+               /* External library loading support */
+               ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
                /* doorbell */
                sof_tgl_ops.irq_thread  = cnl_ipc4_irq_thread;
 
@@ -132,6 +135,9 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
@@ -157,6 +163,9 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
@@ -182,6 +191,9 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
@@ -207,6 +219,9 @@ const struct sof_intel_dsp_desc adls_chip_info = {
        .ssp_base_offset = CNL_SSP_BASE_OFFSET,
        .sdw_shim_base = SDW_SHIM_BASE,
        .sdw_alh_base = SDW_ALH_BASE,
+       .d0i3_offset = SOF_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_common,
+       .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
index 6ed3f9b..b53abc9 100644 (file)
@@ -84,6 +84,14 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes
 }
 EXPORT_SYMBOL(sof_ipc_tx_message);
 
+/* IPC set or get data from host to DSP */
+int sof_ipc_set_get_data(struct snd_sof_ipc *ipc, void *msg_data,
+                        size_t msg_bytes, bool set)
+{
+       return ipc->ops->set_get_data(ipc->sdev, msg_data, msg_bytes, set);
+}
+EXPORT_SYMBOL(sof_ipc_set_get_data);
+
 /*
  * send IPC message from host to DSP without modifying the DSP state.
  * This will be used for IPC's that can be handled by the DSP
@@ -200,6 +208,9 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
                return NULL;
        }
 
+       if (ops->init && ops->init(sdev))
+               return NULL;
+
        ipc->ops = ops;
 
        return ipc;
@@ -217,5 +228,8 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev)
        mutex_lock(&ipc->tx_mutex);
        ipc->disable_ipc_tx = true;
        mutex_unlock(&ipc->tx_mutex);
+
+       if (ipc->ops->exit)
+               ipc->ops->exit(sdev);
 }
 EXPORT_SYMBOL(snd_sof_ipc_free);
index bf423ca..2821876 100644 (file)
@@ -138,8 +138,7 @@ static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmw
 
 static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
-       const struct firmware *fw = plat_data->fw;
+       const struct firmware *fw = sdev->basefw.fw;
        const struct sof_ext_man_elem_header *elem_hdr;
        const struct sof_ext_man_header *head;
        ssize_t ext_man_size;
@@ -310,18 +309,18 @@ static int sof_ipc3_parse_module_memcpy(struct snd_sof_dev *sdev,
 
 static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
-       const struct firmware *fw = plat_data->fw;
+       u32 payload_offset = sdev->basefw.payload_offset;
+       const struct firmware *fw = sdev->basefw.fw;
        struct snd_sof_fw_header *header;
        struct snd_sof_mod_hdr *module;
        int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr);
        size_t remaining;
        int ret, count;
 
-       if (!plat_data->fw)
+       if (!fw)
                return -EINVAL;
 
-       header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+       header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
        load_module = sof_ops(sdev)->load_module;
        if (!load_module) {
                dev_dbg(sdev->dev, "Using generic module loading\n");
@@ -331,9 +330,8 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
        }
 
        /* parse each module */
-       module = (struct snd_sof_mod_hdr *)(fw->data + plat_data->fw_offset +
-                                           sizeof(*header));
-       remaining = fw->size - sizeof(*header) - plat_data->fw_offset;
+       module = (struct snd_sof_mod_hdr *)(fw->data + payload_offset + sizeof(*header));
+       remaining = fw->size - sizeof(*header) - payload_offset;
        /* check for wrap */
        if (remaining > fw->size) {
                dev_err(sdev->dev, "%s: fw size smaller than header size\n", __func__);
@@ -374,19 +372,19 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
 
 static int sof_ipc3_validate_firmware(struct snd_sof_dev *sdev)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
-       const struct firmware *fw = plat_data->fw;
+       u32 payload_offset = sdev->basefw.payload_offset;
+       const struct firmware *fw = sdev->basefw.fw;
        struct snd_sof_fw_header *header;
-       size_t fw_size = fw->size - plat_data->fw_offset;
+       size_t fw_size = fw->size - payload_offset;
 
-       if (fw->size <= plat_data->fw_offset) {
+       if (fw->size <= payload_offset) {
                dev_err(sdev->dev,
                        "firmware size must be greater than firmware offset\n");
                return -EINVAL;
        }
 
        /* Read the header information from the data pointer */
-       header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
+       header = (struct snd_sof_fw_header *)(fw->data + payload_offset);
 
        /* verify FW sig */
        if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
index b28af3a..1fef4dc 100644 (file)
@@ -329,6 +329,8 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
        struct snd_sof_dev *sdev = ipc->sdev;
        int ret;
 
+       ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
+
        ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
 
        if (ret) {
@@ -338,8 +340,6 @@ static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
                return ret;
        }
 
-       ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
-
        /* now wait for completion */
        return ipc3_wait_tx_done(ipc, reply_data);
 }
index e635ae5..1321acc 100644 (file)
 #include "sof-priv.h"
 #include "ops.h"
 
-static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
+/* The module ID includes the id of the library it is part of at offset 12 */
+#define SOF_IPC4_MOD_LIB_ID_SHIFT      12
+
+static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
+                                        struct sof_ipc4_fw_library *fw_lib)
 {
        struct sof_ipc4_fw_data *ipc4_data = sdev->private;
-       struct snd_sof_pdata *plat_data = sdev->pdata;
+       const struct firmware *fw = fw_lib->sof_fw.fw;
        struct sof_man4_fw_binary_header *fw_header;
-       const struct firmware *fw = plat_data->fw;
        struct sof_ext_manifest4_hdr *ext_man_hdr;
        struct sof_man4_module_config *fm_config;
        struct sof_ipc4_fw_module *fw_module;
@@ -71,20 +74,20 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
                return -EINVAL;
        }
 
-       dev_info(sdev->dev, "Loaded firmware version: %u.%u.%u.%u\n",
-                fw_header->major_version, fw_header->minor_version,
+       dev_info(sdev->dev, "Loaded firmware library: %s, version: %u.%u.%u.%u\n",
+                fw_header->name, fw_header->major_version, fw_header->minor_version,
                 fw_header->hotfix_version, fw_header->build_version);
-       dev_dbg(sdev->dev, "Firmware name: %s, header length: %u, module count: %u\n",
-               fw_header->name, fw_header->len, fw_header->num_module_entries);
+       dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
+               fw_header->len, fw_header->num_module_entries);
 
-       ipc4_data->fw_modules = devm_kmalloc_array(sdev->dev,
-                                                  fw_header->num_module_entries,
-                                                  sizeof(*fw_module), GFP_KERNEL);
-       if (!ipc4_data->fw_modules)
+       fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
+                                            sizeof(*fw_module), GFP_KERNEL);
+       if (!fw_lib->modules)
                return -ENOMEM;
 
-       ipc4_data->num_fw_modules = fw_header->num_module_entries;
-       fw_module = ipc4_data->fw_modules;
+       fw_lib->name = fw_header->name;
+       fw_lib->num_modules = fw_header->num_module_entries;
+       fw_module = fw_lib->modules;
 
        fm_entry = (struct sof_man4_module *)((u8 *)fw_header + fw_header->len);
        remaining -= fw_header->len;
@@ -134,13 +137,182 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev)
        return ext_man_hdr->len;
 }
 
+static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_library *fw_lib;
+       ssize_t payload_offset;
+       int ret;
+
+       fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+       if (!fw_lib)
+               return -ENOMEM;
+
+       fw_lib->sof_fw.fw = sdev->basefw.fw;
+
+       payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+       if (payload_offset > 0) {
+               fw_lib->sof_fw.payload_offset = payload_offset;
+
+               /* basefw ID is 0 */
+               fw_lib->id = 0;
+               ret = xa_insert(&ipc4_data->fw_lib_xa, 0, fw_lib, GFP_KERNEL);
+               if (ret)
+                       return ret;
+       }
+
+       return payload_offset;
+}
+
+static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
+                                        unsigned long lib_id, const guid_t *uuid)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_library *fw_lib;
+       const char *fw_filename;
+       ssize_t payload_offset;
+       int ret, i, err;
+
+       if (!sdev->pdata->fw_lib_prefix) {
+               dev_err(sdev->dev,
+                       "Library loading is not supported due to not set library path\n");
+               return -EINVAL;
+       }
+
+       if (!ipc4_data->load_library) {
+               dev_err(sdev->dev, "Library loading is not supported on this platform\n");
+               return -EOPNOTSUPP;
+       }
+
+       fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+       if (!fw_lib)
+               return -ENOMEM;
+
+       fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
+                               sdev->pdata->fw_lib_prefix, uuid);
+       if (!fw_filename) {
+               ret = -ENOMEM;
+               goto free_fw_lib;
+       }
+
+       ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev);
+       if (ret < 0) {
+               dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename);
+               goto free_filename;
+       } else {
+               dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
+       }
+
+       payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+       if (payload_offset <= 0) {
+               if (!payload_offset)
+                       ret = -EINVAL;
+               else
+                       ret = payload_offset;
+
+               goto release;
+       }
+
+       fw_lib->sof_fw.payload_offset = payload_offset;
+       fw_lib->id = lib_id;
+
+       /* Fix up the module ID numbers within the library */
+       for (i = 0; i < fw_lib->num_modules; i++)
+               fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
+
+       /*
+        * Make sure that the DSP is booted and stays up while attempting the
+        * loading the library for the first time
+        */
+       ret = pm_runtime_resume_and_get(sdev->dev);
+       if (ret < 0 && ret != -EACCES) {
+               dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
+                                   __func__, ret);
+               goto release;
+       }
+
+       ret = ipc4_data->load_library(sdev, fw_lib, false);
+
+       pm_runtime_mark_last_busy(sdev->dev);
+       err = pm_runtime_put_autosuspend(sdev->dev);
+       if (err < 0)
+               dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
+                                   __func__, err);
+
+       if (ret)
+               goto release;
+
+       ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL);
+       if (unlikely(ret))
+               goto release;
+
+       kfree(fw_filename);
+
+       return 0;
+
+release:
+       release_firmware(fw_lib->sof_fw.fw);
+       /* Allocated within sof_ipc4_fw_parse_ext_man() */
+       devm_kfree(sdev->dev, fw_lib->modules);
+free_filename:
+       kfree(fw_filename);
+free_fw_lib:
+       devm_kfree(sdev->dev, fw_lib);
+
+       return ret;
+}
+
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+                                                       const guid_t *uuid)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_library *fw_lib;
+       unsigned long lib_id;
+       int i, ret;
+
+       if (guid_is_null(uuid))
+               return NULL;
+
+       xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+               for (i = 0; i < fw_lib->num_modules; i++) {
+                       if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+                               return &fw_lib->modules[i];
+               }
+       }
+
+       /*
+        * Do not attempt to load external library in case the maximum number of
+        * firmware libraries have been already loaded
+        */
+       if ((lib_id + 1) == ipc4_data->max_libs_count) {
+               dev_err(sdev->dev,
+                       "%s: Maximum allowed number of libraries reached (%u)\n",
+                       __func__, ipc4_data->max_libs_count);
+               return NULL;
+       }
+
+       /* The module cannot be found, try to load it as a library */
+       ret = sof_ipc4_load_library_by_uuid(sdev, lib_id + 1, uuid);
+       if (ret)
+               return NULL;
+
+       /* Look for the module in the newly loaded library, it should be available now */
+       xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, lib_id) {
+               for (i = 0; i < fw_lib->num_modules; i++) {
+                       if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+                               return &fw_lib->modules[i];
+               }
+       }
+
+       return NULL;
+}
+
 static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
 {
        struct sof_ipc4_fw_data *ipc4_data = sdev->private;
        u32 fw_hdr_offset = ipc4_data->manifest_fw_hdr_offset;
-       struct snd_sof_pdata *plat_data = sdev->pdata;
        struct sof_man4_fw_binary_header *fw_header;
-       const struct firmware *fw = plat_data->fw;
+       const struct firmware *fw = sdev->basefw.fw;
        struct sof_ext_manifest4_hdr *ext_man_hdr;
 
        ext_man_hdr = (struct sof_ext_manifest4_hdr *)fw->data;
@@ -156,7 +328,7 @@ static int sof_ipc4_validate_firmware(struct snd_sof_dev *sdev)
        return 0;
 }
 
-static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
 {
        struct sof_ipc4_fw_data *ipc4_data = sdev->private;
        const struct sof_ipc_ops *iops = sdev->ipc->ops;
@@ -204,6 +376,24 @@ static int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
                        trace_sof_ipc4_fw_config(sdev, "Trace log size", *tuple->value);
                        ipc4_data->mtrace_log_bytes = *tuple->value;
                        break;
+               case SOF_IPC4_FW_CFG_MAX_LIBS_COUNT:
+                       trace_sof_ipc4_fw_config(sdev, "maximum number of libraries",
+                                                *tuple->value);
+                       ipc4_data->max_libs_count = *tuple->value;
+                       if (!ipc4_data->max_libs_count)
+                               ipc4_data->max_libs_count = 1;
+                       break;
+               case SOF_IPC4_FW_CFG_MAX_PPL_COUNT:
+                       ipc4_data->max_num_pipelines = *tuple->value;
+                       trace_sof_ipc4_fw_config(sdev, "Max PPL count %d",
+                                                ipc4_data->max_num_pipelines);
+                       if (ipc4_data->max_num_pipelines <= 0) {
+                               dev_err(sdev->dev, "Invalid max_num_pipelines %d",
+                                       ipc4_data->max_num_pipelines);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       break;
                default:
                        break;
                }
@@ -217,8 +407,26 @@ out:
        return ret;
 }
 
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_library *fw_lib;
+       unsigned long lib_id;
+       int ret = 0;
+
+       xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, 1) {
+               ret = ipc4_data->load_library(sdev, fw_lib, true);
+               if (ret) {
+                       dev_err(sdev->dev, "%s: Failed to reload library: %s, %d\n",
+                               __func__, fw_lib->name, ret);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
 const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
        .validate = sof_ipc4_validate_firmware,
-       .parse_ext_manifest = sof_ipc4_fw_parse_ext_man,
-       .query_fw_configuration = sof_ipc4_query_fw_configuration,
+       .parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
 };
index 7328723..96941be 100644 (file)
@@ -81,7 +81,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
 
                /* first set the pipeline to PAUSED state */
                if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
-                       ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                       ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id,
                                                          SOF_IPC4_PIPE_PAUSED);
                        if (ret < 0) {
                                dev_err(sdev->dev, "failed to pause pipeline %d\n",
@@ -96,7 +96,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
                        continue;
 
                /* then set the final state */
-               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state);
+               ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id, state);
                if (ret < 0) {
                        dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
                                state, swidget->pipeline_id);
index e3b8484..fc9efdc 100644 (file)
@@ -25,35 +25,63 @@ enum sof_ipc4_mtrace_type {
 };
 
 /**
+ * struct sof_ipc4_fw_module - IPC4 module info
+ * @sof_man4_module: Module info
+ * @m_ida: Module instance identifier
+ * @bss_size: Module object size
+ * @private: Module private data
+ */
+struct sof_ipc4_fw_module {
+       struct sof_man4_module man4_module_entry;
+       struct ida m_ida;
+       u32 bss_size;
+       void *private;
+};
+
+/**
+ * struct sof_ipc4_fw_library - IPC4 library information
+ * @sof_fw: SOF Firmware of the library
+ * @id: Library ID. 0 is reserved for basefw, external libraries must have unique
+ *     ID number between 1 and (sof_ipc4_fw_data.max_libs_count - 1)
+ *     Note: sof_ipc4_fw_data.max_libs_count == 1 implies that external libraries
+ *     are not supported
+ * @num_modules : Number of FW modules in the library
+ * @modules: Array of FW modules
+ */
+struct sof_ipc4_fw_library {
+       struct sof_firmware sof_fw;
+       const char *name;
+       u32 id;
+       int num_modules;
+       struct sof_ipc4_fw_module *modules;
+};
+
+/**
  * struct sof_ipc4_fw_data - IPC4-specific data
  * @manifest_fw_hdr_offset: FW header offset in the manifest
- * @num_fw_modules : Number of modules in base FW
- * @fw_modules: Array of base FW modules
+ * @fw_lib_xa: XArray for firmware libraries, including basefw (ID = 0)
+ *            Used to store the FW libraries and to manage the unique IDs of the
+ *            libraries.
  * @nhlt: NHLT table either from the BIOS or the topology manifest
  * @mtrace_type: mtrace type supported on the booted platform
  * @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
+ * @max_num_pipelines: max number of pipelines
+ * @max_libs_count: Maximum number of libraries support by the FW including the
+ *                 base firmware
+ *
+ * @load_library: Callback function for platform dependent library loading
  */
 struct sof_ipc4_fw_data {
        u32 manifest_fw_hdr_offset;
-       int num_fw_modules;
-       void *fw_modules;
+       struct xarray fw_lib_xa;
        void *nhlt;
        enum sof_ipc4_mtrace_type mtrace_type;
        u32 mtrace_log_bytes;
-};
+       int max_num_pipelines;
+       u32 max_libs_count;
 
-/**
- * struct sof_ipc4_fw_module - IPC4 module info
- * @sof_man4_module : Module info
- * @m_ida: Module instance identifier
- * @bss_size: Module object size
- * @private: Module private data
- */
-struct sof_ipc4_fw_module {
-       struct sof_man4_module man4_module_entry;
-       struct ida m_ida;
-       u32 bss_size;
-       void *private;
+       int (*load_library)(struct snd_sof_dev *sdev,
+                           struct sof_ipc4_fw_library *fw_lib, bool reload);
 };
 
 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
@@ -64,4 +92,9 @@ 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_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
+
+int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
+struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+                                                       const guid_t *uuid);
 #endif
index a81af5f..59f4d42 100644 (file)
@@ -20,6 +20,7 @@
 #define SOF_IPC4_TPLG_ABI_SIZE 6
 
 static DEFINE_IDA(alh_group_ida);
+static DEFINE_IDA(pipeline_ida);
 
 static const struct sof_topology_token ipc4_sched_tokens[] = {
        {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -280,7 +281,7 @@ static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *avai
        available_fmt->out_audio_fmt = NULL;
 }
 
-static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
+static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
 {
        kfree(swidget->private);
 }
@@ -289,22 +290,11 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
 {
        struct snd_soc_component *scomp = swidget->scomp;
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
-       struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
-       int i;
 
-       if (!fw_modules) {
-               dev_err(sdev->dev, "no fw_module information\n");
-               return -EINVAL;
-       }
+       swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
 
-       /* set module info */
-       for (i = 0; i < ipc4_data->num_fw_modules; i++) {
-               if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
-                       swidget->module_info = &fw_modules[i];
-                       return 0;
-               }
-       }
+       if (swidget->module_info)
+               return 0;
 
        dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
                swidget->widget->name, &swidget->uuid);
@@ -328,8 +318,7 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_
        msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
        msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
 
-       msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
-       msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
+       msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
 
        type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
        msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
@@ -636,7 +625,6 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
        swidget->private = pipeline;
 
        pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
-       pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
        pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
        pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
        pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -1447,6 +1435,8 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
 
 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
 {
+       struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
        struct sof_ipc4_pipeline *pipeline;
        struct sof_ipc4_msg *msg;
        void *ipc_data = NULL;
@@ -1462,6 +1452,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
 
                msg = &pipeline->msg;
                msg->primary |= pipeline->mem_usage;
+
+               swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
+                                                    GFP_KERNEL);
+               if (swidget->instance_id < 0) {
+                       dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
+                               swidget->widget->name, swidget->instance_id);
+                       return swidget->instance_id;
+               }
+               msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
+               msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
                break;
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
@@ -1535,6 +1535,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
 
                msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
                msg->extension |= ipc_size >> 2;
+
+               msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
+               msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
        }
        dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
                swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
@@ -1550,6 +1553,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
                        struct sof_ipc4_fw_module *fw_module = swidget->module_info;
 
                        ida_free(&fw_module->m_ida, swidget->instance_id);
+               } else {
+                       ida_free(&pipeline_ida, swidget->instance_id);
                }
        }
 
@@ -1567,7 +1572,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
                struct sof_ipc4_msg msg = {{ 0 }};
                u32 header;
 
-               header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+               header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
                header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
                header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
                header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -1581,6 +1586,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
 
                pipeline->mem_usage = 0;
                pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+               ida_free(&pipeline_ida, swidget->instance_id);
        } else {
                ida_free(&fw_module->m_ida, swidget->instance_id);
        }
@@ -1588,6 +1594,88 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
        return ret;
 }
 
+static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
+                                struct snd_sof_widget *sink_widget, bool pin_type)
+{
+       struct snd_sof_widget *current_swidget;
+       struct snd_soc_component *scomp;
+       struct ida *queue_ida;
+       const char *buddy_name;
+       char **pin_binding;
+       u32 num_pins;
+       int i;
+
+       if (pin_type == SOF_PIN_TYPE_SOURCE) {
+               current_swidget = src_widget;
+               pin_binding = src_widget->src_pin_binding;
+               queue_ida = &src_widget->src_queue_ida;
+               num_pins = src_widget->num_source_pins;
+               buddy_name = sink_widget->widget->name;
+       } else {
+               current_swidget = sink_widget;
+               pin_binding = sink_widget->sink_pin_binding;
+               queue_ida = &sink_widget->sink_queue_ida;
+               num_pins = sink_widget->num_sink_pins;
+               buddy_name = src_widget->widget->name;
+       }
+
+       scomp = current_swidget->scomp;
+
+       if (num_pins < 1) {
+               dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
+                       (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
+                       num_pins, current_swidget->widget->name);
+               return -EINVAL;
+       }
+
+       /* If there is only one sink/source pin, queue id must be 0 */
+       if (num_pins == 1)
+               return 0;
+
+       /* Allocate queue ID from pin binding array if it is defined in topology. */
+       if (pin_binding) {
+               for (i = 0; i < num_pins; i++) {
+                       if (!strcmp(pin_binding[i], buddy_name))
+                               return i;
+               }
+               /*
+                * Fail if no queue ID found from pin binding array, so that we don't
+                * mixed use pin binding array and ida for queue ID allocation.
+                */
+               dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
+                       (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"),
+                       current_swidget->widget->name);
+               return -EINVAL;
+       }
+
+       /* If no pin binding array specified in topology, use ida to allocate one */
+       return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
+}
+
+static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
+                                 bool pin_type)
+{
+       struct ida *queue_ida;
+       char **pin_binding;
+       int num_pins;
+
+       if (pin_type == SOF_PIN_TYPE_SOURCE) {
+               pin_binding = swidget->src_pin_binding;
+               queue_ida = &swidget->src_queue_ida;
+               num_pins = swidget->num_source_pins;
+       } else {
+               pin_binding = swidget->sink_pin_binding;
+               queue_ida = &swidget->sink_queue_ida;
+               num_pins = swidget->num_sink_pins;
+       }
+
+       /* Nothing to free if queue ID is not allocated with ida. */
+       if (num_pins == 1 || pin_binding)
+               return;
+
+       ida_free(queue_ida, queue_id);
+}
+
 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
 {
        struct snd_sof_widget *src_widget = sroute->src_widget;
@@ -1596,12 +1684,29 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
        struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
        struct sof_ipc4_msg msg = {{ 0 }};
        u32 header, extension;
-       int src_queue = 0;
-       int dst_queue = 0;
        int ret;
 
-       dev_dbg(sdev->dev, "bind %s -> %s\n",
-               src_widget->widget->name, sink_widget->widget->name);
+       sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
+                                                    SOF_PIN_TYPE_SOURCE);
+       if (sroute->src_queue_id < 0) {
+               dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
+                       src_widget->widget->name);
+               return sroute->src_queue_id;
+       }
+
+       sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
+                                                    SOF_PIN_TYPE_SINK);
+       if (sroute->dst_queue_id < 0) {
+               dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
+                       sink_widget->widget->name);
+               sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
+                                     SOF_PIN_TYPE_SOURCE);
+               return sroute->dst_queue_id;
+       }
+
+       dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
+               src_widget->widget->name, sroute->src_queue_id,
+               sink_widget->widget->name, sroute->dst_queue_id);
 
        header = src_fw_module->man4_module_entry.id;
        header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
@@ -1611,17 +1716,23 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
 
        extension = sink_fw_module->man4_module_entry.id;
        extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
-       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
-       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
+       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
 
        msg.primary = header;
        msg.extension = extension;
 
        ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
                        __func__, src_widget->widget->name, sink_widget->widget->name);
 
+               sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
+                                     SOF_PIN_TYPE_SOURCE);
+               sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id,
+                                     SOF_PIN_TYPE_SINK);
+       }
+
        return ret;
 }
 
@@ -1633,12 +1744,11 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
        struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
        struct sof_ipc4_msg msg = {{ 0 }};
        u32 header, extension;
-       int src_queue = 0;
-       int dst_queue = 0;
        int ret;
 
-       dev_dbg(sdev->dev, "unbind modules %s -> %s\n",
-               src_widget->widget->name, sink_widget->widget->name);
+       dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
+               src_widget->widget->name, sroute->src_queue_id,
+               sink_widget->widget->name, sroute->dst_queue_id);
 
        header = src_fw_module->man4_module_entry.id;
        header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
@@ -1648,8 +1758,8 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
 
        extension = sink_fw_module->man4_module_entry.id;
        extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
-       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
-       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
+       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
 
        msg.primary = header;
        msg.extension = extension;
@@ -1659,6 +1769,9 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
                dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
                        src_widget->widget->name, sink_widget->widget->name);
 
+       sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK);
+       sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE);
+
        return ret;
 }
 
@@ -1824,6 +1937,39 @@ static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
        return -EINVAL;
 }
 
+static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+{
+       struct snd_sof_pcm *spcm;
+       int dir, ret;
+
+       /*
+        * This function is called during system suspend, we need to make sure
+        * that all streams have been freed up.
+        * Freeing might have been skipped when xrun happened just at the start
+        * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
+        * stream. This will call sof_pcm_stream_free() with
+        * free_widget_list = false which will leave the kernel and firmware out
+        * of sync during suspend/resume.
+        *
+        * This will also make sure that paused streams handled correctly.
+        */
+       list_for_each_entry(spcm, &sdev->pcm_list, list) {
+               for_each_pcm_streams(dir) {
+                       struct snd_pcm_substream *substream = spcm->stream[dir].substream;
+
+                       if (!substream || !substream->runtime)
+                               continue;
+
+                       if (spcm->stream[dir].list) {
+                               ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
+                               if (ret < 0)
+                                       return ret;
+                       }
+               }
+       }
+       return 0;
+}
+
 static enum sof_tokens host_token_list[] = {
        SOF_COMP_TOKENS,
        SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1895,7 +2041,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
                                  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
                                  sof_ipc4_prepare_copier_module,
                                  sof_ipc4_unprepare_copier_module},
-       [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
+       [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
+                                   sof_ipc4_widget_free_comp_pipeline,
                                    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
                                    NULL, NULL},
        [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
@@ -1924,4 +2071,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
        .dai_config = sof_ipc4_dai_config,
        .parse_manifest = sof_ipc4_parse_manifest,
        .dai_get_clk = sof_ipc4_dai_get_clk,
+       .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
 };
index 6eaa18e..74cd7e9 100644 (file)
@@ -8,6 +8,7 @@
 // Authors: Rander Wang <rander.wang@linux.intel.com>
 //         Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
 //
+#include <linux/firmware.h>
 #include <sound/sof/header.h>
 #include <sound/sof/ipc4/header.h>
 #include "sof-priv.h"
@@ -342,6 +343,8 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
        if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size)
                return -EINVAL;
 
+       sof_ipc4_log_header(sdev->dev, "ipc tx      ", msg_data, true);
+
        ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
        if (ret) {
                dev_err_ratelimited(sdev->dev,
@@ -350,8 +353,6 @@ static int ipc4_tx_msg_unlocked(struct snd_sof_ipc *ipc,
                return ret;
        }
 
-       sof_ipc4_log_header(sdev->dev, "ipc tx      ", msg_data, true);
-
        /* now wait for completion */
        return ipc4_wait_tx_done(ipc, reply_data);
 }
@@ -657,7 +658,47 @@ static const struct sof_ipc_pm_ops ipc4_pm_ops = {
        .set_core_state = sof_ipc4_set_core_state,
 };
 
+static int sof_ipc4_init(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+       xa_init_flags(&ipc4_data->fw_lib_xa, XA_FLAGS_ALLOC);
+
+       return 0;
+}
+
+static void sof_ipc4_exit(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_library *fw_lib;
+       unsigned long lib_id;
+
+       xa_for_each(&ipc4_data->fw_lib_xa, lib_id, fw_lib) {
+               /*
+                * The basefw (ID == 0) is handled by generic code, it is not
+                * loaded by IPC4 code.
+                */
+               if (lib_id != 0)
+                       release_firmware(fw_lib->sof_fw.fw);
+
+               fw_lib->sof_fw.fw = NULL;
+       }
+
+       xa_destroy(&ipc4_data->fw_lib_xa);
+}
+
+static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
+{
+       if (sdev->first_boot)
+               return sof_ipc4_query_fw_configuration(sdev);
+
+       return sof_ipc4_reload_fw_libraries(sdev);
+}
+
 const struct sof_ipc_ops ipc4_ops = {
+       .init = sof_ipc4_init,
+       .exit = sof_ipc4_exit,
+       .post_fw_boot = sof_ipc4_post_boot,
        .tx_msg = sof_ipc4_tx_msg,
        .rx_msg = sof_ipc4_rx_msg,
        .set_get_data = sof_ipc4_set_get_data,
index 5f51d93..81d202e 100644 (file)
@@ -22,7 +22,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
        int ret;
 
        /* Don't request firmware again if firmware is already requested */
-       if (plat_data->fw)
+       if (sdev->basefw.fw)
                return 0;
 
        fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
@@ -31,7 +31,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
        if (!fw_filename)
                return -ENOMEM;
 
-       ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
+       ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
 
        if (ret < 0) {
                dev_err(sdev->dev,
@@ -48,7 +48,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
        ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
        if (ext_man_size > 0) {
                /* when no error occurred, drop extended manifest */
-               plat_data->fw_offset = ext_man_size;
+               sdev->basefw.payload_offset = ext_man_size;
        } else if (!ext_man_size) {
                /* No extended manifest, so nothing to skip during FW load */
                dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
@@ -67,7 +67,6 @@ EXPORT_SYMBOL(snd_sof_load_firmware_raw);
 
 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
 {
-       struct snd_sof_pdata *plat_data = sdev->pdata;
        int ret;
 
        ret = snd_sof_load_firmware_raw(sdev);
@@ -100,8 +99,8 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
        return 0;
 
 error:
-       release_firmware(plat_data->fw);
-       plat_data->fw = NULL;
+       release_firmware(sdev->basefw.fw);
+       sdev->basefw.fw = NULL;
        return ret;
 
 }
@@ -165,6 +164,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
        if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
                return -EIO; /* FW boots but fw_ready op failed */
 
+       dev_dbg(sdev->dev, "firmware boot complete\n");
+       sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
+
        /* perform post fw run operations */
        ret = snd_sof_dsp_post_fw_run(sdev);
        if (ret < 0) {
@@ -172,11 +174,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
                return ret;
        }
 
-       dev_dbg(sdev->dev, "firmware boot complete\n");
-       sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
-
-       if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
-               return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
+       if (sdev->ipc->ops->post_fw_boot)
+               return sdev->ipc->ops->post_fw_boot(sdev);
 
        return 0;
 }
@@ -185,7 +184,7 @@ EXPORT_SYMBOL(snd_sof_run_firmware);
 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
 {
        /* TODO: support module unloading at runtime */
-       release_firmware(sdev->pdata->fw);
-       sdev->pdata->fw = NULL;
+       release_firmware(sdev->basefw.fw);
+       sdev->basefw.fw = NULL;
 }
 EXPORT_SYMBOL(snd_sof_fw_unload);
index 55d43ad..c527522 100644 (file)
@@ -302,26 +302,40 @@ static inline int snd_sof_debugfs_add_region_item(struct snd_sof_dev *sdev,
 }
 
 /* register IO */
+static inline void snd_sof_dsp_write8(struct snd_sof_dev *sdev, u32 bar,
+                                     u32 offset, u8 value)
+{
+       if (sof_ops(sdev)->write8)
+               sof_ops(sdev)->write8(sdev, sdev->bar[bar] + offset, value);
+       else
+               writeb(value,  sdev->bar[bar] + offset);
+}
+
 static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar,
                                     u32 offset, u32 value)
 {
-       if (sof_ops(sdev)->write) {
+       if (sof_ops(sdev)->write)
                sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value);
-               return;
-       }
-
-       dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
+       else
+               writel(value,  sdev->bar[bar] + offset);
 }
 
 static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar,
                                       u32 offset, u64 value)
 {
-       if (sof_ops(sdev)->write64) {
+       if (sof_ops(sdev)->write64)
                sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value);
-               return;
-       }
+       else
+               writeq(value, sdev->bar[bar] + offset);
+}
 
-       dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
+static inline u8 snd_sof_dsp_read8(struct snd_sof_dev *sdev, u32 bar,
+                                  u32 offset)
+{
+       if (sof_ops(sdev)->read8)
+               return sof_ops(sdev)->read8(sdev, sdev->bar[bar] + offset);
+       else
+               return readb(sdev->bar[bar] + offset);
 }
 
 static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
@@ -329,9 +343,8 @@ static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
 {
        if (sof_ops(sdev)->read)
                return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset);
-
-       dev_err(sdev->dev, "error: %s not defined\n", __func__);
-       return -ENOTSUPP;
+       else
+               return readl(sdev->bar[bar] + offset);
 }
 
 static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
@@ -339,9 +352,19 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
 {
        if (sof_ops(sdev)->read64)
                return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset);
+       else
+               return readq(sdev->bar[bar] + offset);
+}
 
-       dev_err(sdev->dev, "error: %s not defined\n", __func__);
-       return -ENOTSUPP;
+static inline void snd_sof_dsp_update8(struct snd_sof_dev *sdev, u32 bar,
+                                      u32 offset, u8 value, u8 mask)
+{
+       u8 reg;
+
+       reg = snd_sof_dsp_read8(sdev, bar, offset);
+       reg &= ~mask;
+       reg |= value;
+       snd_sof_dsp_write8(sdev, bar, offset, reg);
 }
 
 /* block IO */
index 62092e2..7306a26 100644 (file)
@@ -826,6 +826,10 @@ int sof_machine_check(struct snd_sof_dev *sdev)
        if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
                const struct snd_sof_of_mach *of_mach;
 
+               if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+                   sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+                       goto nocodec;
+
                /* find machine */
                mach = snd_sof_machine_select(sdev);
                if (mach) {
@@ -848,6 +852,7 @@ int sof_machine_check(struct snd_sof_dev *sdev)
                dev_warn(sdev->dev, "Force to use nocodec mode\n");
        }
 
+nocodec:
        /* select nocodec mode */
        dev_warn(sdev->dev, "Using nocodec machine driver\n");
        mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
index 4284ea2..1b5b3ea 100644 (file)
 
 #define SOF_AUDIO_PCM_DRV_NAME "sof-audio-component"
 
+/*
+ * The ipc4 firmware only supports up to 8 sink or source pins
+ * per widget, because only 3 bits are used for queue(pin) ID
+ * in ipc4 protocol.
+ */
+#define SOF_WIDGET_MAX_NUM_PINS        8
+
+/* The type of a widget pin is either sink or source */
+#define SOF_PIN_TYPE_SINK      0
+#define SOF_PIN_TYPE_SOURCE    1
+
 /* max number of FE PCMs before BEs */
 #define SOF_BE_PCM_BASE                16
 
@@ -387,6 +398,33 @@ struct snd_sof_widget {
        int num_tuples;
        struct snd_sof_tuple *tuples;
 
+       /*
+        * The allowed range for num_sink/source_pins is [0, SOF_WIDGET_MAX_NUM_PINS].
+        * Widgets may have zero sink or source pins, for example the tone widget has
+        * zero sink pins.
+        */
+       u32 num_sink_pins;
+       u32 num_source_pins;
+
+       /*
+        * The sink/source pin binding array, it takes the form of
+        * [widget_name_connected_to_pin0, widget_name_connected_to_pin1, ...],
+        * with the index as the queue ID.
+        *
+        * The array is used for special pin binding. Note that even if there
+        * is only one sink/source pin requires special pin binding, pin binding
+        * should be defined for all sink/source pins in topology, for pin(s) that
+        * are not used, give the value "NotConnected".
+        *
+        * If pin binding is not defined in topology, nothing to parse in the kernel,
+        * sink_pin_binding and src_pin_binding shall be NULL.
+        */
+       char **sink_pin_binding;
+       char **src_pin_binding;
+
+       struct ida src_queue_ida;
+       struct ida sink_queue_ida;
+
        void *private;          /* core does not touch this */
 };
 
@@ -400,6 +438,9 @@ struct snd_sof_route {
        struct snd_sof_widget *sink_widget;
        bool setup;
 
+       int src_queue_id;
+       int dst_queue_id;
+
        void *private;
 };
 
@@ -531,6 +572,7 @@ int get_token_u16(void *elem, void *object, u32 offset);
 int get_token_comp_format(void *elem, void *object, u32 offset);
 int get_token_dai_type(void *elem, void *object, u32 offset);
 int get_token_uuid(void *elem, void *object, u32 offset);
+int get_token_string(void *elem, void *object, u32 offset);
 int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id,
                          struct snd_sof_tuple *tuples, int num_tuples,
                          size_t object_size, int token_instance_num);
diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c
new file mode 100644 (file)
index 0000000..ef768db
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2019-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+// Code moved to this file by:
+//  Jyri Sarha <jyri.sarha@intel.com>
+//
+
+#include <linux/stddef.h>
+#include <sound/soc.h>
+#include <sound/sof/header.h>
+#include "sof-client.h"
+#include "sof-client-probes.h"
+
+struct sof_probe_dma {
+       unsigned int stream_tag;
+       unsigned int dma_buffer_size;
+} __packed;
+
+struct sof_ipc_probe_dma_add_params {
+       struct sof_ipc_cmd_hdr hdr;
+       unsigned int num_elems;
+       struct sof_probe_dma dma[];
+} __packed;
+
+struct sof_ipc_probe_info_params {
+       struct sof_ipc_reply rhdr;
+       unsigned int num_elems;
+       union {
+               DECLARE_FLEX_ARRAY(struct sof_probe_dma, dma);
+               DECLARE_FLEX_ARRAY(struct sof_probe_point_desc, desc);
+       };
+} __packed;
+
+struct sof_ipc_probe_point_add_params {
+       struct sof_ipc_cmd_hdr hdr;
+       unsigned int num_elems;
+       struct sof_probe_point_desc desc[];
+} __packed;
+
+struct sof_ipc_probe_point_remove_params {
+       struct sof_ipc_cmd_hdr hdr;
+       unsigned int num_elems;
+       unsigned int buffer_id[];
+} __packed;
+
+/**
+ * ipc3_probes_init - initialize data probing
+ * @cdev:              SOF client device
+ * @stream_tag:                Extractor stream tag
+ * @buffer_size:       DMA buffer size to set for extractor
+ *
+ * Host chooses whether extraction is supported or not by providing
+ * valid stream tag to DSP. Once specified, stream described by that
+ * tag will be tied to DSP for extraction for the entire lifetime of
+ * probe.
+ *
+ * Probing is initialized only once and each INIT request must be
+ * matched by DEINIT call.
+ */
+static int ipc3_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
+                           size_t buffer_size)
+{
+       struct sof_ipc_probe_dma_add_params *msg;
+       size_t size = struct_size(msg, dma, 1);
+       struct sof_ipc_reply reply;
+       int ret;
+
+       msg = kmalloc(size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+       msg->hdr.size = size;
+       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
+       msg->num_elems = 1;
+       msg->dma[0].stream_tag = stream_tag;
+       msg->dma[0].dma_buffer_size = buffer_size;
+
+       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+       kfree(msg);
+       return ret;
+}
+
+/**
+ * ipc3_probes_deinit - cleanup after data probing
+ * @cdev:              SOF client device
+ *
+ * Host sends DEINIT request to free previously initialized probe
+ * on DSP side once it is no longer needed. DEINIT only when there
+ * are no probes connected and with all injectors detached.
+ */
+static int ipc3_probes_deinit(struct sof_client_dev *cdev)
+{
+       struct sof_ipc_cmd_hdr msg;
+       struct sof_ipc_reply reply;
+
+       msg.size = sizeof(msg);
+       msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
+
+       return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
+}
+
+static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
+                           void **params, size_t *num_params)
+{
+       size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
+       struct sof_ipc_probe_info_params msg = {{{0}}};
+       struct sof_ipc_probe_info_params *reply;
+       size_t bytes;
+       int ret;
+
+       *params = NULL;
+       *num_params = 0;
+
+       reply = kzalloc(max_msg_size, GFP_KERNEL);
+       if (!reply)
+               return -ENOMEM;
+       msg.rhdr.hdr.size = sizeof(msg);
+       msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
+
+       ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
+       if (ret < 0 || reply->rhdr.error < 0)
+               goto exit;
+
+       if (!reply->num_elems)
+               goto exit;
+
+       if (cmd == SOF_IPC_PROBE_DMA_INFO)
+               bytes = sizeof(reply->dma[0]);
+       else
+               bytes = sizeof(reply->desc[0]);
+       bytes *= reply->num_elems;
+       *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
+       if (!*params) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+       *num_params = reply->num_elems;
+
+exit:
+       kfree(reply);
+       return ret;
+}
+
+/**
+ * ipc3_probes_points_info - retrieve list of active probe points
+ * @cdev:              SOF client device
+ * @desc:      Returned list of active probes
+ * @num_desc:  Returned count of active probes
+ *
+ * Host sends PROBE_POINT_INFO request to obtain list of active probe
+ * points, valid for disconnection when given probe is no longer
+ * required.
+ */
+static int ipc3_probes_points_info(struct sof_client_dev *cdev,
+                                  struct sof_probe_point_desc **desc,
+                                  size_t *num_desc)
+{
+       return ipc3_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
+                              (void **)desc, num_desc);
+}
+
+/**
+ * ipc3_probes_points_add - connect specified probes
+ * @cdev:              SOF client device
+ * @desc:      List of probe points to connect
+ * @num_desc:  Number of elements in @desc
+ *
+ * Dynamically connects to provided set of endpoints. Immediately
+ * after connection is established, host must be prepared to
+ * transfer data from or to target stream given the probing purpose.
+ *
+ * Each probe point should be removed using PROBE_POINT_REMOVE
+ * request when no longer needed.
+ */
+static int ipc3_probes_points_add(struct sof_client_dev *cdev,
+                                 struct sof_probe_point_desc *desc,
+                                 size_t num_desc)
+{
+       struct sof_ipc_probe_point_add_params *msg;
+       size_t size = struct_size(msg, desc, num_desc);
+       struct sof_ipc_reply reply;
+       int ret;
+
+       msg = kmalloc(size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+       msg->hdr.size = size;
+       msg->num_elems = num_desc;
+       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
+       memcpy(&msg->desc[0], desc, size - sizeof(*msg));
+
+       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+       kfree(msg);
+       return ret;
+}
+
+/**
+ * ipc3_probes_points_remove - disconnect specified probes
+ * @cdev:              SOF client device
+ * @buffer_id:         List of probe points to disconnect
+ * @num_buffer_id:     Number of elements in @desc
+ *
+ * Removes previously connected probes from list of active probe
+ * points and frees all resources on DSP side.
+ */
+static int ipc3_probes_points_remove(struct sof_client_dev *cdev,
+                                    unsigned int *buffer_id,
+                                    size_t num_buffer_id)
+{
+       struct sof_ipc_probe_point_remove_params *msg;
+       size_t size = struct_size(msg, buffer_id, num_buffer_id);
+       struct sof_ipc_reply reply;
+       int ret;
+
+       msg = kmalloc(size, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+       msg->hdr.size = size;
+       msg->num_elems = num_buffer_id;
+       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
+       memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
+
+       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
+       kfree(msg);
+       return ret;
+}
+
+const struct sof_probes_ipc_ops ipc3_probe_ops =  {
+       .init = ipc3_probes_init,
+       .deinit = ipc3_probes_deinit,
+       .points_info = ipc3_probes_points_info,
+       .points_add = ipc3_probes_points_add,
+       .points_remove = ipc3_probes_points_remove,
+};
diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c
new file mode 100644 (file)
index 0000000..66fa7c2
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2019-2022 Intel Corporation. All rights reserved.
+//
+// Author: Jyri Sarha <jyri.sarha@intel.com>
+//
+
+#include <sound/soc.h>
+#include <sound/sof/ipc4/header.h>
+#include <uapi/sound/sof/header.h>
+#include "sof-priv.h"
+#include "ipc4-priv.h"
+#include "sof-client.h"
+#include "sof-client-probes.h"
+
+enum sof_ipc4_dma_type {
+       SOF_IPC4_DMA_HDA_HOST_OUTPUT = 0,
+       SOF_IPC4_DMA_HDA_HOST_INPUT = 1,
+       SOF_IPC4_DMA_HDA_LINK_OUTPUT = 8,
+       SOF_IPC4_DMA_HDA_LINK_INPUT = 9,
+       SOF_IPC4_DMA_DMIC_LINK_INPUT = 11,
+       SOF_IPC4_DMA_I2S_LINK_OUTPUT = 12,
+       SOF_IPC4_DMA_I2S_LINK_INPUT = 13,
+};
+
+enum sof_ipc4_probe_runtime_param {
+       SOF_IPC4_PROBE_INJECTION_DMA = 1,
+       SOF_IPC4_PROBE_INJECTION_DMA_DETACH,
+       SOF_IPC4_PROBE_POINTS,
+       SOF_IPC4_PROBE_POINTS_DISCONNECT,
+};
+
+struct sof_ipc4_probe_gtw_cfg {
+       u32 node_id;
+       u32 dma_buffer_size;
+} __packed __aligned(4);
+
+#define SOF_IPC4_PROBE_NODE_ID_INDEX(x)                ((x) & GENMASK(7, 0))
+#define SOF_IPC4_PROBE_NODE_ID_TYPE(x)         (((x) << 8) & GENMASK(12, 8))
+
+struct sof_ipc4_probe_cfg {
+       struct sof_ipc4_base_module_cfg base;
+       struct sof_ipc4_probe_gtw_cfg gtw_cfg;
+} __packed __aligned(4);
+
+enum sof_ipc4_probe_type {
+       SOF_IPC4_PROBE_TYPE_INPUT = 0,
+       SOF_IPC4_PROBE_TYPE_OUTPUT,
+       SOF_IPC4_PROBE_TYPE_INTERNAL
+};
+
+struct sof_ipc4_probe_point {
+       u32 point_id;
+       u32 purpose;
+       u32 stream_tag;
+} __packed __aligned(4);
+
+#define INVALID_PIPELINE_ID      0xFF
+
+/**
+ * sof_ipc4_probe_get_module_info - Get IPC4 module info for probe module
+ * @cdev:              SOF client device
+ * @return:            Pointer to IPC4 probe module info
+ *
+ * Look up the IPC4 probe module info based on the hard coded uuid and
+ * store the value for the future calls.
+ */
+static struct sof_man4_module *sof_ipc4_probe_get_module_info(struct sof_client_dev *cdev)
+{
+       struct sof_probes_priv *priv = cdev->data;
+       struct device *dev = &cdev->auxdev.dev;
+       static const guid_t probe_uuid =
+               GUID_INIT(0x7CAD0808, 0xAB10, 0xCD23,
+                         0xEF, 0x45, 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF);
+
+       if (!priv->ipc_priv) {
+               struct sof_ipc4_fw_module *fw_module =
+                       sof_client_ipc4_find_module(cdev, &probe_uuid);
+
+               if (!fw_module) {
+                       dev_err(dev, "%s: no matching uuid found", __func__);
+                       return NULL;
+               }
+
+               priv->ipc_priv = &fw_module->man4_module_entry;
+       }
+
+       return (struct sof_man4_module *)priv->ipc_priv;
+}
+
+/**
+ * ipc4_probes_init - initialize data probing
+ * @cdev:              SOF client device
+ * @stream_tag:                Extractor stream tag
+ * @buffer_size:       DMA buffer size to set for extractor
+ * @return:            0 on success, negative error code on error
+ *
+ * Host chooses whether extraction is supported or not by providing
+ * valid stream tag to DSP. Once specified, stream described by that
+ * tag will be tied to DSP for extraction for the entire lifetime of
+ * probe.
+ *
+ * Probing is initialized only once and each INIT request must be
+ * matched by DEINIT call.
+ */
+static int ipc4_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
+                           size_t buffer_size)
+{
+       struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+       struct sof_ipc4_msg msg;
+       struct sof_ipc4_probe_cfg cfg;
+
+       if (!mentry)
+               return -ENODEV;
+
+       memset(&cfg, '\0', sizeof(cfg));
+       cfg.gtw_cfg.node_id = SOF_IPC4_PROBE_NODE_ID_INDEX(stream_tag - 1) |
+               SOF_IPC4_PROBE_NODE_ID_TYPE(SOF_IPC4_DMA_HDA_HOST_INPUT);
+
+       cfg.gtw_cfg.dma_buffer_size = buffer_size;
+
+       msg.primary = mentry->id;
+       msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+       msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
+       msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
+
+       msg.data_size = sizeof(cfg);
+       msg.data_ptr = &cfg;
+
+       return sof_client_ipc_tx_message(cdev, &msg, NULL, 0);
+}
+
+/**
+ * ipc4_probes_deinit - cleanup after data probing
+ * @cdev:              SOF client device
+ * @return:            0 on success, negative error code on error
+ *
+ * Host sends DEINIT request to free previously initialized probe
+ * on DSP side once it is no longer needed. DEINIT only when there
+ * are no probes connected and with all injectors detached.
+ */
+static int ipc4_probes_deinit(struct sof_client_dev *cdev)
+{
+       struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+       struct sof_ipc4_msg msg;
+
+       msg.primary = mentry->id;
+       msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE);
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+       msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
+       msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
+
+       msg.data_size = 0;
+       msg.data_ptr = NULL;
+
+       return sof_client_ipc_tx_message(cdev, &msg, NULL, 0);
+}
+
+/**
+ * ipc4_probes_points_info - retrieve list of active probe points
+ * @cdev:      SOF client device
+ * @desc:      Returned list of active probes
+ * @num_desc:  Returned count of active probes
+ * @return:    0 on success, negative error code on error
+ *
+ * Dummy implementation returning empty list of probes.
+ */
+static int ipc4_probes_points_info(struct sof_client_dev *cdev,
+                                  struct sof_probe_point_desc **desc,
+                                  size_t *num_desc)
+{
+       /* TODO: Firmware side implementation needed first */
+       *desc = NULL;
+       *num_desc = 0;
+       return 0;
+}
+
+/**
+ * ipc4_probes_points_add - connect specified probes
+ * @cdev:      SOF client device
+ * @desc:      List of probe points to connect
+ * @num_desc:  Number of elements in @desc
+ * @return:    0 on success, negative error code on error
+ *
+ * Translates the generic probe point presentation to an IPC4
+ * message to dynamically connect the provided set of endpoints.
+ */
+static int ipc4_probes_points_add(struct sof_client_dev *cdev,
+                                 struct sof_probe_point_desc *desc,
+                                 size_t num_desc)
+{
+       struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+       struct sof_ipc4_probe_point *points;
+       struct sof_ipc4_msg msg;
+       int i, ret;
+
+       /* The sof_probe_point_desc and sof_ipc4_probe_point structs
+        * are of same size and even the integers are the same in the
+        * same order, and similar meaning, but since there is no
+        * performance issue I wrote the conversion explicitly open for
+        * future development.
+        */
+       points = kcalloc(num_desc, sizeof(*points), GFP_KERNEL);
+       if (!points)
+               return -ENOMEM;
+
+       for (i = 0; i < num_desc; i++) {
+               points[i].point_id = desc[i].buffer_id;
+               points[i].purpose = desc[i].purpose;
+               points[i].stream_tag = desc[i].stream_tag;
+       }
+
+       msg.primary = mentry->id;
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS);
+
+       msg.data_size = sizeof(*points) * num_desc;
+       msg.data_ptr = points;
+
+       ret = sof_client_ipc_set_get_data(cdev, &msg, true);
+
+       kfree(points);
+
+       return ret;
+}
+
+/**
+ * ipc4_probes_points_remove - disconnect specified probes
+ * @cdev:              SOF client device
+ * @buffer_id:         List of probe points to disconnect
+ * @num_buffer_id:     Number of elements in @desc
+ * @return:            0 on success, negative error code on error
+ *
+ * Converts the generic buffer_id to IPC4 probe_point_id and remove
+ * the probe points with an IPC4 for message.
+ */
+static int ipc4_probes_points_remove(struct sof_client_dev *cdev,
+                                    unsigned int *buffer_id, size_t num_buffer_id)
+{
+       struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
+       struct sof_ipc4_msg msg;
+       u32 *probe_point_ids;
+       int i, ret;
+
+       probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids),
+                                 GFP_KERNEL);
+       if (!probe_point_ids)
+               return -ENOMEM;
+
+       for (i = 0; i < num_buffer_id; i++)
+               probe_point_ids[i] = buffer_id[i];
+
+       msg.primary = mentry->id;
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       msg.extension =
+               SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_PROBE_POINTS_DISCONNECT);
+
+       msg.data_size = num_buffer_id * sizeof(*probe_point_ids);
+       msg.data_ptr = probe_point_ids;
+
+       ret = sof_client_ipc_set_get_data(cdev, &msg, true);
+
+       kfree(probe_point_ids);
+
+       return ret;
+}
+
+const struct sof_probes_ipc_ops ipc4_probe_ops =  {
+       .init = ipc4_probes_init,
+       .deinit = ipc4_probes_deinit,
+       .points_info = ipc4_probes_points_info,
+       .points_add = ipc4_probes_points_add,
+       .points_remove = ipc4_probes_points_remove,
+};
index ddeabbb..fff1268 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/string_helpers.h>
+#include <linux/stddef.h>
 
 #include <sound/soc.h>
 #include <sound/sof/header.h>
@@ -29,233 +30,6 @@ static bool __read_mostly sof_probes_enabled;
 module_param_named(enable, sof_probes_enabled, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable SOF probes support");
 
-struct sof_probes_priv {
-       struct dentry *dfs_points;
-       struct dentry *dfs_points_remove;
-       u32 extractor_stream_tag;
-       struct snd_soc_card card;
-
-       const struct sof_probes_host_ops *host_ops;
-};
-
-struct sof_probe_point_desc {
-       unsigned int buffer_id;
-       unsigned int purpose;
-       unsigned int stream_tag;
-} __packed;
-
-struct sof_probe_dma {
-       unsigned int stream_tag;
-       unsigned int dma_buffer_size;
-} __packed;
-
-struct sof_ipc_probe_dma_add_params {
-       struct sof_ipc_cmd_hdr hdr;
-       unsigned int num_elems;
-       struct sof_probe_dma dma[];
-} __packed;
-
-struct sof_ipc_probe_info_params {
-       struct sof_ipc_reply rhdr;
-       unsigned int num_elems;
-       union {
-               struct sof_probe_dma dma[0];
-               struct sof_probe_point_desc desc[0];
-       };
-} __packed;
-
-struct sof_ipc_probe_point_add_params {
-       struct sof_ipc_cmd_hdr hdr;
-       unsigned int num_elems;
-       struct sof_probe_point_desc desc[];
-} __packed;
-
-struct sof_ipc_probe_point_remove_params {
-       struct sof_ipc_cmd_hdr hdr;
-       unsigned int num_elems;
-       unsigned int buffer_id[];
-} __packed;
-
-/**
- * sof_probes_init - initialize data probing
- * @cdev:              SOF client device
- * @stream_tag:                Extractor stream tag
- * @buffer_size:       DMA buffer size to set for extractor
- *
- * Host chooses whether extraction is supported or not by providing
- * valid stream tag to DSP. Once specified, stream described by that
- * tag will be tied to DSP for extraction for the entire lifetime of
- * probe.
- *
- * Probing is initialized only once and each INIT request must be
- * matched by DEINIT call.
- */
-static int sof_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
-                          size_t buffer_size)
-{
-       struct sof_ipc_probe_dma_add_params *msg;
-       size_t size = struct_size(msg, dma, 1);
-       struct sof_ipc_reply reply;
-       int ret;
-
-       msg = kmalloc(size, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-       msg->hdr.size = size;
-       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
-       msg->num_elems = 1;
-       msg->dma[0].stream_tag = stream_tag;
-       msg->dma[0].dma_buffer_size = buffer_size;
-
-       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
-       kfree(msg);
-       return ret;
-}
-
-/**
- * sof_probes_deinit - cleanup after data probing
- * @cdev:              SOF client device
- *
- * Host sends DEINIT request to free previously initialized probe
- * on DSP side once it is no longer needed. DEINIT only when there
- * are no probes connected and with all injectors detached.
- */
-static int sof_probes_deinit(struct sof_client_dev *cdev)
-{
-       struct sof_ipc_cmd_hdr msg;
-       struct sof_ipc_reply reply;
-
-       msg.size = sizeof(msg);
-       msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
-
-       return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
-}
-
-static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
-                          void **params, size_t *num_params)
-{
-       size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
-       struct sof_ipc_probe_info_params msg = {{{0}}};
-       struct sof_ipc_probe_info_params *reply;
-       size_t bytes;
-       int ret;
-
-       *params = NULL;
-       *num_params = 0;
-
-       reply = kzalloc(max_msg_size, GFP_KERNEL);
-       if (!reply)
-               return -ENOMEM;
-       msg.rhdr.hdr.size = sizeof(msg);
-       msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
-
-       ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
-       if (ret < 0 || reply->rhdr.error < 0)
-               goto exit;
-
-       if (!reply->num_elems)
-               goto exit;
-
-       if (cmd == SOF_IPC_PROBE_DMA_INFO)
-               bytes = sizeof(reply->dma[0]);
-       else
-               bytes = sizeof(reply->desc[0]);
-       bytes *= reply->num_elems;
-       *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
-       if (!*params) {
-               ret = -ENOMEM;
-               goto exit;
-       }
-       *num_params = reply->num_elems;
-
-exit:
-       kfree(reply);
-       return ret;
-}
-
-/**
- * sof_probes_points_info - retrieve list of active probe points
- * @cdev:              SOF client device
- * @desc:      Returned list of active probes
- * @num_desc:  Returned count of active probes
- *
- * Host sends PROBE_POINT_INFO request to obtain list of active probe
- * points, valid for disconnection when given probe is no longer
- * required.
- */
-static int sof_probes_points_info(struct sof_client_dev *cdev,
-                                 struct sof_probe_point_desc **desc,
-                                 size_t *num_desc)
-{
-       return sof_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
-                              (void **)desc, num_desc);
-}
-
-/**
- * sof_probes_points_add - connect specified probes
- * @cdev:              SOF client device
- * @desc:      List of probe points to connect
- * @num_desc:  Number of elements in @desc
- *
- * Dynamically connects to provided set of endpoints. Immediately
- * after connection is established, host must be prepared to
- * transfer data from or to target stream given the probing purpose.
- *
- * Each probe point should be removed using PROBE_POINT_REMOVE
- * request when no longer needed.
- */
-static int sof_probes_points_add(struct sof_client_dev *cdev,
-                                struct sof_probe_point_desc *desc,
-                                size_t num_desc)
-{
-       struct sof_ipc_probe_point_add_params *msg;
-       size_t size = struct_size(msg, desc, num_desc);
-       struct sof_ipc_reply reply;
-       int ret;
-
-       msg = kmalloc(size, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-       msg->hdr.size = size;
-       msg->num_elems = num_desc;
-       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
-       memcpy(&msg->desc[0], desc, size - sizeof(*msg));
-
-       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
-       kfree(msg);
-       return ret;
-}
-
-/**
- * sof_probes_points_remove - disconnect specified probes
- * @cdev:              SOF client device
- * @buffer_id:         List of probe points to disconnect
- * @num_buffer_id:     Number of elements in @desc
- *
- * Removes previously connected probes from list of active probe
- * points and frees all resources on DSP side.
- */
-static int sof_probes_points_remove(struct sof_client_dev *cdev,
-                                   unsigned int *buffer_id, size_t num_buffer_id)
-{
-       struct sof_ipc_probe_point_remove_params *msg;
-       size_t size = struct_size(msg, buffer_id, num_buffer_id);
-       struct sof_ipc_reply reply;
-       int ret;
-
-       msg = kmalloc(size, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-       msg->hdr.size = size;
-       msg->num_elems = num_buffer_id;
-       msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
-       memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
-
-       ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
-       kfree(msg);
-       return ret;
-}
-
 static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
                                    struct snd_soc_dai *dai)
 {
@@ -289,23 +63,24 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
        struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
        struct sof_probes_priv *priv = cdev->data;
        const struct sof_probes_host_ops *ops = priv->host_ops;
+       const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
        struct sof_probe_point_desc *desc;
        size_t num_desc;
        int i, ret;
 
        /* disconnect all probe points */
-       ret = sof_probes_points_info(cdev, &desc, &num_desc);
+       ret = ipc->points_info(cdev, &desc, &num_desc);
        if (ret < 0) {
                dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
                goto exit;
        }
 
        for (i = 0; i < num_desc; i++)
-               sof_probes_points_remove(cdev, &desc[i].buffer_id, 1);
+               ipc->points_remove(cdev, &desc[i].buffer_id, 1);
        kfree(desc);
 
 exit:
-       ret = sof_probes_deinit(cdev);
+       ret = ipc->deinit(cdev);
        if (ret < 0)
                dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
 
@@ -328,6 +103,7 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
        struct snd_compr_runtime *rtd = cstream->runtime;
        struct sof_probes_priv *priv = cdev->data;
        const struct sof_probes_host_ops *ops = priv->host_ops;
+       const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
        int ret;
 
        cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
@@ -340,7 +116,7 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
        if (ret)
                return ret;
 
-       ret = sof_probes_init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
+       ret = ipc->init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
        if (ret < 0) {
                dev_err(dai->dev, "Failed to init probe: %d\n", ret);
                return ret;
@@ -419,6 +195,7 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
        struct sof_probes_priv *priv = cdev->data;
        struct device *dev = &cdev->auxdev.dev;
        struct sof_probe_point_desc *desc;
+       const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
        int remaining, offset;
        size_t num_desc;
        char *buf;
@@ -439,7 +216,7 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
                goto exit;
        }
 
-       ret = sof_probes_points_info(cdev, &desc, &num_desc);
+       ret = ipc->points_info(cdev, &desc, &num_desc);
        if (ret < 0)
                goto exit;
 
@@ -475,6 +252,7 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
 {
        struct sof_client_dev *cdev = file->private_data;
        struct sof_probes_priv *priv = cdev->data;
+       const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
        struct device *dev = &cdev->auxdev.dev;
        struct sof_probe_point_desc *desc;
        u32 num_elems, *array;
@@ -505,7 +283,7 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
                goto exit;
        }
 
-       ret = sof_probes_points_add(cdev, desc, bytes / sizeof(*desc));
+       ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
        if (!ret)
                ret = count;
 
@@ -533,6 +311,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
 {
        struct sof_client_dev *cdev = file->private_data;
        struct sof_probes_priv *priv = cdev->data;
+       const struct sof_probes_ipc_ops *ipc = priv->ipc_ops;
        struct device *dev = &cdev->auxdev.dev;
        int ret, err;
        u32 *array;
@@ -552,7 +331,7 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
                goto exit;
        }
 
-       ret = sof_probes_points_remove(cdev, &array[1], array[0]);
+       ret = ipc->points_remove(cdev, &array[1], array[0]);
        if (!ret)
                ret = count;
 
@@ -620,28 +399,39 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
        if (!sof_probes_enabled)
                return -ENXIO;
 
-       /* only ipc3 is supported */
-       if (sof_client_get_ipc_type(cdev) != SOF_IPC)
-               return -ENXIO;
-
-       if (!dev->platform_data) {
+       ops = dev_get_platdata(dev);
+       if (!ops) {
                dev_err(dev, "missing platform data\n");
                return -ENODEV;
        }
+       if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
+           !ops->pointer) {
+               dev_err(dev, "missing platform callback(s)\n");
+               return -ENODEV;
+       }
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       ops = dev->platform_data;
+       priv->host_ops = ops;
 
-       if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
-           !ops->pointer) {
-               dev_err(dev, "missing platform callback(s)\n");
+       switch (sof_client_get_ipc_type(cdev)) {
+#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4
+       case SOF_INTEL_IPC4:
+               priv->ipc_ops = &ipc4_probe_ops;
+               break;
+#endif
+#ifdef CONFIG_SND_SOC_SOF_IPC3
+       case SOF_IPC:
+               priv->ipc_ops = &ipc3_probe_ops;
+               break;
+#endif
+       default:
+               dev_err(dev, "Matching IPC ops not found.");
                return -ENODEV;
        }
 
-       priv->host_ops = ops;
        cdev->data = priv;
 
        /* register probes component driver and dai */
index 9e43f3c..da04d65 100644 (file)
@@ -28,4 +28,38 @@ struct sof_probes_host_ops {
                       struct snd_soc_dai *dai);
 };
 
+struct sof_probe_point_desc {
+       unsigned int buffer_id;
+       unsigned int purpose;
+       unsigned int stream_tag;
+} __packed;
+
+struct sof_probes_ipc_ops {
+       int (*init)(struct sof_client_dev *cdev, u32 stream_tag,
+                   size_t buffer_size);
+       int (*deinit)(struct sof_client_dev *cdev);
+       int (*points_info)(struct sof_client_dev *cdev,
+                          struct sof_probe_point_desc **desc,
+                          size_t *num_desc);
+       int (*points_add)(struct sof_client_dev *cdev,
+                         struct sof_probe_point_desc *desc,
+                         size_t num_desc);
+       int (*points_remove)(struct sof_client_dev *cdev,
+                            unsigned int *buffer_id, size_t num_buffer_id);
+};
+
+extern const struct sof_probes_ipc_ops ipc3_probe_ops;
+extern const struct sof_probes_ipc_ops ipc4_probe_ops;
+
+struct sof_probes_priv {
+       struct dentry *dfs_points;
+       struct dentry *dfs_points_remove;
+       u32 extractor_stream_tag;
+       struct snd_soc_card card;
+       void *ipc_priv;
+
+       const struct sof_probes_host_ops *host_ops;
+       const struct sof_probes_ipc_ops *ipc_ops;
+};
+
 #endif
index 125aa21..9017f08 100644 (file)
@@ -16,6 +16,7 @@
 #include "ops.h"
 #include "sof-client.h"
 #include "sof-priv.h"
+#include "ipc4-priv.h"
 
 /**
  * struct sof_ipc_event_entry - IPC client event description
@@ -265,6 +266,39 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
 }
 EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT);
 
+int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
+                               bool set)
+{
+       if (cdev->sdev->pdata->ipc_type == SOF_IPC) {
+               struct sof_ipc_cmd_hdr *hdr = ipc_msg;
+
+               return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg, hdr->size,
+                                           set);
+       } else if (cdev->sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+               struct sof_ipc4_msg *msg = ipc_msg;
+
+               return sof_ipc_set_get_data(cdev->sdev->ipc, ipc_msg,
+                                           msg->data_size, set);
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT);
+
+#ifdef CONFIG_SND_SOC_SOF_INTEL_IPC4
+struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid)
+{
+       struct snd_sof_dev *sdev = c->sdev;
+
+       if (sdev->pdata->ipc_type == SOF_INTEL_IPC4)
+               return sof_ipc4_find_module_by_uuid(sdev, uuid);
+       dev_err(sdev->dev, "Only supported with IPC4\n");
+
+       return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT);
+#endif
+
 int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
 {
        struct auxiliary_driver *adrv;
index 46b215d..2589714 100644 (file)
@@ -13,6 +13,8 @@ struct sof_ipc_cmd_hdr;
 struct snd_sof_dev;
 struct dentry;
 
+struct sof_ipc4_fw_module;
+
 /**
  * struct sof_client_dev - SOF client device
  * @auxdev:    auxiliary device
@@ -37,6 +39,10 @@ struct sof_client_dev {
 
 int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
                              void *reply_data, size_t reply_bytes);
+int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
+                               bool set);
+
+struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *u);
 
 struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev);
 struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev);
index 643fd10..f5ece43 100644 (file)
@@ -28,6 +28,10 @@ static char *fw_filename;
 module_param(fw_filename, charp, 0444);
 MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware.");
 
+static char *lib_path;
+module_param(lib_path, charp, 0444);
+MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries.");
+
 static char *tplg_path;
 module_param(tplg_path, charp, 0444);
 MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
@@ -272,6 +276,28 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                        sof_pdata->desc->default_fw_path[sof_pdata->ipc_type];
        }
 
+       if (lib_path) {
+               sof_pdata->fw_lib_prefix = lib_path;
+
+               dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
+                       sof_pdata->fw_lib_prefix);
+
+       } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) {
+               if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
+                       sof_pdata->fw_lib_prefix =
+                               devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+                                       sof_pdata->desc->default_lib_path[sof_pdata->ipc_type],
+                                       "community");
+
+                       dev_dbg(dev,
+                               "Platform uses community key, changed fw_lib path to %s\n",
+                               sof_pdata->fw_lib_prefix);
+               } else {
+                       sof_pdata->fw_lib_prefix =
+                               sof_pdata->desc->default_lib_path[sof_pdata->ipc_type];
+               }
+       }
+
        if (tplg_path)
                sof_pdata->tplg_filename_prefix = tplg_path;
        else
index de08825..6760fd8 100644 (file)
@@ -43,6 +43,9 @@
 #define SOF_DBG_PRINT_IPC_SUCCESS_LOGS         BIT(9) /* print IPC success
                                                        * in dmesg logs
                                                        */
+#define SOF_DBG_FORCE_NOCODEC                  BIT(10) /* ignore all codec-related
+                                                        * configurations
+                                                        */
 
 /* Flag definitions used for controlling the DSP dump behavior */
 #define SOF_DBG_DUMP_REGS              BIT(0)
@@ -136,6 +139,17 @@ struct snd_sof_platform_stream_params {
        bool cont_update_posn;
 };
 
+/**
+ * struct sof_firmware - Container struct for SOF firmware
+ * @fw:                        Pointer to the firmware
+ * @payload_offset:    Offset of the data within the loaded firmware image to be
+ *                     loaded to the DSP (skipping for example ext_manifest section)
+ */
+struct sof_firmware {
+       const struct firmware *fw;
+       u32 payload_offset;
+};
+
 /*
  * SOF DSP HW abstraction operations.
  * Used to abstract DSP HW architecture and any IO busses between host CPU
@@ -160,6 +174,10 @@ struct snd_sof_dsp_ops {
         * TODO: consider removing these operations and calling respective
         * implementations directly
         */
+       void (*write8)(struct snd_sof_dev *sof_dev, void __iomem *addr,
+                      u8 value); /* optional */
+       u8 (*read8)(struct snd_sof_dev *sof_dev,
+                   void __iomem *addr); /* optional */
        void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr,
                      u32 value); /* optional */
        u32 (*read)(struct snd_sof_dev *sof_dev,
@@ -410,15 +428,11 @@ struct sof_ipc_pm_ops {
  *                     DSP.
  *                     The function implements generic, hardware independent way
  *                     of loading the initial firmware and its modules (if any).
- * @query_fw_configuration: Optional function pointer to query information and
- *                     configuration from the booted firmware.
- *                     Executed after the first successful firmware boot.
  */
 struct sof_ipc_fw_loader_ops {
        int (*validate)(struct snd_sof_dev *sdev);
        size_t (*parse_ext_manifest)(struct snd_sof_dev *sdev);
        int (*load_fw_to_dsp)(struct snd_sof_dev *sdev);
-       int (*query_fw_configuration)(struct snd_sof_dev *sdev);
 };
 
 struct sof_ipc_tplg_ops;
@@ -432,6 +446,11 @@ struct sof_ipc_pcm_ops;
  * @fw_loader: Pointer to Firmware Loader ops
  * @fw_tracing:        Pointer to Firmware tracing ops
  *
+ * @init:      Optional pointer for IPC related initialization
+ * @exit:      Optional pointer for IPC related cleanup
+ * @post_fw_boot: Optional pointer to execute IPC related tasks after firmware
+ *             boot.
+ *
  * @tx_msg:    Function pointer for sending a 'short' IPC message
  * @set_get_data: Function pointer for set/get data ('large' IPC message). This
  *             function may split up the 'large' message and use the @tx_msg
@@ -453,6 +472,10 @@ struct sof_ipc_ops {
        const struct sof_ipc_fw_loader_ops *fw_loader;
        const struct sof_ipc_fw_tracing_ops *fw_tracing;
 
+       int (*init)(struct snd_sof_dev *sdev);
+       void (*exit)(struct snd_sof_dev *sdev);
+       int (*post_fw_boot)(struct snd_sof_dev *sdev);
+
        int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
                      void *reply_data, size_t reply_bytes, bool no_pm);
        int (*set_get_data)(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
@@ -487,6 +510,9 @@ struct snd_sof_dev {
        spinlock_t ipc_lock;    /* lock for IPC users */
        spinlock_t hw_lock;     /* lock for HW IO access */
 
+       /* Main, Base firmware image */
+       struct sof_firmware basefw;
+
        /*
         * ASoC components. plat_drv fields are set dynamically so
         * can't use const
@@ -654,6 +680,8 @@ static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
 }
 int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
                       void *reply_data, size_t reply_bytes);
+int sof_ipc_set_get_data(struct snd_sof_ipc *ipc, void *msg_data,
+                        size_t msg_bytes, bool set);
 int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
                             void *reply_data, size_t reply_bytes);
 int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
index 38855dd..176f64a 100644 (file)
@@ -360,6 +360,21 @@ int get_token_uuid(void *elem, void *object, u32 offset)
        return 0;
 }
 
+/*
+ * The string gets from topology will be stored in heap, the owner only
+ * holds a char* member point to the heap.
+ */
+int get_token_string(void *elem, void *object, u32 offset)
+{
+       /* "dst" here points to the char* member of the owner */
+       char **dst = (char **)((u8 *)object + offset);
+
+       *dst = kstrdup(elem, GFP_KERNEL);
+       if (!*dst)
+               return -ENOMEM;
+       return 0;
+};
+
 int get_token_comp_format(void *elem, void *object, u32 offset)
 {
        u32 *val = (u32 *)((u8 *)object + offset);
@@ -392,6 +407,23 @@ static const struct sof_topology_token led_tokens[] = {
                offsetof(struct snd_sof_led_control, direction)},
 };
 
+static const struct sof_topology_token comp_pin_tokens[] = {
+       {SOF_TKN_COMP_NUM_SINK_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct snd_sof_widget, num_sink_pins)},
+       {SOF_TKN_COMP_NUM_SOURCE_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct snd_sof_widget, num_source_pins)},
+};
+
+static const struct sof_topology_token comp_sink_pin_binding_tokens[] = {
+       {SOF_TKN_COMP_SINK_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+               get_token_string, 0},
+};
+
+static const struct sof_topology_token comp_src_pin_binding_tokens[] = {
+       {SOF_TKN_COMP_SRC_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING,
+               get_token_string, 0},
+};
+
 /**
  * sof_parse_uuid_tokens - Parse multiple sets of UUID tokens
  * @scomp: pointer to soc component
@@ -572,7 +604,7 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
 {
        struct snd_soc_tplg_vendor_string_elem *elem;
        int found = 0;
-       int i, j;
+       int i, j, ret;
 
        /* parse element by element */
        for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
@@ -589,7 +621,9 @@ static int sof_parse_string_tokens(struct snd_soc_component *scomp,
                                continue;
 
                        /* matched - now load token */
-                       tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+                       ret = tokens[j].get_token(elem->string, object, offset + tokens[j].offset);
+                       if (ret < 0)
+                               return ret;
 
                        found++;
                }
@@ -669,6 +703,7 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
        int found = 0;
        int total = 0;
        int asize;
+       int ret;
 
        while (array_size > 0 && total < count * token_instance_num) {
                asize = le32_to_cpu(array->size);
@@ -695,8 +730,15 @@ static int sof_parse_token_sets(struct snd_soc_component *scomp,
                                                       array);
                        break;
                case SND_SOC_TPLG_TUPLE_TYPE_STRING:
-                       found += sof_parse_string_tokens(scomp, object, offset, tokens, count,
-                                                        array);
+
+                       ret = sof_parse_string_tokens(scomp, object, offset, tokens, count,
+                                                     array);
+                       if (ret < 0) {
+                               dev_err(scomp->dev, "error: no memory to copy string token\n");
+                               return ret;
+                       }
+
+                       found += ret;
                        break;
                case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
                case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
@@ -1251,6 +1293,79 @@ err:
        return ret;
 }
 
+static void sof_free_pin_binding(struct snd_sof_widget *swidget,
+                                bool pin_type)
+{
+       char **pin_binding;
+       u32 num_pins;
+       int i;
+
+       if (pin_type == SOF_PIN_TYPE_SINK) {
+               pin_binding = swidget->sink_pin_binding;
+               num_pins = swidget->num_sink_pins;
+       } else {
+               pin_binding = swidget->src_pin_binding;
+               num_pins = swidget->num_source_pins;
+       }
+
+       if (pin_binding) {
+               for (i = 0; i < num_pins; i++)
+                       kfree(pin_binding[i]);
+       }
+
+       kfree(pin_binding);
+}
+
+static int sof_parse_pin_binding(struct snd_sof_widget *swidget,
+                                struct snd_soc_tplg_private *priv, bool pin_type)
+{
+       const struct sof_topology_token *pin_binding_token;
+       char *pin_binding[SOF_WIDGET_MAX_NUM_PINS];
+       int token_count;
+       u32 num_pins;
+       char **pb;
+       int ret;
+       int i;
+
+       if (pin_type == SOF_PIN_TYPE_SINK) {
+               num_pins = swidget->num_sink_pins;
+               pin_binding_token = comp_sink_pin_binding_tokens;
+               token_count = ARRAY_SIZE(comp_sink_pin_binding_tokens);
+       } else {
+               num_pins = swidget->num_source_pins;
+               pin_binding_token = comp_src_pin_binding_tokens;
+               token_count = ARRAY_SIZE(comp_src_pin_binding_tokens);
+       }
+
+       memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *));
+       ret = sof_parse_token_sets(swidget->scomp, pin_binding, pin_binding_token,
+                                  token_count, priv->array, le32_to_cpu(priv->size),
+                                  num_pins, sizeof(char *));
+       if (ret < 0)
+               goto err;
+
+       /* copy pin binding array to swidget only if it is defined in topology */
+       if (pin_binding[0]) {
+               pb = kmemdup(pin_binding, num_pins * sizeof(char *), GFP_KERNEL);
+               if (!pb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               if (pin_type == SOF_PIN_TYPE_SINK)
+                       swidget->sink_pin_binding = pb;
+               else
+                       swidget->src_pin_binding = pb;
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < num_pins; i++)
+               kfree(pin_binding[i]);
+
+       return ret;
+}
+
 /* external widget init - used for any driver specific init */
 static int sof_widget_ready(struct snd_soc_component *scomp, int index,
                            struct snd_soc_dapm_widget *w,
@@ -1259,6 +1374,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
        const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
        const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
+       struct snd_soc_tplg_private *priv = &tw->priv;
        struct snd_sof_widget *swidget;
        struct snd_sof_dai *dai;
        enum sof_tokens *token_list;
@@ -1276,11 +1392,50 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
        swidget->id = w->id;
        swidget->pipeline_id = index;
        swidget->private = NULL;
+       ida_init(&swidget->src_queue_ida);
+       ida_init(&swidget->sink_queue_ida);
 
-       dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
-               swidget->comp_id, index, swidget->id, tw->name,
-               strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
-                       ? tw->sname : "none");
+       ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
+                              ARRAY_SIZE(comp_pin_tokens), priv->array,
+                              le32_to_cpu(priv->size));
+       if (ret < 0) {
+               dev_err(scomp->dev, "failed to parse component pin tokens for %s\n",
+                       w->name);
+               return ret;
+       }
+
+       if (swidget->num_sink_pins > SOF_WIDGET_MAX_NUM_PINS ||
+           swidget->num_source_pins > SOF_WIDGET_MAX_NUM_PINS) {
+               dev_err(scomp->dev, "invalid pins for %s: [sink: %d, src: %d]\n",
+                       swidget->widget->name, swidget->num_sink_pins, swidget->num_source_pins);
+               return -EINVAL;
+       }
+
+       if (swidget->num_sink_pins > 1) {
+               ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK);
+               /* on parsing error, pin binding is not allocated, nothing to free. */
+               if (ret < 0) {
+                       dev_err(scomp->dev, "failed to parse sink pin binding for %s\n",
+                               w->name);
+                       return ret;
+               }
+       }
+
+       if (swidget->num_source_pins > 1) {
+               ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE);
+               /* on parsing error, pin binding is not allocated, nothing to free. */
+               if (ret < 0) {
+                       dev_err(scomp->dev, "failed to parse source pin binding for %s\n",
+                               w->name);
+                       return ret;
+               }
+       }
+
+       dev_dbg(scomp->dev,
+               "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n",
+               swidget->comp_id, w->name, swidget->id, index,
+               swidget->num_sink_pins, swidget->num_source_pins,
+               strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none");
 
        token_list = widget_ops[w->id].token_list;
        token_list_size = widget_ops[w->id].token_list_size;
@@ -1471,6 +1626,12 @@ out:
        if (widget_ops[swidget->id].ipc_free)
                widget_ops[swidget->id].ipc_free(swidget);
 
+       ida_destroy(&swidget->src_queue_ida);
+       ida_destroy(&swidget->sink_queue_ida);
+
+       sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK);
+       sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE);
+
        kfree(swidget->tuples);
 
        /* remove and free swidget object */
index 86cff5a..069c993 100644 (file)
@@ -317,8 +317,7 @@ static int sun50i_dmic_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* Get the addresses */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(base))
                return dev_err_probe(&pdev->dev, PTR_ERR(base),
                                     "get resource failed.\n");
@@ -391,7 +390,7 @@ static const struct dev_pm_ops sun50i_dmic_pm = {
 static struct platform_driver sun50i_dmic_driver = {
        .driver         = {
                .name   = "sun50i-dmic",
-               .of_match_table = of_match_ptr(sun50i_dmic_of_match),
+               .of_match_table = sun50i_dmic_of_match,
                .pm     = &sun50i_dmic_pm,
        },
        .probe          = sun50i_dmic_probe,
index d786daa..eeacb12 100644 (file)
@@ -54,7 +54,7 @@ static const struct tegra210_mbdrc_config mbdrc_init_config = {
        .mode                   = 0, /* Bypass */
        .rms_off                = 48,
        .peak_rms_mode          = 1, /* PEAK */
-       .fliter_structure       = 0, /* All-pass tree */
+       .filter_structure       = 0, /* All-pass tree */
        .shift_ctrl             = 30,
        .frame_size             = 32,
        .channel_mask           = 0x3,
@@ -819,7 +819,7 @@ int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
 
        regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
                TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
-               conf->fliter_structure <<
+               conf->filter_structure <<
                TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
 
        regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
index 4c48da0..76e443a 100644 (file)
@@ -199,7 +199,7 @@ struct tegra210_mbdrc_config {
        unsigned int mode;
        unsigned int rms_off;
        unsigned int peak_rms_mode;
-       unsigned int fliter_structure;
+       unsigned int filter_structure;
        unsigned int shift_ctrl;
        unsigned int frame_size;
        unsigned int channel_mask;
index ca5d1bb..f5ac2ab 100644 (file)
@@ -869,7 +869,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
        if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
                max_active_serializers = 1;
        else
-               max_active_serializers = (channels + slots - 1) / slots;
+               max_active_serializers = DIV_ROUND_UP(channels, slots);
 
        /* Default configuration */
        if (mcasp->version < MCASP_VERSION_3)
@@ -1002,8 +1002,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
         */
        if (mcasp->tdm_mask[stream]) {
                active_slots = hweight32(mcasp->tdm_mask[stream]);
-               active_serializers = (channels + active_slots - 1) /
-                       active_slots;
+               active_serializers = DIV_ROUND_UP(channels, active_slots);
                if (active_serializers == 1)
                        active_slots = channels;
                for (i = 0; i < total_slots; i++) {
@@ -1014,7 +1013,7 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
                        }
                }
        } else {
-               active_serializers = (channels + total_slots - 1) / total_slots;
+               active_serializers = DIV_ROUND_UP(channels, total_slots);
                if (active_serializers == 1)
                        active_slots = channels;
                else