All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] OPE support on Tegra210 and later
@ 2022-05-27 10:26 ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

This series adds support for Output Prcoessing Module (OPE) module on
Tegra210 and later generations of SoCs. OPE is a client of AHUB and it
has sub blocks of PEQ (Parametric Equalizer) and MBDRC (Multi Band
Dynamic Range Compressor) for data processing.

An ASoC component is registered for OPE, which includes PEQ and MBDRC
functions as well. This can be plugged in audio path using ALSA mixer
controls. The series adds necessary binding documentaion, driver and
DT binding patches to enable OPE module on Jetson platforms.


Changelog
=========

  v1 -> v2:
  ---------
    * Use generic node names for OPE, PEQ and MBDRC devices. Update
      binding doc and DT patches for this.
    * Remove redundant nodename rule enforcement from
      OPE, PEQ and MBDRC nodes. Update binding doc patch for this.
    * Fix spaces before binding doc examples and remove '|'
      from binding doc descriptions.

Sameer Pujar (6):
  ASoC: tegra: Add binding doc for OPE module
  ASoC: tegra: Add Tegra210 based OPE driver
  ASoC: tegra: AHUB routes for OPE module
  arm64: defconfig: Build Tegra OPE module
  arm64: tegra: Add OPE device on Tegra210 and later
  arm64: tegra: Enable OPE on various platforms

 .../bindings/sound/nvidia,tegra210-ahub.yaml       |    4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      |   47 +
 .../bindings/sound/nvidia,tegra210-ope.yaml        |   87 ++
 .../bindings/sound/nvidia,tegra210-peq.yaml        |   48 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |   43 +
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |   43 +
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi |   43 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           |   40 +
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  |   43 +
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |   23 +
 arch/arm64/configs/defconfig                       |    1 +
 sound/soc/tegra/Kconfig                            |    9 +
 sound/soc/tegra/Makefile                           |    2 +
 sound/soc/tegra/tegra210_ahub.c                    |   39 +-
 sound/soc/tegra/tegra210_mbdrc.c                   | 1012 ++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h                   |  215 +++++
 sound/soc/tegra/tegra210_ope.c                     |  419 ++++++++
 sound/soc/tegra/tegra210_ope.h                     |   90 ++
 sound/soc/tegra/tegra210_peq.c                     |  434 +++++++++
 sound/soc/tegra/tegra210_peq.h                     |   56 ++
 24 files changed, 2908 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 0/6] OPE support on Tegra210 and later
@ 2022-05-27 10:26 ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

This series adds support for Output Prcoessing Module (OPE) module on
Tegra210 and later generations of SoCs. OPE is a client of AHUB and it
has sub blocks of PEQ (Parametric Equalizer) and MBDRC (Multi Band
Dynamic Range Compressor) for data processing.

An ASoC component is registered for OPE, which includes PEQ and MBDRC
functions as well. This can be plugged in audio path using ALSA mixer
controls. The series adds necessary binding documentaion, driver and
DT binding patches to enable OPE module on Jetson platforms.


Changelog
=========

  v1 -> v2:
  ---------
    * Use generic node names for OPE, PEQ and MBDRC devices. Update
      binding doc and DT patches for this.
    * Remove redundant nodename rule enforcement from
      OPE, PEQ and MBDRC nodes. Update binding doc patch for this.
    * Fix spaces before binding doc examples and remove '|'
      from binding doc descriptions.

Sameer Pujar (6):
  ASoC: tegra: Add binding doc for OPE module
  ASoC: tegra: Add Tegra210 based OPE driver
  ASoC: tegra: AHUB routes for OPE module
  arm64: defconfig: Build Tegra OPE module
  arm64: tegra: Add OPE device on Tegra210 and later
  arm64: tegra: Enable OPE on various platforms

 .../bindings/sound/nvidia,tegra210-ahub.yaml       |    4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      |   47 +
 .../bindings/sound/nvidia,tegra210-ope.yaml        |   87 ++
 .../bindings/sound/nvidia,tegra210-peq.yaml        |   48 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |   43 +
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |   43 +
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi |   43 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           |   40 +
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  |   43 +
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |   23 +
 arch/arm64/configs/defconfig                       |    1 +
 sound/soc/tegra/Kconfig                            |    9 +
 sound/soc/tegra/Makefile                           |    2 +
 sound/soc/tegra/tegra210_ahub.c                    |   39 +-
 sound/soc/tegra/tegra210_mbdrc.c                   | 1012 ++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h                   |  215 +++++
 sound/soc/tegra/tegra210_ope.c                     |  419 ++++++++
 sound/soc/tegra/tegra210_ope.h                     |   90 ++
 sound/soc/tegra/tegra210_peq.c                     |  434 +++++++++
 sound/soc/tegra/tegra210_peq.h                     |   56 ++
 24 files changed, 2908 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 0/6] OPE support on Tegra210 and later
@ 2022-05-27 10:26 ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

This series adds support for Output Prcoessing Module (OPE) module on
Tegra210 and later generations of SoCs. OPE is a client of AHUB and it
has sub blocks of PEQ (Parametric Equalizer) and MBDRC (Multi Band
Dynamic Range Compressor) for data processing.

An ASoC component is registered for OPE, which includes PEQ and MBDRC
functions as well. This can be plugged in audio path using ALSA mixer
controls. The series adds necessary binding documentaion, driver and
DT binding patches to enable OPE module on Jetson platforms.


Changelog
=========

  v1 -> v2:
  ---------
    * Use generic node names for OPE, PEQ and MBDRC devices. Update
      binding doc and DT patches for this.
    * Remove redundant nodename rule enforcement from
      OPE, PEQ and MBDRC nodes. Update binding doc patch for this.
    * Fix spaces before binding doc examples and remove '|'
      from binding doc descriptions.

Sameer Pujar (6):
  ASoC: tegra: Add binding doc for OPE module
  ASoC: tegra: Add Tegra210 based OPE driver
  ASoC: tegra: AHUB routes for OPE module
  arm64: defconfig: Build Tegra OPE module
  arm64: tegra: Add OPE device on Tegra210 and later
  arm64: tegra: Enable OPE on various platforms

 .../bindings/sound/nvidia,tegra210-ahub.yaml       |    4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      |   47 +
 .../bindings/sound/nvidia,tegra210-ope.yaml        |   87 ++
 .../bindings/sound/nvidia,tegra210-peq.yaml        |   48 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |   43 +
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |   43 +
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi |   43 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           |   23 +
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |   84 ++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           |   40 +
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  |   43 +
 arch/arm64/boot/dts/nvidia/tegra234.dtsi           |   23 +
 arch/arm64/configs/defconfig                       |    1 +
 sound/soc/tegra/Kconfig                            |    9 +
 sound/soc/tegra/Makefile                           |    2 +
 sound/soc/tegra/tegra210_ahub.c                    |   39 +-
 sound/soc/tegra/tegra210_mbdrc.c                   | 1012 ++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h                   |  215 +++++
 sound/soc/tegra/tegra210_ope.c                     |  419 ++++++++
 sound/soc/tegra/tegra210_ope.h                     |   90 ++
 sound/soc/tegra/tegra210_peq.c                     |  434 +++++++++
 sound/soc/tegra/tegra210_peq.h                     |   56 ++
 24 files changed, 2908 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

This patch adds YAML schema for DT bindings of Output Processing
Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
binding doc for these blocks are added as well. The OPE will be
registered as an ASoC component and can be plugged into an audio
path as per need via ALSA mixer controls. The DT bindings are
applicable on Tegra210 and later SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
 .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
index 6df6f85..47b6e71 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -110,6 +110,10 @@ patternProperties:
     type: object
     $ref: nvidia,tegra186-asrc.yaml#
 
+  '^processing-engine@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-ope.yaml#
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
new file mode 100644
index 0000000..0d55328
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 MBDRC Device Tree Bindings
+
+description:
+  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
+  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
+  Audio Client Interface (ACIF). MBDRC can be used as a traditional
+  single full band or a dual band or a multi band dynamic processor.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-mbdrc
+      - items:
+          - enum:
+              - nvidia,tegra234-mbdrc
+              - nvidia,tegra194-mbdrc
+              - nvidia,tegra186-mbdrc
+          - const: nvidia,tegra210-mbdrc
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dynamic-range-compressor@702d8200 {
+        compatible = "nvidia,tegra210-mbdrc";
+        reg = <0x702d8200 0x200>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
new file mode 100644
index 0000000..7cbc756
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 OPE Device Tree Bindings
+
+description:
+  The Output Processing Engine (OPE) is one of the AHUB client. It has
+  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
+  sub blocks for data processing.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: name-prefix.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-ope
+      - items:
+          - enum:
+              - nvidia,tegra234-ope
+              - nvidia,tegra194-ope
+              - nvidia,tegra186-ope
+          - const: nvidia,tegra210-ope
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  sound-name-prefix:
+    pattern: "^OPE[1-9]$"
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF (Audio Client Interface) input port. This is connected
+          to corresponding ACIF output port on AHUB (Audio Hub).
+
+      port@1:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF output port. This is connected to corresponding ACIF
+          input port on AHUB.
+
+patternProperties:
+  '^equalizer@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-peq.yaml#
+
+  '^dynamic-range-compressor@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-mbdrc.yaml#
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    processing-engine@702d8000 {
+        compatible = "nvidia,tegra210-ope";
+        reg = <0x702d8000 0x100>;
+        sound-name-prefix = "OPE1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
new file mode 100644
index 0000000..fea4c63
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 PEQ Device Tree Bindings
+
+description:
+  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
+  each filter tuned based on certain parameters. It can be used to
+  equalize the irregularities in the speaker frequency response.
+  PEQ sits inside Output Processing Engine (OPE) which interfaces
+  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-peq
+      - items:
+          - enum:
+              - nvidia,tegra234-peq
+              - nvidia,tegra194-peq
+              - nvidia,tegra186-peq
+          - const: nvidia,tegra210-peq
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    equalizer@702d8100 {
+        compatible = "nvidia,tegra210-peq";
+        reg = <0x702d8100 0x100>;
+    };
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

This patch adds YAML schema for DT bindings of Output Processing
Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
binding doc for these blocks are added as well. The OPE will be
registered as an ASoC component and can be plugged into an audio
path as per need via ALSA mixer controls. The DT bindings are
applicable on Tegra210 and later SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
 .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
index 6df6f85..47b6e71 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -110,6 +110,10 @@ patternProperties:
     type: object
     $ref: nvidia,tegra186-asrc.yaml#
 
+  '^processing-engine@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-ope.yaml#
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
new file mode 100644
index 0000000..0d55328
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 MBDRC Device Tree Bindings
+
+description:
+  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
+  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
+  Audio Client Interface (ACIF). MBDRC can be used as a traditional
+  single full band or a dual band or a multi band dynamic processor.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-mbdrc
+      - items:
+          - enum:
+              - nvidia,tegra234-mbdrc
+              - nvidia,tegra194-mbdrc
+              - nvidia,tegra186-mbdrc
+          - const: nvidia,tegra210-mbdrc
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dynamic-range-compressor@702d8200 {
+        compatible = "nvidia,tegra210-mbdrc";
+        reg = <0x702d8200 0x200>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
new file mode 100644
index 0000000..7cbc756
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 OPE Device Tree Bindings
+
+description:
+  The Output Processing Engine (OPE) is one of the AHUB client. It has
+  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
+  sub blocks for data processing.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: name-prefix.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-ope
+      - items:
+          - enum:
+              - nvidia,tegra234-ope
+              - nvidia,tegra194-ope
+              - nvidia,tegra186-ope
+          - const: nvidia,tegra210-ope
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  sound-name-prefix:
+    pattern: "^OPE[1-9]$"
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF (Audio Client Interface) input port. This is connected
+          to corresponding ACIF output port on AHUB (Audio Hub).
+
+      port@1:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF output port. This is connected to corresponding ACIF
+          input port on AHUB.
+
+patternProperties:
+  '^equalizer@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-peq.yaml#
+
+  '^dynamic-range-compressor@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-mbdrc.yaml#
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    processing-engine@702d8000 {
+        compatible = "nvidia,tegra210-ope";
+        reg = <0x702d8000 0x100>;
+        sound-name-prefix = "OPE1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
new file mode 100644
index 0000000..fea4c63
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 PEQ Device Tree Bindings
+
+description:
+  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
+  each filter tuned based on certain parameters. It can be used to
+  equalize the irregularities in the speaker frequency response.
+  PEQ sits inside Output Processing Engine (OPE) which interfaces
+  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-peq
+      - items:
+          - enum:
+              - nvidia,tegra234-peq
+              - nvidia,tegra194-peq
+              - nvidia,tegra186-peq
+          - const: nvidia,tegra210-peq
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    equalizer@702d8100 {
+        compatible = "nvidia,tegra210-peq";
+        reg = <0x702d8100 0x100>;
+    };
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

This patch adds YAML schema for DT bindings of Output Processing
Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
binding doc for these blocks are added as well. The OPE will be
registered as an ASoC component and can be plugged into an audio
path as per need via ALSA mixer controls. The DT bindings are
applicable on Tegra210 and later SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
 .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
 .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
index 6df6f85..47b6e71 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -110,6 +110,10 @@ patternProperties:
     type: object
     $ref: nvidia,tegra186-asrc.yaml#
 
+  '^processing-engine@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-ope.yaml#
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
new file mode 100644
index 0000000..0d55328
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 MBDRC Device Tree Bindings
+
+description:
+  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
+  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
+  Audio Client Interface (ACIF). MBDRC can be used as a traditional
+  single full band or a dual band or a multi band dynamic processor.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-mbdrc
+      - items:
+          - enum:
+              - nvidia,tegra234-mbdrc
+              - nvidia,tegra194-mbdrc
+              - nvidia,tegra186-mbdrc
+          - const: nvidia,tegra210-mbdrc
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dynamic-range-compressor@702d8200 {
+        compatible = "nvidia,tegra210-mbdrc";
+        reg = <0x702d8200 0x200>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
new file mode 100644
index 0000000..7cbc756
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 OPE Device Tree Bindings
+
+description:
+  The Output Processing Engine (OPE) is one of the AHUB client. It has
+  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
+  sub blocks for data processing.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: name-prefix.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-ope
+      - items:
+          - enum:
+              - nvidia,tegra234-ope
+              - nvidia,tegra194-ope
+              - nvidia,tegra186-ope
+          - const: nvidia,tegra210-ope
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  sound-name-prefix:
+    pattern: "^OPE[1-9]$"
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF (Audio Client Interface) input port. This is connected
+          to corresponding ACIF output port on AHUB (Audio Hub).
+
+      port@1:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF output port. This is connected to corresponding ACIF
+          input port on AHUB.
+
+patternProperties:
+  '^equalizer@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-peq.yaml#
+
+  '^dynamic-range-compressor@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-mbdrc.yaml#
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    processing-engine@702d8000 {
+        compatible = "nvidia,tegra210-ope";
+        reg = <0x702d8000 0x100>;
+        sound-name-prefix = "OPE1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
new file mode 100644
index 0000000..fea4c63
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 PEQ Device Tree Bindings
+
+description:
+  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
+  each filter tuned based on certain parameters. It can be used to
+  equalize the irregularities in the speaker frequency response.
+  PEQ sits inside Output Processing Engine (OPE) which interfaces
+  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-peq
+      - items:
+          - enum:
+              - nvidia,tegra234-peq
+              - nvidia,tegra194-peq
+              - nvidia,tegra186-peq
+          - const: nvidia,tegra210-peq
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    equalizer@702d8100 {
+        compatible = "nvidia,tegra210-peq";
+        reg = <0x702d8100 0x100>;
+    };
+
+...
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/6] ASoC: tegra: Add Tegra210 based OPE driver
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

The Output Processing Engine (OPE) is one of the AHUB client. It has
PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
sub blocks for data processing. The PEQ block gets samples from the MBDRC
block.

This patch registers OPE driver with ASoC framework. The component driver
exposes DAPM widgets, routes and kcontrols for the device. The DAI driver
exposes OPE interfaces, which can be used to connect different components
in the ASoC layer. Makefile and Kconfig support is added to allow build
the driver.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig          |    9 +
 sound/soc/tegra/Makefile         |    2 +
 sound/soc/tegra/tegra210_mbdrc.c | 1012 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h |  215 ++++++++
 sound/soc/tegra/tegra210_ope.c   |  419 ++++++++++++++++
 sound/soc/tegra/tegra210_ope.h   |   90 ++++
 sound/soc/tegra/tegra210_peq.c   |  434 ++++++++++++++++
 sound/soc/tegra/tegra210_peq.h   |   56 +++
 8 files changed, 2237 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2482d98..b6712a3 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -85,6 +85,15 @@ config SND_SOC_TEGRA210_I2S
 	  compatible devices.
 	  Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA210_OPE
+	tristate "Tegra210 OPE module"
+	help
+	  Config to enable the Output Processing Engine (OPE) which includes
+	  Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor
+	  (MBDRC) sub blocks for data processing. It can support up to 8
+	  channels.
+	  Say Y or M if you want to add support for Tegra210 OPE module.
+
 config SND_SOC_TEGRA186_ASRC
 	tristate "Tegra186 ASRC module"
 	help
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 70a498d..b723c78 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -19,6 +19,7 @@ snd-soc-tegra210-sfc-objs := tegra210_sfc.o
 snd-soc-tegra210-amx-objs := tegra210_amx.o
 snd-soc-tegra210-adx-objs := tegra210_adx.o
 snd-soc-tegra210-mixer-objs := tegra210_mixer.o
+snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
+obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
new file mode 100644
index 0000000..7d9da33
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -0,0 +1,1012 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_mbdrc.c - Tegra210 MBDRC driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+
+#define MBDRC_FILTER_REG(reg, id)					    \
+	((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
+
+#define MBDRC_FILTER_REG_DEFAULTS(id)					    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b},  \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+
+static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
+	{ TEGRA210_MBDRC_CFG, 0x0030de51},
+	{ TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
+	{ TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
+
+	MBDRC_FILTER_REG_DEFAULTS(0),
+	MBDRC_FILTER_REG_DEFAULTS(1),
+	MBDRC_FILTER_REG_DEFAULTS(2),
+};
+
+/* Default MBDRC parameters */
+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 */
+	.shift_ctrl		= 30,
+	.frame_size		= 32,
+	.channel_mask		= 0x3,
+	.fa_factor		= 2048,
+	.fr_factor		= 14747,
+
+	.band_params[MBDRC_LOW_BAND] = {
+		.band			= MBDRC_LOW_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1044928780,
+		.in_release_tc		= 138497695,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 80, 20, 6},
+		.out_threshold		= {155, 55, 13, 6},
+		.ratio			= {40960, 8192, 2867, 2048, 410},
+		.makeup_gain		= 4,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 14268942,
+		.gain_release_tc	= 1440547090,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params	= {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			961046798, -2030431983, 1073741824,
+			2030431983, -961046798,
+			/* Band-1 */
+			1030244425, -2099481453, 1073741824,
+			2099481453, -1030244425,
+			/* Band-2 */
+			1067169294, -2136327263, 1073741824,
+			2136327263, -1067169294,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_MID_BAND] = {
+		.band			= MBDRC_MID_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1581413104,
+		.in_release_tc		= 35494783,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			-1005668963, 1073741824, 0,
+			1005668963, 0,
+			/* Band-1 */
+			998437058, -2067742187, 1073741824,
+			2067742187, -998437058,
+			/* Band-2 */
+			1051963422, -2121153948, 1073741824,
+			2121153948, -1051963422,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_HIGH_BAND] = {
+		.band			= MBDRC_HIGH_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 2144750688,
+		.in_release_tc		= 70402888,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-1 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-2 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-3 */
+			-619925131, 1073741824, 0,
+			619925131, 0,
+			/* Band-4 */
+			606839335, -1455425976, 1073741824,
+			1455425976, -606839335,
+			/* Band-5 */
+			917759617, -1724690840, 1073741824,
+			1724690840, -917759617,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	}
+};
+
+static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				     unsigned int reg_data, unsigned int ram_offset,
+				     unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 (mc->max << mc->shift), val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, e->reg, &val);
+
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	bool change = false;
+	unsigned int val;
+	unsigned int mask;
+
+	if (ucontrol->value.enumerated.item[0] > e->items - 1)
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = e->mask << e->shift_l;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
+				 &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &data[i]);
+
+		data[i] = ((data[i] & mask) >> shift);
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
+					 data[i] << shift, &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	u32 val;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &val);
+
+		data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
+			  TEGRA210_MBDRC_THRESH_1ST_SHIFT;
+		data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
+			      TEGRA210_MBDRC_THRESH_2ND_SHIFT;
+		data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
+			      TEGRA210_MBDRC_THRESH_3RD_SHIFT;
+		data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
+			      TEGRA210_MBDRC_THRESH_4TH_SHIFT;
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			   ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			   ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			   ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff,
+					 data[i], &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
+				 params->shift, data, params->soc.num_regs);
+
+	return 1;
+}
+
+static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = params->num_regs * sizeof(u32);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] =
+		((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val += TEGRA210_MBDRC_MASTER_VOL_MIN;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 mc->max << mc->shift, val << mc->shift,
+				 &change);
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	return change ? 1 : 0;
+}
+
+static const char * const tegra210_mbdrc_mode_text[] = {
+	"Bypass", "Fullband", "Dualband", "Multiband"
+};
+
+static const struct soc_enum tegra210_mbdrc_mode_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
+			4, tegra210_mbdrc_mode_text);
+
+static const char * const tegra210_mbdrc_peak_rms_text[] = {
+	"Peak", "RMS"
+};
+
+static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
+			2, tegra210_mbdrc_peak_rms_text);
+
+static const char * const tegra210_mbdrc_filter_structure_text[] = {
+	"All-pass-tree", "Flexible"
+};
+
+static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
+			TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2,
+			tegra210_mbdrc_filter_structure_text);
+
+static const char * const tegra210_mbdrc_frame_size_text[] = {
+	"N1", "N2", "N4", "N8", "N16", "N32", "N64"
+};
+
+static const struct soc_enum tegra210_mbdrc_frame_size_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
+			7, tegra210_mbdrc_frame_size_text);
+
+#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo)    \
+	TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		    \
+			    tegra210_mbdrc_band_params_get,		    \
+			    tegra210_mbdrc_band_params_put,		    \
+			    tegra210_mbdrc_param_info)
+
+#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo)	    \
+	TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT,    \
+			      xshift, xmask, xinfo)
+
+static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500);
+
+static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
+	SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Filter Structure",
+		     tegra210_mbdrc_filter_structure_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume",
+				 TEGRA210_MBDRC_MASTER_VOL,
+				 TEGRA210_MBDRC_MASTER_VOL_SHIFT,
+				 0, 0x1ff, 0,
+				 tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
+				 mdbrc_vol_tlv),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST,
+			    TEGRA210_MBDRC_FILTER_COUNT * 5,
+			    TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_INIT_GAIN_SHIFT,
+			    TEGRA210_MBDRC_INIT_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain",
+			    TEGRA210_MBDRC_FAST_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				(TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+};
+
+static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_CG:
+	case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_mbdrc_wr_reg(dev, reg))
+		return true;
+
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_STATUS:
+	case TEGRA210_MBDRC_CFG_RAM_CTRL:
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
+	.name			= "mbdrc",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_MBDRC_MAX_REG,
+	.writeable_reg		= tegra210_mbdrc_wr_reg,
+	.readable_reg		= tegra210_mbdrc_rd_reg,
+	.volatile_reg		= tegra210_mbdrc_volatile_reg,
+	.precious_reg		= tegra210_mbdrc_precious_reg,
+	.reg_defaults		= tegra210_mbdrc_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	u32 val = 0;
+	unsigned int i;
+
+	regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
+
+	if (val & TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
+		return 0;
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+			&conf->band_params[i];
+
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
+					 0, (u32 *)&params->biquad_params[0],
+					 TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+	return 0;
+}
+
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	unsigned int i;
+	u32 val;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	/* Initialize MBDRC registers and AHUB RAM with default params */
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
+		conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
+		conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
+		conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
+		conf->fliter_structure <<
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
+		conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
+		__ffs(conf->frame_size) <<
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
+		TEGRA210_MBDRC_CHANNEL_MASK_MASK,
+		conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+						&conf->band_params[i];
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IIR_CFG,
+			TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			params->iir_stages <<
+				TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_ATTACK,
+			TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			params->in_attack_tc <<
+				TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_RELEASE,
+			TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			params->in_release_tc <<
+				TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_ATTACK,
+			TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			params->fast_attack_tc <<
+				TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
+
+		val = (((params->in_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->in_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->in_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->in_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+				   reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
+				   0xffffffff, val);
+
+		val = (((params->out_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->out_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->out_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->out_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
+			0xffffffff, val);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_1ST,
+			TEGRA210_MBDRC_RATIO_1ST_MASK,
+			params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_2ND,
+			TEGRA210_MBDRC_RATIO_2ND_MASK,
+			params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_3RD,
+			TEGRA210_MBDRC_RATIO_3RD_MASK,
+			params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_4TH,
+			TEGRA210_MBDRC_RATIO_4TH_MASK,
+			params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_5TH,
+			TEGRA210_MBDRC_RATIO_5TH_MASK,
+			params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
+			TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			params->makeup_gain <<
+				TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_INIT_GAIN,
+			TEGRA210_MBDRC_INIT_GAIN_MASK,
+			params->gain_init <<
+				TEGRA210_MBDRC_INIT_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
+			TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			params->gain_attack_tc <<
+				TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
+			TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			params->gain_release_tc <<
+				TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_RELEASE,
+			TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			params->fast_release_tc <<
+				TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0,
+			(u32 *)&params->biquad_params[0],
+			TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
+				       ARRAY_SIZE(tegra210_mbdrc_controls));
+
+	return 0;
+}
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get MBDRC resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
+						  &tegra210_mbdrc_regmap_cfg);
+	if (IS_ERR(ope->mbdrc_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->mbdrc_regmap);
+	}
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
new file mode 100644
index 0000000..4c48da0
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_MBDRC_H__
+#define __TEGRA210_MBDRC_H__
+
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+/* Register offsets from TEGRA210_MBDRC*_BASE */
+#define TEGRA210_MBDRC_SOFT_RESET			0x4
+#define TEGRA210_MBDRC_CG				0x8
+#define TEGRA210_MBDRC_STATUS				0xc
+#define TEGRA210_MBDRC_CFG				0x28
+#define TEGRA210_MBDRC_CHANNEL_MASK			0x2c
+#define TEGRA210_MBDRC_MASTER_VOL			0x30
+#define TEGRA210_MBDRC_FAST_FACTOR			0x34
+
+#define TEGRA210_MBDRC_FILTER_COUNT			3
+#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE		0x4
+
+#define TEGRA210_MBDRC_IIR_CFG				0x38
+#define TEGRA210_MBDRC_IN_ATTACK			0x44
+#define TEGRA210_MBDRC_IN_RELEASE			0x50
+#define TEGRA210_MBDRC_FAST_ATTACK			0x5c
+#define TEGRA210_MBDRC_IN_THRESHOLD			0x68
+#define TEGRA210_MBDRC_OUT_THRESHOLD			0x74
+#define TEGRA210_MBDRC_RATIO_1ST			0x80
+#define TEGRA210_MBDRC_RATIO_2ND			0x8c
+#define TEGRA210_MBDRC_RATIO_3RD			0x98
+#define TEGRA210_MBDRC_RATIO_4TH			0xa4
+#define TEGRA210_MBDRC_RATIO_5TH			0xb0
+#define TEGRA210_MBDRC_MAKEUP_GAIN			0xbc
+#define TEGRA210_MBDRC_INIT_GAIN			0xc8
+#define TEGRA210_MBDRC_GAIN_ATTACK			0xd4
+#define TEGRA210_MBDRC_GAIN_RELEASE			0xe0
+#define TEGRA210_MBDRC_FAST_RELEASE			0xec
+#define TEGRA210_MBDRC_CFG_RAM_CTRL			0xf8
+#define TEGRA210_MBDRC_CFG_RAM_DATA			0x104
+
+#define TEGRA210_MBDRC_MAX_REG				(TEGRA210_MBDRC_CFG_RAM_DATA +		\
+							 (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *	\
+							  (TEGRA210_MBDRC_FILTER_COUNT - 1)))
+
+/* Fields for TEGRA210_MBDRC_CFG */
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT		16
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK		(0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT		14
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK		(0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+#define TEGRA210_MBDRC_CFG_PEAK				(1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT	13
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK	(0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX	(1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT		8
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK		(0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT		4
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK		(0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT		0
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK		(0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS		(0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */
+#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT		0
+#define TEGRA210_MBDRC_CHANNEL_MASK_MASK		(0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MASTER_VOL */
+#define TEGRA210_MBDRC_MASTER_VOL_SHIFT			23
+#define TEGRA210_MBDRC_MASTER_VOL_MIN			-256
+#define TEGRA210_MBDRC_MASTER_VOL_MAX			256
+
+/* Fields for TEGRA210_MBDRC_FAST_FACTOR */
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT	16
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IIR_CFG */
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT		0
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK		(0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_ATTACK */
+#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_RELEASE */
+#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_ATTACK */
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */
+#define TEGRA210_MBDRC_THRESH_4TH_SHIFT			24
+#define TEGRA210_MBDRC_THRESH_4TH_MASK			(0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_3RD_SHIFT			16
+#define TEGRA210_MBDRC_THRESH_3RD_MASK			(0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_2ND_SHIFT			8
+#define TEGRA210_MBDRC_THRESH_2ND_MASK			(0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_1ST_SHIFT			0
+#define TEGRA210_MBDRC_THRESH_1ST_MASK			(0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_1ST */
+#define TEGRA210_MBDRC_RATIO_1ST_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_1ST_MASK			(0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_2ND */
+#define TEGRA210_MBDRC_RATIO_2ND_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_2ND_MASK			(0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_3RD */
+#define TEGRA210_MBDRC_RATIO_3RD_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_3RD_MASK			(0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_4TH */
+#define TEGRA210_MBDRC_RATIO_4TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_4TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_5TH */
+#define TEGRA210_MBDRC_RATIO_5TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_5TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */
+#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT		0
+#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK			(0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_INIT_GAIN */
+#define TEGRA210_MBDRC_INIT_GAIN_SHIFT			0
+#define TEGRA210_MBDRC_INIT_GAIN_MASK			(0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */
+#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_ATTACK_MASK			(0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */
+#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_RELEASE */
+#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_FAST_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_RAM_CTRL_RW_READ			0
+#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE		(1 << 14)
+#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/*
+ * Order and size of each structure element for following structures should not
+ * be altered size order of elements and their size are based on PEQ co-eff ram
+ * and shift ram layout.
+ */
+#define TEGRA210_MBDRC_THRESHOLD_NUM				4
+#define TEGRA210_MBDRC_RATIO_NUM				(TEGRA210_MBDRC_THRESHOLD_NUM + 1)
+#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES			8
+
+/* Order of these enums are same as the order of band specific hw registers */
+enum {
+	MBDRC_LOW_BAND,
+	MBDRC_MID_BAND,
+	MBDRC_HIGH_BAND,
+	MBDRC_NUM_BAND,
+};
+
+struct tegra210_mbdrc_band_params {
+	u32 band;
+	u32 iir_stages;
+	u32 in_attack_tc;
+	u32 in_release_tc;
+	u32 fast_attack_tc;
+	u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 ratio[TEGRA210_MBDRC_RATIO_NUM];
+	u32 makeup_gain;
+	u32 gain_init;
+	u32 gain_attack_tc;
+	u32 gain_release_tc;
+	u32 fast_release_tc;
+	/* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */
+	u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5];
+};
+
+struct tegra210_mbdrc_config {
+	unsigned int mode;
+	unsigned int rms_off;
+	unsigned int peak_rms_mode;
+	unsigned int fliter_structure;
+	unsigned int shift_ctrl;
+	unsigned int frame_size;
+	unsigned int channel_mask;
+	unsigned int fa_factor;	/* Fast attack factor */
+	unsigned int fr_factor;	/* Fast release factor */
+	struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND];
+};
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev);
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt);
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt);
+
+#endif
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
new file mode 100644
index 0000000..3dd2bde
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ope.c - Tegra210 OPE driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_ope_reg_defaults[] = {
+	{ TEGRA210_OPE_RX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_TX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_CG, 0x1},
+};
+
+static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
+				      struct snd_pcm_hw_params *params,
+				      unsigned int reg)
+{
+	int channels, audio_bits;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 2)
+		return -EINVAL;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+	cif_conf.audio_bits = audio_bits;
+	cif_conf.client_bits = audio_bits;
+
+	tegra_set_cif(ope->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
+	int err;
+
+	/* Set RX and TX CIF */
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_RX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
+		return err;
+	}
+
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_TX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
+		return err;
+	}
+
+	tegra210_mbdrc_hw_params(dai->component);
+
+	return err;
+}
+
+static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
+
+	tegra210_peq_component_init(cmpnt);
+	tegra210_mbdrc_component_init(cmpnt);
+
+	/*
+	 * The OPE, PEQ and MBDRC functionalities are combined under one
+	 * device registered by OPE driver. In fact OPE HW block includes
+	 * sub blocks PEQ and MBDRC. However driver registers separate
+	 * regmap interfaces for each of these. ASoC core depends on
+	 * dev_get_regmap() to populate the regmap field for a given ASoC
+	 * component. A component can have one regmap reference and since
+	 * the DAPM routes depend on OPE regmap only, below explicit
+	 * assignment is done to highlight this. This is needed for ASoC
+	 * core to access correct regmap during DAPM path setup.
+	 */
+	snd_soc_component_init_regmap(cmpnt, ope->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
+	.hw_params	= tegra210_ope_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_ope_dais[] = {
+	{
+		.name = "OPE-RX-CIF",
+		.playback = {
+			.stream_name = "RX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "RX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+	},
+	{
+		.name = "OPE-TX-CIF",
+		.playback = {
+			.stream_name = "TX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "TX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_ope_dai_ops,
+	}
+};
+
+static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
+			     TEGRA210_OPE_EN_SHIFT, 0),
+};
+
+#define OPE_ROUTES(sname)					\
+	{ "RX XBAR-" sname,	NULL,	"XBAR-TX" },		\
+	{ "RX-CIF-" sname,	NULL,	"RX XBAR-" sname },	\
+	{ "RX",			NULL,	"RX-CIF-" sname },	\
+	{ "TX-CIF-" sname,	NULL,	"TX" },			\
+	{ "TX XBAR-" sname,	NULL,	"TX-CIF-" sname },	\
+	{ "XBAR-RX",		NULL,	"TX XBAR-" sname }
+
+static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
+	{ "TX", NULL, "RX" },
+	OPE_ROUTES("Playback"),
+	OPE_ROUTES("Capture"),
+};
+
+static const char * const tegra210_ope_data_dir_text[] = {
+	"MBDRC to PEQ",
+	"PEQ to MBDRC"
+};
+
+static const struct soc_enum tegra210_ope_data_dir_enum =
+	SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
+			2, tegra210_ope_data_dir_text);
+
+static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+
+	ucontrol->value.enumerated.item[0] = ope->data_dir;
+
+	return 0;
+}
+
+static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int value = ucontrol->value.enumerated.item[0];
+
+	if (value == ope->data_dir)
+		return 0;
+
+	ope->data_dir = value;
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new tegra210_ope_controls[] = {
+	SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
+		     tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
+};
+
+static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
+	.probe			= tegra210_ope_component_probe,
+	.dapm_widgets		= tegra210_ope_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ope_widgets),
+	.dapm_routes		= tegra210_ope_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ope_routes),
+	.controls		= tegra210_ope_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_ope_controls),
+};
+
+static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
+	case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
+	case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
+	case TEGRA210_OPE_DIR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_ope_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_SOFT_RESET:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_ope_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_OPE_DIR,
+	.writeable_reg		= tegra210_ope_wr_reg,
+	.readable_reg		= tegra210_ope_rd_reg,
+	.volatile_reg		= tegra210_ope_volatile_reg,
+	.reg_defaults		= tegra210_ope_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_ope_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_ope_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope;
+	void __iomem *regs;
+	int err;
+
+	ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
+	if (!ope)
+		return -ENOMEM;
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_ope_regmap_config);
+	if (IS_ERR(ope->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->regmap);
+	}
+
+	regcache_cache_only(ope->regmap, true);
+
+	dev_set_drvdata(dev, ope);
+
+	err = tegra210_peq_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "PEQ init failed\n");
+		return err;
+	}
+
+	err = tegra210_mbdrc_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "MBDRC init failed\n");
+		return err;
+	}
+
+	err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
+					      tegra210_ope_dais,
+					      ARRAY_SIZE(tegra210_ope_dais));
+	if (err) {
+		dev_err(dev, "can't register OPE component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_ope_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
+			  ope->peq_biquad_shifts);
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+	regcache_cache_only(ope->peq_regmap, true);
+	regcache_cache_only(ope->regmap, true);
+
+	regcache_mark_dirty(ope->regmap);
+	regcache_mark_dirty(ope->peq_regmap);
+	regcache_mark_dirty(ope->mbdrc_regmap);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	regcache_cache_only(ope->regmap, false);
+	regcache_cache_only(ope->peq_regmap, false);
+	regcache_cache_only(ope->mbdrc_regmap, false);
+
+	regcache_sync(ope->regmap);
+	regcache_sync(ope->peq_regmap);
+	regcache_sync(ope->mbdrc_regmap);
+
+	tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
+			     ope->peq_biquad_shifts);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_ope_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+			   tegra210_ope_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_ope_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ope" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
+
+static struct platform_driver tegra210_ope_driver = {
+	.driver = {
+		.name = "tegra210-ope",
+		.of_match_table = tegra210_ope_of_match,
+		.pm = &tegra210_ope_pm_ops,
+	},
+	.probe = tegra210_ope_probe,
+	.remove = tegra210_ope_remove,
+};
+module_platform_driver(tegra210_ope_driver)
+
+MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h
new file mode 100644
index 0000000..2835af6
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ope.h - Definitions for Tegra210 OPE driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_OPE_H__
+#define __TEGRA210_OPE_H__
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tegra210_peq.h"
+
+/*
+ * OPE_RX registers are with respect to XBAR.
+ * The data comes from XBAR to OPE
+ */
+#define TEGRA210_OPE_RX_STATUS			0xc
+#define TEGRA210_OPE_RX_INT_STATUS		0x10
+#define TEGRA210_OPE_RX_INT_MASK		0x14
+#define TEGRA210_OPE_RX_INT_SET			0x18
+#define TEGRA210_OPE_RX_INT_CLEAR		0x1c
+#define TEGRA210_OPE_RX_CIF_CTRL		0x20
+
+/*
+ * OPE_TX registers are with respect to XBAR.
+ * The data goes out from OPE to XBAR
+ */
+#define TEGRA210_OPE_TX_STATUS			0x4c
+#define TEGRA210_OPE_TX_INT_STATUS		0x50
+#define TEGRA210_OPE_TX_INT_MASK		0x54
+#define TEGRA210_OPE_TX_INT_SET			0x58
+#define TEGRA210_OPE_TX_INT_CLEAR		0x5c
+#define TEGRA210_OPE_TX_CIF_CTRL		0x60
+
+/* OPE Gloabal registers */
+#define TEGRA210_OPE_ENABLE			0x80
+#define TEGRA210_OPE_SOFT_RESET			0x84
+#define TEGRA210_OPE_CG				0x88
+#define TEGRA210_OPE_STATUS			0x8c
+#define TEGRA210_OPE_INT_STATUS			0x90
+#define TEGRA210_OPE_DIR			0x94
+
+/* Fields for TEGRA210_OPE_ENABLE */
+#define TEGRA210_OPE_EN_SHIFT			0
+#define TEGRA210_OPE_EN				(1 << TEGRA210_OPE_EN_SHIFT)
+
+/* Fields for TEGRA210_OPE_SOFT_RESET */
+#define TEGRA210_OPE_SOFT_RESET_SHIFT		0
+#define TEGRA210_OPE_SOFT_RESET_EN		(1 << TEGRA210_OPE_SOFT_RESET_SHIFT)
+
+#define TEGRA210_OPE_DIR_SHIFT			0
+
+struct tegra210_ope {
+	struct regmap *regmap;
+	struct regmap *peq_regmap;
+	struct regmap *mbdrc_regmap;
+	u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+	u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH];
+	unsigned int data_dir;
+};
+
+/* Extension of soc_bytes structure defined in sound/soc.h */
+struct tegra_soc_bytes {
+	struct soc_bytes soc;
+	u32 shift; /* Used as offset for AHUB RAM related programing */
+};
+
+/* Utility structures for using mixer control of type snd_soc_bytes */
+#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		\
+			    xhandler_get, xhandler_put, xinfo)		\
+{									\
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,				\
+	.name	= xname,						\
+	.info	= xinfo,						\
+	.get	= xhandler_get,						\
+	.put	= xhandler_put,						\
+	.private_value = ((unsigned long)&(struct tegra_soc_bytes)	\
+	{								\
+		.soc.base	= xbase,				\
+		.soc.num_regs	= xregs,				\
+		.soc.mask	= xmask,				\
+		.shift		= xshift				\
+	})								\
+}
+
+#endif
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
new file mode 100644
index 0000000..205d956
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_peq.c - Tegra210 PEQ driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+
+static const struct reg_default tegra210_peq_reg_defaults[] = {
+	{ TEGRA210_PEQ_CFG, 0x00000013},
+	{ TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},
+	{ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},
+};
+
+static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {
+	1495012349, /* Pre-gain */
+
+	/* Gains : b0, b1, a0, a1, a2 */
+	536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */
+	134217728, -265414508, 131766272, 2140402222, -1071252997,  /* Band-1 */
+	268435456, -233515765, -33935948, 1839817267, -773826124,   /* Band-2 */
+	536870912, -672537913, 139851540, 1886437554, -824433167,   /* Band-3 */
+	268435456, -114439279, 173723964, 205743566, 278809729,     /* Band-4 */
+	1, 0, 0, 0, 0, /* Band-5 */
+	1, 0, 0, 0, 0, /* Band-6 */
+	1, 0, 0, 0, 0, /* Band-7 */
+	1, 0, 0, 0, 0, /* Band-8 */
+	1, 0, 0, 0, 0, /* Band-9 */
+	1, 0, 0, 0, 0, /* Band-10 */
+	1, 0, 0, 0, 0, /* Band-11 */
+
+	963423114, /* Post-gain */
+};
+
+static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {
+	23, /* Pre-shift */
+	30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */
+	28, /* Post-shift */
+};
+
+static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+
+static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				  unsigned int reg_data, unsigned int ram_offset,
+				  unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	/*
+	 * Since all ahub non-io modules work under same ahub clock it is not
+	 * necessary to check ahub read busy bit after every read.
+	 */
+	for (i = 0; i < size; i++)
+		regmap_read(regmap, reg_data, &data[i]);
+}
+
+static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				   unsigned int reg_data, unsigned int ram_offset,
+				   unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_peq_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	unsigned int val;
+
+	regmap_read(ope->peq_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
+
+	if (!mc->invert)
+		return 0;
+
+	ucontrol->value.integer.value[0] =
+		mc->max - ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tegra210_peq_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	bool change = false;
+	unsigned int val;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	if (mc->invert)
+		val = mc->max - val;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),
+				 val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			      params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		ucontrol->value.integer.value[i] = (long)data[i];
+
+	return 0;
+}
+
+static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		data[i] = (s32)ucontrol->value.integer.value[i];
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			       params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	return 1;
+}
+
+static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->value.integer.min = INT_MIN;
+	uinfo->value.integer.max = INT_MAX;
+	uinfo->count = params->num_regs;
+
+	return 0;
+}
+
+#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params",	  \
+		TEGRA210_PEQ_CFG_RAM_CTRL,				  \
+		TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params",  \
+		TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,			  \
+		TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f,	  \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+static const struct snd_kcontrol_new tegra210_peq_controls[] = {
+	SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,
+		       TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),
+
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),
+};
+
+static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_CG:
+	case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_peq_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_PEQ_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_STATUS:
+	case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_CFG_RAM_DATA:
+	case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_peq_regmap_config = {
+	.name			= "peq",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+	.writeable_reg		= tegra210_peq_wr_reg,
+	.readable_reg		= tegra210_peq_rd_reg,
+	.volatile_reg		= tegra210_peq_volatile_reg,
+	.precious_reg		= tegra210_peq_precious_reg,
+	.reg_defaults		= tegra210_peq_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_peq_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_write_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+}
+
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+	}
+}
+
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int i;
+
+	pm_runtime_get_sync(cmpnt->dev);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_MODE_MASK,
+		0 << TEGRA210_PEQ_CFG_MODE_SHIFT);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,
+		(TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);
+
+	/* Initialize PEQ AHUB RAM with default params */
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+
+		/* Set default gain params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		/* Set default shift params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,
+				       ARRAY_SIZE(tegra210_peq_controls));
+
+	return 0;
+}
+
+int tegra210_peq_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "equalizer");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get PEQ resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+	ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
+						&tegra210_peq_regmap_config);
+	if (IS_ERR(ope->peq_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->peq_regmap);
+	}
+
+	regcache_cache_only(ope->peq_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h
new file mode 100644
index 0000000..6d3de4f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_peq.h - Definitions for Tegra210 PEQ driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_PEQ_H__
+#define __TEGRA210_PEQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+/* Register offsets from PEQ base */
+#define TEGRA210_PEQ_SOFT_RESET				0x0
+#define TEGRA210_PEQ_CG					0x4
+#define TEGRA210_PEQ_STATUS				0x8
+#define TEGRA210_PEQ_CFG				0xc
+#define TEGRA210_PEQ_CFG_RAM_CTRL			0x10
+#define TEGRA210_PEQ_CFG_RAM_DATA			0x14
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL			0x18
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA			0x1c
+
+/* Fields in TEGRA210_PEQ_CFG */
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT		2
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK		(0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT)
+
+#define TEGRA210_PEQ_CFG_MODE_SHIFT			0
+#define TEGRA210_PEQ_CFG_MODE_MASK			(0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT)
+
+#define TEGRA210_PEQ_RAM_CTRL_RW_READ			0
+#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE			(1 << 14)
+#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/* PEQ register definition ends here */
+#define TEGRA210_PEQ_MAX_BIQUAD_STAGES			12
+
+#define TEGRA210_PEQ_MAX_CHANNELS			8
+
+#define TEGRA210_PEQ_BIQUAD_INIT_STAGE			5
+
+#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5)
+#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES)
+
+int tegra210_peq_regmap_init(struct platform_device *pdev);
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt);
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts);
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts);
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/6] ASoC: tegra: Add Tegra210 based OPE driver
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

The Output Processing Engine (OPE) is one of the AHUB client. It has
PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
sub blocks for data processing. The PEQ block gets samples from the MBDRC
block.

This patch registers OPE driver with ASoC framework. The component driver
exposes DAPM widgets, routes and kcontrols for the device. The DAI driver
exposes OPE interfaces, which can be used to connect different components
in the ASoC layer. Makefile and Kconfig support is added to allow build
the driver.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig          |    9 +
 sound/soc/tegra/Makefile         |    2 +
 sound/soc/tegra/tegra210_mbdrc.c | 1012 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h |  215 ++++++++
 sound/soc/tegra/tegra210_ope.c   |  419 ++++++++++++++++
 sound/soc/tegra/tegra210_ope.h   |   90 ++++
 sound/soc/tegra/tegra210_peq.c   |  434 ++++++++++++++++
 sound/soc/tegra/tegra210_peq.h   |   56 +++
 8 files changed, 2237 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2482d98..b6712a3 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -85,6 +85,15 @@ config SND_SOC_TEGRA210_I2S
 	  compatible devices.
 	  Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA210_OPE
+	tristate "Tegra210 OPE module"
+	help
+	  Config to enable the Output Processing Engine (OPE) which includes
+	  Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor
+	  (MBDRC) sub blocks for data processing. It can support up to 8
+	  channels.
+	  Say Y or M if you want to add support for Tegra210 OPE module.
+
 config SND_SOC_TEGRA186_ASRC
 	tristate "Tegra186 ASRC module"
 	help
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 70a498d..b723c78 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -19,6 +19,7 @@ snd-soc-tegra210-sfc-objs := tegra210_sfc.o
 snd-soc-tegra210-amx-objs := tegra210_amx.o
 snd-soc-tegra210-adx-objs := tegra210_adx.o
 snd-soc-tegra210-mixer-objs := tegra210_mixer.o
+snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
+obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
new file mode 100644
index 0000000..7d9da33
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -0,0 +1,1012 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_mbdrc.c - Tegra210 MBDRC driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+
+#define MBDRC_FILTER_REG(reg, id)					    \
+	((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
+
+#define MBDRC_FILTER_REG_DEFAULTS(id)					    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b},  \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+
+static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
+	{ TEGRA210_MBDRC_CFG, 0x0030de51},
+	{ TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
+	{ TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
+
+	MBDRC_FILTER_REG_DEFAULTS(0),
+	MBDRC_FILTER_REG_DEFAULTS(1),
+	MBDRC_FILTER_REG_DEFAULTS(2),
+};
+
+/* Default MBDRC parameters */
+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 */
+	.shift_ctrl		= 30,
+	.frame_size		= 32,
+	.channel_mask		= 0x3,
+	.fa_factor		= 2048,
+	.fr_factor		= 14747,
+
+	.band_params[MBDRC_LOW_BAND] = {
+		.band			= MBDRC_LOW_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1044928780,
+		.in_release_tc		= 138497695,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 80, 20, 6},
+		.out_threshold		= {155, 55, 13, 6},
+		.ratio			= {40960, 8192, 2867, 2048, 410},
+		.makeup_gain		= 4,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 14268942,
+		.gain_release_tc	= 1440547090,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params	= {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			961046798, -2030431983, 1073741824,
+			2030431983, -961046798,
+			/* Band-1 */
+			1030244425, -2099481453, 1073741824,
+			2099481453, -1030244425,
+			/* Band-2 */
+			1067169294, -2136327263, 1073741824,
+			2136327263, -1067169294,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_MID_BAND] = {
+		.band			= MBDRC_MID_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1581413104,
+		.in_release_tc		= 35494783,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			-1005668963, 1073741824, 0,
+			1005668963, 0,
+			/* Band-1 */
+			998437058, -2067742187, 1073741824,
+			2067742187, -998437058,
+			/* Band-2 */
+			1051963422, -2121153948, 1073741824,
+			2121153948, -1051963422,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_HIGH_BAND] = {
+		.band			= MBDRC_HIGH_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 2144750688,
+		.in_release_tc		= 70402888,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-1 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-2 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-3 */
+			-619925131, 1073741824, 0,
+			619925131, 0,
+			/* Band-4 */
+			606839335, -1455425976, 1073741824,
+			1455425976, -606839335,
+			/* Band-5 */
+			917759617, -1724690840, 1073741824,
+			1724690840, -917759617,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	}
+};
+
+static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				     unsigned int reg_data, unsigned int ram_offset,
+				     unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 (mc->max << mc->shift), val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, e->reg, &val);
+
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	bool change = false;
+	unsigned int val;
+	unsigned int mask;
+
+	if (ucontrol->value.enumerated.item[0] > e->items - 1)
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = e->mask << e->shift_l;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
+				 &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &data[i]);
+
+		data[i] = ((data[i] & mask) >> shift);
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
+					 data[i] << shift, &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	u32 val;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &val);
+
+		data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
+			  TEGRA210_MBDRC_THRESH_1ST_SHIFT;
+		data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
+			      TEGRA210_MBDRC_THRESH_2ND_SHIFT;
+		data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
+			      TEGRA210_MBDRC_THRESH_3RD_SHIFT;
+		data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
+			      TEGRA210_MBDRC_THRESH_4TH_SHIFT;
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			   ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			   ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			   ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff,
+					 data[i], &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
+				 params->shift, data, params->soc.num_regs);
+
+	return 1;
+}
+
+static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = params->num_regs * sizeof(u32);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] =
+		((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val += TEGRA210_MBDRC_MASTER_VOL_MIN;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 mc->max << mc->shift, val << mc->shift,
+				 &change);
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	return change ? 1 : 0;
+}
+
+static const char * const tegra210_mbdrc_mode_text[] = {
+	"Bypass", "Fullband", "Dualband", "Multiband"
+};
+
+static const struct soc_enum tegra210_mbdrc_mode_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
+			4, tegra210_mbdrc_mode_text);
+
+static const char * const tegra210_mbdrc_peak_rms_text[] = {
+	"Peak", "RMS"
+};
+
+static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
+			2, tegra210_mbdrc_peak_rms_text);
+
+static const char * const tegra210_mbdrc_filter_structure_text[] = {
+	"All-pass-tree", "Flexible"
+};
+
+static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
+			TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2,
+			tegra210_mbdrc_filter_structure_text);
+
+static const char * const tegra210_mbdrc_frame_size_text[] = {
+	"N1", "N2", "N4", "N8", "N16", "N32", "N64"
+};
+
+static const struct soc_enum tegra210_mbdrc_frame_size_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
+			7, tegra210_mbdrc_frame_size_text);
+
+#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo)    \
+	TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		    \
+			    tegra210_mbdrc_band_params_get,		    \
+			    tegra210_mbdrc_band_params_put,		    \
+			    tegra210_mbdrc_param_info)
+
+#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo)	    \
+	TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT,    \
+			      xshift, xmask, xinfo)
+
+static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500);
+
+static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
+	SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Filter Structure",
+		     tegra210_mbdrc_filter_structure_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume",
+				 TEGRA210_MBDRC_MASTER_VOL,
+				 TEGRA210_MBDRC_MASTER_VOL_SHIFT,
+				 0, 0x1ff, 0,
+				 tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
+				 mdbrc_vol_tlv),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST,
+			    TEGRA210_MBDRC_FILTER_COUNT * 5,
+			    TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_INIT_GAIN_SHIFT,
+			    TEGRA210_MBDRC_INIT_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain",
+			    TEGRA210_MBDRC_FAST_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				(TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+};
+
+static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_CG:
+	case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_mbdrc_wr_reg(dev, reg))
+		return true;
+
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_STATUS:
+	case TEGRA210_MBDRC_CFG_RAM_CTRL:
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
+	.name			= "mbdrc",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_MBDRC_MAX_REG,
+	.writeable_reg		= tegra210_mbdrc_wr_reg,
+	.readable_reg		= tegra210_mbdrc_rd_reg,
+	.volatile_reg		= tegra210_mbdrc_volatile_reg,
+	.precious_reg		= tegra210_mbdrc_precious_reg,
+	.reg_defaults		= tegra210_mbdrc_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	u32 val = 0;
+	unsigned int i;
+
+	regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
+
+	if (val & TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
+		return 0;
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+			&conf->band_params[i];
+
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
+					 0, (u32 *)&params->biquad_params[0],
+					 TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+	return 0;
+}
+
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	unsigned int i;
+	u32 val;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	/* Initialize MBDRC registers and AHUB RAM with default params */
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
+		conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
+		conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
+		conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
+		conf->fliter_structure <<
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
+		conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
+		__ffs(conf->frame_size) <<
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
+		TEGRA210_MBDRC_CHANNEL_MASK_MASK,
+		conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+						&conf->band_params[i];
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IIR_CFG,
+			TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			params->iir_stages <<
+				TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_ATTACK,
+			TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			params->in_attack_tc <<
+				TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_RELEASE,
+			TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			params->in_release_tc <<
+				TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_ATTACK,
+			TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			params->fast_attack_tc <<
+				TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
+
+		val = (((params->in_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->in_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->in_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->in_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+				   reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
+				   0xffffffff, val);
+
+		val = (((params->out_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->out_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->out_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->out_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
+			0xffffffff, val);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_1ST,
+			TEGRA210_MBDRC_RATIO_1ST_MASK,
+			params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_2ND,
+			TEGRA210_MBDRC_RATIO_2ND_MASK,
+			params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_3RD,
+			TEGRA210_MBDRC_RATIO_3RD_MASK,
+			params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_4TH,
+			TEGRA210_MBDRC_RATIO_4TH_MASK,
+			params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_5TH,
+			TEGRA210_MBDRC_RATIO_5TH_MASK,
+			params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
+			TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			params->makeup_gain <<
+				TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_INIT_GAIN,
+			TEGRA210_MBDRC_INIT_GAIN_MASK,
+			params->gain_init <<
+				TEGRA210_MBDRC_INIT_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
+			TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			params->gain_attack_tc <<
+				TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
+			TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			params->gain_release_tc <<
+				TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_RELEASE,
+			TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			params->fast_release_tc <<
+				TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0,
+			(u32 *)&params->biquad_params[0],
+			TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
+				       ARRAY_SIZE(tegra210_mbdrc_controls));
+
+	return 0;
+}
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get MBDRC resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
+						  &tegra210_mbdrc_regmap_cfg);
+	if (IS_ERR(ope->mbdrc_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->mbdrc_regmap);
+	}
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
new file mode 100644
index 0000000..4c48da0
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_MBDRC_H__
+#define __TEGRA210_MBDRC_H__
+
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+/* Register offsets from TEGRA210_MBDRC*_BASE */
+#define TEGRA210_MBDRC_SOFT_RESET			0x4
+#define TEGRA210_MBDRC_CG				0x8
+#define TEGRA210_MBDRC_STATUS				0xc
+#define TEGRA210_MBDRC_CFG				0x28
+#define TEGRA210_MBDRC_CHANNEL_MASK			0x2c
+#define TEGRA210_MBDRC_MASTER_VOL			0x30
+#define TEGRA210_MBDRC_FAST_FACTOR			0x34
+
+#define TEGRA210_MBDRC_FILTER_COUNT			3
+#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE		0x4
+
+#define TEGRA210_MBDRC_IIR_CFG				0x38
+#define TEGRA210_MBDRC_IN_ATTACK			0x44
+#define TEGRA210_MBDRC_IN_RELEASE			0x50
+#define TEGRA210_MBDRC_FAST_ATTACK			0x5c
+#define TEGRA210_MBDRC_IN_THRESHOLD			0x68
+#define TEGRA210_MBDRC_OUT_THRESHOLD			0x74
+#define TEGRA210_MBDRC_RATIO_1ST			0x80
+#define TEGRA210_MBDRC_RATIO_2ND			0x8c
+#define TEGRA210_MBDRC_RATIO_3RD			0x98
+#define TEGRA210_MBDRC_RATIO_4TH			0xa4
+#define TEGRA210_MBDRC_RATIO_5TH			0xb0
+#define TEGRA210_MBDRC_MAKEUP_GAIN			0xbc
+#define TEGRA210_MBDRC_INIT_GAIN			0xc8
+#define TEGRA210_MBDRC_GAIN_ATTACK			0xd4
+#define TEGRA210_MBDRC_GAIN_RELEASE			0xe0
+#define TEGRA210_MBDRC_FAST_RELEASE			0xec
+#define TEGRA210_MBDRC_CFG_RAM_CTRL			0xf8
+#define TEGRA210_MBDRC_CFG_RAM_DATA			0x104
+
+#define TEGRA210_MBDRC_MAX_REG				(TEGRA210_MBDRC_CFG_RAM_DATA +		\
+							 (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *	\
+							  (TEGRA210_MBDRC_FILTER_COUNT - 1)))
+
+/* Fields for TEGRA210_MBDRC_CFG */
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT		16
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK		(0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT		14
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK		(0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+#define TEGRA210_MBDRC_CFG_PEAK				(1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT	13
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK	(0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX	(1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT		8
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK		(0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT		4
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK		(0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT		0
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK		(0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS		(0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */
+#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT		0
+#define TEGRA210_MBDRC_CHANNEL_MASK_MASK		(0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MASTER_VOL */
+#define TEGRA210_MBDRC_MASTER_VOL_SHIFT			23
+#define TEGRA210_MBDRC_MASTER_VOL_MIN			-256
+#define TEGRA210_MBDRC_MASTER_VOL_MAX			256
+
+/* Fields for TEGRA210_MBDRC_FAST_FACTOR */
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT	16
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IIR_CFG */
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT		0
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK		(0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_ATTACK */
+#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_RELEASE */
+#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_ATTACK */
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */
+#define TEGRA210_MBDRC_THRESH_4TH_SHIFT			24
+#define TEGRA210_MBDRC_THRESH_4TH_MASK			(0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_3RD_SHIFT			16
+#define TEGRA210_MBDRC_THRESH_3RD_MASK			(0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_2ND_SHIFT			8
+#define TEGRA210_MBDRC_THRESH_2ND_MASK			(0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_1ST_SHIFT			0
+#define TEGRA210_MBDRC_THRESH_1ST_MASK			(0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_1ST */
+#define TEGRA210_MBDRC_RATIO_1ST_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_1ST_MASK			(0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_2ND */
+#define TEGRA210_MBDRC_RATIO_2ND_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_2ND_MASK			(0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_3RD */
+#define TEGRA210_MBDRC_RATIO_3RD_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_3RD_MASK			(0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_4TH */
+#define TEGRA210_MBDRC_RATIO_4TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_4TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_5TH */
+#define TEGRA210_MBDRC_RATIO_5TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_5TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */
+#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT		0
+#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK			(0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_INIT_GAIN */
+#define TEGRA210_MBDRC_INIT_GAIN_SHIFT			0
+#define TEGRA210_MBDRC_INIT_GAIN_MASK			(0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */
+#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_ATTACK_MASK			(0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */
+#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_RELEASE */
+#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_FAST_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_RAM_CTRL_RW_READ			0
+#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE		(1 << 14)
+#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/*
+ * Order and size of each structure element for following structures should not
+ * be altered size order of elements and their size are based on PEQ co-eff ram
+ * and shift ram layout.
+ */
+#define TEGRA210_MBDRC_THRESHOLD_NUM				4
+#define TEGRA210_MBDRC_RATIO_NUM				(TEGRA210_MBDRC_THRESHOLD_NUM + 1)
+#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES			8
+
+/* Order of these enums are same as the order of band specific hw registers */
+enum {
+	MBDRC_LOW_BAND,
+	MBDRC_MID_BAND,
+	MBDRC_HIGH_BAND,
+	MBDRC_NUM_BAND,
+};
+
+struct tegra210_mbdrc_band_params {
+	u32 band;
+	u32 iir_stages;
+	u32 in_attack_tc;
+	u32 in_release_tc;
+	u32 fast_attack_tc;
+	u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 ratio[TEGRA210_MBDRC_RATIO_NUM];
+	u32 makeup_gain;
+	u32 gain_init;
+	u32 gain_attack_tc;
+	u32 gain_release_tc;
+	u32 fast_release_tc;
+	/* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */
+	u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5];
+};
+
+struct tegra210_mbdrc_config {
+	unsigned int mode;
+	unsigned int rms_off;
+	unsigned int peak_rms_mode;
+	unsigned int fliter_structure;
+	unsigned int shift_ctrl;
+	unsigned int frame_size;
+	unsigned int channel_mask;
+	unsigned int fa_factor;	/* Fast attack factor */
+	unsigned int fr_factor;	/* Fast release factor */
+	struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND];
+};
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev);
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt);
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt);
+
+#endif
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
new file mode 100644
index 0000000..3dd2bde
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ope.c - Tegra210 OPE driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_ope_reg_defaults[] = {
+	{ TEGRA210_OPE_RX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_TX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_CG, 0x1},
+};
+
+static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
+				      struct snd_pcm_hw_params *params,
+				      unsigned int reg)
+{
+	int channels, audio_bits;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 2)
+		return -EINVAL;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+	cif_conf.audio_bits = audio_bits;
+	cif_conf.client_bits = audio_bits;
+
+	tegra_set_cif(ope->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
+	int err;
+
+	/* Set RX and TX CIF */
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_RX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
+		return err;
+	}
+
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_TX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
+		return err;
+	}
+
+	tegra210_mbdrc_hw_params(dai->component);
+
+	return err;
+}
+
+static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
+
+	tegra210_peq_component_init(cmpnt);
+	tegra210_mbdrc_component_init(cmpnt);
+
+	/*
+	 * The OPE, PEQ and MBDRC functionalities are combined under one
+	 * device registered by OPE driver. In fact OPE HW block includes
+	 * sub blocks PEQ and MBDRC. However driver registers separate
+	 * regmap interfaces for each of these. ASoC core depends on
+	 * dev_get_regmap() to populate the regmap field for a given ASoC
+	 * component. A component can have one regmap reference and since
+	 * the DAPM routes depend on OPE regmap only, below explicit
+	 * assignment is done to highlight this. This is needed for ASoC
+	 * core to access correct regmap during DAPM path setup.
+	 */
+	snd_soc_component_init_regmap(cmpnt, ope->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
+	.hw_params	= tegra210_ope_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_ope_dais[] = {
+	{
+		.name = "OPE-RX-CIF",
+		.playback = {
+			.stream_name = "RX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "RX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+	},
+	{
+		.name = "OPE-TX-CIF",
+		.playback = {
+			.stream_name = "TX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "TX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_ope_dai_ops,
+	}
+};
+
+static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
+			     TEGRA210_OPE_EN_SHIFT, 0),
+};
+
+#define OPE_ROUTES(sname)					\
+	{ "RX XBAR-" sname,	NULL,	"XBAR-TX" },		\
+	{ "RX-CIF-" sname,	NULL,	"RX XBAR-" sname },	\
+	{ "RX",			NULL,	"RX-CIF-" sname },	\
+	{ "TX-CIF-" sname,	NULL,	"TX" },			\
+	{ "TX XBAR-" sname,	NULL,	"TX-CIF-" sname },	\
+	{ "XBAR-RX",		NULL,	"TX XBAR-" sname }
+
+static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
+	{ "TX", NULL, "RX" },
+	OPE_ROUTES("Playback"),
+	OPE_ROUTES("Capture"),
+};
+
+static const char * const tegra210_ope_data_dir_text[] = {
+	"MBDRC to PEQ",
+	"PEQ to MBDRC"
+};
+
+static const struct soc_enum tegra210_ope_data_dir_enum =
+	SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
+			2, tegra210_ope_data_dir_text);
+
+static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+
+	ucontrol->value.enumerated.item[0] = ope->data_dir;
+
+	return 0;
+}
+
+static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int value = ucontrol->value.enumerated.item[0];
+
+	if (value == ope->data_dir)
+		return 0;
+
+	ope->data_dir = value;
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new tegra210_ope_controls[] = {
+	SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
+		     tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
+};
+
+static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
+	.probe			= tegra210_ope_component_probe,
+	.dapm_widgets		= tegra210_ope_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ope_widgets),
+	.dapm_routes		= tegra210_ope_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ope_routes),
+	.controls		= tegra210_ope_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_ope_controls),
+};
+
+static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
+	case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
+	case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
+	case TEGRA210_OPE_DIR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_ope_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_SOFT_RESET:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_ope_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_OPE_DIR,
+	.writeable_reg		= tegra210_ope_wr_reg,
+	.readable_reg		= tegra210_ope_rd_reg,
+	.volatile_reg		= tegra210_ope_volatile_reg,
+	.reg_defaults		= tegra210_ope_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_ope_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_ope_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope;
+	void __iomem *regs;
+	int err;
+
+	ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
+	if (!ope)
+		return -ENOMEM;
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_ope_regmap_config);
+	if (IS_ERR(ope->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->regmap);
+	}
+
+	regcache_cache_only(ope->regmap, true);
+
+	dev_set_drvdata(dev, ope);
+
+	err = tegra210_peq_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "PEQ init failed\n");
+		return err;
+	}
+
+	err = tegra210_mbdrc_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "MBDRC init failed\n");
+		return err;
+	}
+
+	err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
+					      tegra210_ope_dais,
+					      ARRAY_SIZE(tegra210_ope_dais));
+	if (err) {
+		dev_err(dev, "can't register OPE component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_ope_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
+			  ope->peq_biquad_shifts);
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+	regcache_cache_only(ope->peq_regmap, true);
+	regcache_cache_only(ope->regmap, true);
+
+	regcache_mark_dirty(ope->regmap);
+	regcache_mark_dirty(ope->peq_regmap);
+	regcache_mark_dirty(ope->mbdrc_regmap);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	regcache_cache_only(ope->regmap, false);
+	regcache_cache_only(ope->peq_regmap, false);
+	regcache_cache_only(ope->mbdrc_regmap, false);
+
+	regcache_sync(ope->regmap);
+	regcache_sync(ope->peq_regmap);
+	regcache_sync(ope->mbdrc_regmap);
+
+	tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
+			     ope->peq_biquad_shifts);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_ope_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+			   tegra210_ope_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_ope_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ope" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
+
+static struct platform_driver tegra210_ope_driver = {
+	.driver = {
+		.name = "tegra210-ope",
+		.of_match_table = tegra210_ope_of_match,
+		.pm = &tegra210_ope_pm_ops,
+	},
+	.probe = tegra210_ope_probe,
+	.remove = tegra210_ope_remove,
+};
+module_platform_driver(tegra210_ope_driver)
+
+MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h
new file mode 100644
index 0000000..2835af6
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ope.h - Definitions for Tegra210 OPE driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_OPE_H__
+#define __TEGRA210_OPE_H__
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tegra210_peq.h"
+
+/*
+ * OPE_RX registers are with respect to XBAR.
+ * The data comes from XBAR to OPE
+ */
+#define TEGRA210_OPE_RX_STATUS			0xc
+#define TEGRA210_OPE_RX_INT_STATUS		0x10
+#define TEGRA210_OPE_RX_INT_MASK		0x14
+#define TEGRA210_OPE_RX_INT_SET			0x18
+#define TEGRA210_OPE_RX_INT_CLEAR		0x1c
+#define TEGRA210_OPE_RX_CIF_CTRL		0x20
+
+/*
+ * OPE_TX registers are with respect to XBAR.
+ * The data goes out from OPE to XBAR
+ */
+#define TEGRA210_OPE_TX_STATUS			0x4c
+#define TEGRA210_OPE_TX_INT_STATUS		0x50
+#define TEGRA210_OPE_TX_INT_MASK		0x54
+#define TEGRA210_OPE_TX_INT_SET			0x58
+#define TEGRA210_OPE_TX_INT_CLEAR		0x5c
+#define TEGRA210_OPE_TX_CIF_CTRL		0x60
+
+/* OPE Gloabal registers */
+#define TEGRA210_OPE_ENABLE			0x80
+#define TEGRA210_OPE_SOFT_RESET			0x84
+#define TEGRA210_OPE_CG				0x88
+#define TEGRA210_OPE_STATUS			0x8c
+#define TEGRA210_OPE_INT_STATUS			0x90
+#define TEGRA210_OPE_DIR			0x94
+
+/* Fields for TEGRA210_OPE_ENABLE */
+#define TEGRA210_OPE_EN_SHIFT			0
+#define TEGRA210_OPE_EN				(1 << TEGRA210_OPE_EN_SHIFT)
+
+/* Fields for TEGRA210_OPE_SOFT_RESET */
+#define TEGRA210_OPE_SOFT_RESET_SHIFT		0
+#define TEGRA210_OPE_SOFT_RESET_EN		(1 << TEGRA210_OPE_SOFT_RESET_SHIFT)
+
+#define TEGRA210_OPE_DIR_SHIFT			0
+
+struct tegra210_ope {
+	struct regmap *regmap;
+	struct regmap *peq_regmap;
+	struct regmap *mbdrc_regmap;
+	u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+	u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH];
+	unsigned int data_dir;
+};
+
+/* Extension of soc_bytes structure defined in sound/soc.h */
+struct tegra_soc_bytes {
+	struct soc_bytes soc;
+	u32 shift; /* Used as offset for AHUB RAM related programing */
+};
+
+/* Utility structures for using mixer control of type snd_soc_bytes */
+#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		\
+			    xhandler_get, xhandler_put, xinfo)		\
+{									\
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,				\
+	.name	= xname,						\
+	.info	= xinfo,						\
+	.get	= xhandler_get,						\
+	.put	= xhandler_put,						\
+	.private_value = ((unsigned long)&(struct tegra_soc_bytes)	\
+	{								\
+		.soc.base	= xbase,				\
+		.soc.num_regs	= xregs,				\
+		.soc.mask	= xmask,				\
+		.shift		= xshift				\
+	})								\
+}
+
+#endif
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
new file mode 100644
index 0000000..205d956
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_peq.c - Tegra210 PEQ driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+
+static const struct reg_default tegra210_peq_reg_defaults[] = {
+	{ TEGRA210_PEQ_CFG, 0x00000013},
+	{ TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},
+	{ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},
+};
+
+static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {
+	1495012349, /* Pre-gain */
+
+	/* Gains : b0, b1, a0, a1, a2 */
+	536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */
+	134217728, -265414508, 131766272, 2140402222, -1071252997,  /* Band-1 */
+	268435456, -233515765, -33935948, 1839817267, -773826124,   /* Band-2 */
+	536870912, -672537913, 139851540, 1886437554, -824433167,   /* Band-3 */
+	268435456, -114439279, 173723964, 205743566, 278809729,     /* Band-4 */
+	1, 0, 0, 0, 0, /* Band-5 */
+	1, 0, 0, 0, 0, /* Band-6 */
+	1, 0, 0, 0, 0, /* Band-7 */
+	1, 0, 0, 0, 0, /* Band-8 */
+	1, 0, 0, 0, 0, /* Band-9 */
+	1, 0, 0, 0, 0, /* Band-10 */
+	1, 0, 0, 0, 0, /* Band-11 */
+
+	963423114, /* Post-gain */
+};
+
+static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {
+	23, /* Pre-shift */
+	30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */
+	28, /* Post-shift */
+};
+
+static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+
+static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				  unsigned int reg_data, unsigned int ram_offset,
+				  unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	/*
+	 * Since all ahub non-io modules work under same ahub clock it is not
+	 * necessary to check ahub read busy bit after every read.
+	 */
+	for (i = 0; i < size; i++)
+		regmap_read(regmap, reg_data, &data[i]);
+}
+
+static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				   unsigned int reg_data, unsigned int ram_offset,
+				   unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_peq_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	unsigned int val;
+
+	regmap_read(ope->peq_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
+
+	if (!mc->invert)
+		return 0;
+
+	ucontrol->value.integer.value[0] =
+		mc->max - ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tegra210_peq_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	bool change = false;
+	unsigned int val;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	if (mc->invert)
+		val = mc->max - val;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),
+				 val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			      params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		ucontrol->value.integer.value[i] = (long)data[i];
+
+	return 0;
+}
+
+static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		data[i] = (s32)ucontrol->value.integer.value[i];
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			       params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	return 1;
+}
+
+static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->value.integer.min = INT_MIN;
+	uinfo->value.integer.max = INT_MAX;
+	uinfo->count = params->num_regs;
+
+	return 0;
+}
+
+#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params",	  \
+		TEGRA210_PEQ_CFG_RAM_CTRL,				  \
+		TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params",  \
+		TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,			  \
+		TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f,	  \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+static const struct snd_kcontrol_new tegra210_peq_controls[] = {
+	SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,
+		       TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),
+
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),
+};
+
+static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_CG:
+	case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_peq_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_PEQ_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_STATUS:
+	case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_CFG_RAM_DATA:
+	case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_peq_regmap_config = {
+	.name			= "peq",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+	.writeable_reg		= tegra210_peq_wr_reg,
+	.readable_reg		= tegra210_peq_rd_reg,
+	.volatile_reg		= tegra210_peq_volatile_reg,
+	.precious_reg		= tegra210_peq_precious_reg,
+	.reg_defaults		= tegra210_peq_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_peq_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_write_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+}
+
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+	}
+}
+
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int i;
+
+	pm_runtime_get_sync(cmpnt->dev);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_MODE_MASK,
+		0 << TEGRA210_PEQ_CFG_MODE_SHIFT);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,
+		(TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);
+
+	/* Initialize PEQ AHUB RAM with default params */
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+
+		/* Set default gain params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		/* Set default shift params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,
+				       ARRAY_SIZE(tegra210_peq_controls));
+
+	return 0;
+}
+
+int tegra210_peq_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "equalizer");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get PEQ resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+	ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
+						&tegra210_peq_regmap_config);
+	if (IS_ERR(ope->peq_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->peq_regmap);
+	}
+
+	regcache_cache_only(ope->peq_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h
new file mode 100644
index 0000000..6d3de4f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_peq.h - Definitions for Tegra210 PEQ driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_PEQ_H__
+#define __TEGRA210_PEQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+/* Register offsets from PEQ base */
+#define TEGRA210_PEQ_SOFT_RESET				0x0
+#define TEGRA210_PEQ_CG					0x4
+#define TEGRA210_PEQ_STATUS				0x8
+#define TEGRA210_PEQ_CFG				0xc
+#define TEGRA210_PEQ_CFG_RAM_CTRL			0x10
+#define TEGRA210_PEQ_CFG_RAM_DATA			0x14
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL			0x18
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA			0x1c
+
+/* Fields in TEGRA210_PEQ_CFG */
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT		2
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK		(0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT)
+
+#define TEGRA210_PEQ_CFG_MODE_SHIFT			0
+#define TEGRA210_PEQ_CFG_MODE_MASK			(0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT)
+
+#define TEGRA210_PEQ_RAM_CTRL_RW_READ			0
+#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE			(1 << 14)
+#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/* PEQ register definition ends here */
+#define TEGRA210_PEQ_MAX_BIQUAD_STAGES			12
+
+#define TEGRA210_PEQ_MAX_CHANNELS			8
+
+#define TEGRA210_PEQ_BIQUAD_INIT_STAGE			5
+
+#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5)
+#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES)
+
+int tegra210_peq_regmap_init(struct platform_device *pdev);
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt);
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts);
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts);
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/6] ASoC: tegra: Add Tegra210 based OPE driver
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

The Output Processing Engine (OPE) is one of the AHUB client. It has
PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
sub blocks for data processing. The PEQ block gets samples from the MBDRC
block.

This patch registers OPE driver with ASoC framework. The component driver
exposes DAPM widgets, routes and kcontrols for the device. The DAI driver
exposes OPE interfaces, which can be used to connect different components
in the ASoC layer. Makefile and Kconfig support is added to allow build
the driver.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig          |    9 +
 sound/soc/tegra/Makefile         |    2 +
 sound/soc/tegra/tegra210_mbdrc.c | 1012 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_mbdrc.h |  215 ++++++++
 sound/soc/tegra/tegra210_ope.c   |  419 ++++++++++++++++
 sound/soc/tegra/tegra210_ope.h   |   90 ++++
 sound/soc/tegra/tegra210_peq.c   |  434 ++++++++++++++++
 sound/soc/tegra/tegra210_peq.h   |   56 +++
 8 files changed, 2237 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.c
 create mode 100644 sound/soc/tegra/tegra210_mbdrc.h
 create mode 100644 sound/soc/tegra/tegra210_ope.c
 create mode 100644 sound/soc/tegra/tegra210_ope.h
 create mode 100644 sound/soc/tegra/tegra210_peq.c
 create mode 100644 sound/soc/tegra/tegra210_peq.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2482d98..b6712a3 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -85,6 +85,15 @@ config SND_SOC_TEGRA210_I2S
 	  compatible devices.
 	  Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA210_OPE
+	tristate "Tegra210 OPE module"
+	help
+	  Config to enable the Output Processing Engine (OPE) which includes
+	  Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor
+	  (MBDRC) sub blocks for data processing. It can support up to 8
+	  channels.
+	  Say Y or M if you want to add support for Tegra210 OPE module.
+
 config SND_SOC_TEGRA186_ASRC
 	tristate "Tegra186 ASRC module"
 	help
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 70a498d..b723c78 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -19,6 +19,7 @@ snd-soc-tegra210-sfc-objs := tegra210_sfc.o
 snd-soc-tegra210-amx-objs := tegra210_amx.o
 snd-soc-tegra210-adx-objs := tegra210_adx.o
 snd-soc-tegra210-mixer-objs := tegra210_mixer.o
+snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
+obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
new file mode 100644
index 0000000..7d9da33
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.c
@@ -0,0 +1,1012 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_mbdrc.c - Tegra210 MBDRC driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+
+#define MBDRC_FILTER_REG(reg, id)					    \
+	((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
+
+#define MBDRC_FILTER_REG_DEFAULTS(id)					    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b},  \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666},	    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e},    \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a},   \
+	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+
+static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
+	{ TEGRA210_MBDRC_CFG, 0x0030de51},
+	{ TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
+	{ TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
+
+	MBDRC_FILTER_REG_DEFAULTS(0),
+	MBDRC_FILTER_REG_DEFAULTS(1),
+	MBDRC_FILTER_REG_DEFAULTS(2),
+};
+
+/* Default MBDRC parameters */
+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 */
+	.shift_ctrl		= 30,
+	.frame_size		= 32,
+	.channel_mask		= 0x3,
+	.fa_factor		= 2048,
+	.fr_factor		= 14747,
+
+	.band_params[MBDRC_LOW_BAND] = {
+		.band			= MBDRC_LOW_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1044928780,
+		.in_release_tc		= 138497695,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 80, 20, 6},
+		.out_threshold		= {155, 55, 13, 6},
+		.ratio			= {40960, 8192, 2867, 2048, 410},
+		.makeup_gain		= 4,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 14268942,
+		.gain_release_tc	= 1440547090,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params	= {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			961046798, -2030431983, 1073741824,
+			2030431983, -961046798,
+			/* Band-1 */
+			1030244425, -2099481453, 1073741824,
+			2099481453, -1030244425,
+			/* Band-2 */
+			1067169294, -2136327263, 1073741824,
+			2136327263, -1067169294,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_MID_BAND] = {
+		.band			= MBDRC_MID_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 1581413104,
+		.in_release_tc		= 35494783,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			-1005668963, 1073741824, 0,
+			1005668963, 0,
+			/* Band-1 */
+			998437058, -2067742187, 1073741824,
+			2067742187, -998437058,
+			/* Band-2 */
+			1051963422, -2121153948, 1073741824,
+			2121153948, -1051963422,
+			/* Band-3 */
+			434951949, -1306567134, 1073741824,
+			1306567134, -434951949,
+			/* Band-4 */
+			780656019, -1605955641, 1073741824,
+			1605955641, -780656019,
+			/* Band-5 */
+			1024497031, -1817128152, 1073741824,
+			1817128152, -1024497031,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	},
+
+	.band_params[MBDRC_HIGH_BAND] = {
+		.band			= MBDRC_HIGH_BAND,
+		.iir_stages		= 5,
+		.in_attack_tc		= 2144750688,
+		.in_release_tc		= 70402888,
+		.fast_attack_tc		= 2147483647,
+		.in_threshold		= {130, 50, 30, 6},
+		.out_threshold		= {106, 50, 30, 13},
+		.ratio			= {40960, 2867, 4096, 2867, 410},
+		.makeup_gain		= 6,
+		.gain_init		= 419430,
+		.gain_attack_tc		= 4766887,
+		.gain_release_tc	= 1044928780,
+		.fast_release_tc	= 2147480170,
+
+		.biquad_params = {
+			/*
+			 * Gains:
+			 *
+			 * b0, b1, a0,
+			 * a1, a2,
+			 */
+
+			/* Band-0 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-1 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-2 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-3 */
+			-619925131, 1073741824, 0,
+			619925131, 0,
+			/* Band-4 */
+			606839335, -1455425976, 1073741824,
+			1455425976, -606839335,
+			/* Band-5 */
+			917759617, -1724690840, 1073741824,
+			1724690840, -917759617,
+			/* Band-6 */
+			1073741824, 0, 0,
+			0, 0,
+			/* Band-7 */
+			1073741824, 0, 0,
+			0, 0,
+		}
+	}
+};
+
+static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				     unsigned int reg_data, unsigned int ram_offset,
+				     unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 (mc->max << mc->shift), val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+
+	regmap_read(ope->mbdrc_regmap, e->reg, &val);
+
+	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
+
+	return 0;
+}
+
+static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	bool change = false;
+	unsigned int val;
+	unsigned int mask;
+
+	if (ucontrol->value.enumerated.item[0] > e->items - 1)
+		return -EINVAL;
+
+	val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	mask = e->mask << e->shift_l;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
+				 &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &data[i]);
+
+		data[i] = ((data[i] & mask) >> shift);
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 mask = params->soc.mask;
+	u32 shift = params->shift;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
+					 data[i] << shift, &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	u32 val;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		regmap_read(ope->mbdrc_regmap, regs, &val);
+
+		data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
+			  TEGRA210_MBDRC_THRESH_1ST_SHIFT;
+		data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
+			      TEGRA210_MBDRC_THRESH_2ND_SHIFT;
+		data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
+			      TEGRA210_MBDRC_THRESH_3RD_SHIFT;
+		data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
+			      TEGRA210_MBDRC_THRESH_4TH_SHIFT;
+	}
+
+	return 0;
+}
+
+static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+	u32 regs = params->soc.base;
+	u32 num_regs = params->soc.num_regs;
+	bool change = false;
+	unsigned int i;
+
+	for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+		bool update = false;
+
+		data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			   ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			   ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			   ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			    TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff,
+					 data[i], &update);
+
+		change |= update;
+	}
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
+					    struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+	tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
+				 params->shift, data, params->soc.num_regs);
+
+	return 1;
+}
+
+static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = params->num_regs * sizeof(u32);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val;
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] =
+		((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
+
+	return 0;
+}
+
+static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	int val = ucontrol->value.integer.value[0];
+	bool change = false;
+
+	val += TEGRA210_MBDRC_MASTER_VOL_MIN;
+
+	regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+				 mc->max << mc->shift, val << mc->shift,
+				 &change);
+
+	regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+	return change ? 1 : 0;
+}
+
+static const char * const tegra210_mbdrc_mode_text[] = {
+	"Bypass", "Fullband", "Dualband", "Multiband"
+};
+
+static const struct soc_enum tegra210_mbdrc_mode_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
+			4, tegra210_mbdrc_mode_text);
+
+static const char * const tegra210_mbdrc_peak_rms_text[] = {
+	"Peak", "RMS"
+};
+
+static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
+			2, tegra210_mbdrc_peak_rms_text);
+
+static const char * const tegra210_mbdrc_filter_structure_text[] = {
+	"All-pass-tree", "Flexible"
+};
+
+static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
+			TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2,
+			tegra210_mbdrc_filter_structure_text);
+
+static const char * const tegra210_mbdrc_frame_size_text[] = {
+	"N1", "N2", "N4", "N8", "N16", "N32", "N64"
+};
+
+static const struct soc_enum tegra210_mbdrc_frame_size_enum =
+	SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
+			7, tegra210_mbdrc_frame_size_text);
+
+#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo)    \
+	TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		    \
+			    tegra210_mbdrc_band_params_get,		    \
+			    tegra210_mbdrc_band_params_put,		    \
+			    tegra210_mbdrc_param_info)
+
+#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo)	    \
+	TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT,    \
+			      xshift, xmask, xinfo)
+
+static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500);
+
+static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
+	SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Filter Structure",
+		     tegra210_mbdrc_filter_structure_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum,
+		     tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+	SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG,
+		       TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR,
+		       TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
+		       tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+	SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume",
+				 TEGRA210_MBDRC_MASTER_VOL,
+				 TEGRA210_MBDRC_MASTER_VOL_SHIFT,
+				 0, 0x1ff, 0,
+				 tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
+				 mdbrc_vol_tlv),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
+			    TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
+			    TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
+			    TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD,
+			    TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+			    tegra210_mbdrc_threshold_get,
+			    tegra210_mbdrc_threshold_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST,
+			    TEGRA210_MBDRC_FILTER_COUNT * 5,
+			    TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
+			    TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_INIT_GAIN_SHIFT,
+			    TEGRA210_MBDRC_INIT_GAIN_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
+			    TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain",
+			    TEGRA210_MBDRC_FAST_RELEASE,
+			    TEGRA210_MBDRC_FILTER_COUNT,
+			    TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
+			    TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			    tegra210_mbdrc_band_params_get,
+			    tegra210_mbdrc_band_params_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+
+	TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs",
+			    TEGRA210_MBDRC_CFG_RAM_CTRL +
+				(TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
+			    TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+			    tegra210_mbdrc_biquad_coeffs_get,
+			    tegra210_mbdrc_biquad_coeffs_put,
+			    tegra210_mbdrc_param_info),
+};
+
+static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_CG:
+	case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_mbdrc_wr_reg(dev, reg))
+		return true;
+
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_SOFT_RESET:
+	case TEGRA210_MBDRC_STATUS:
+	case TEGRA210_MBDRC_CFG_RAM_CTRL:
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
+{
+	if (reg >= TEGRA210_MBDRC_IIR_CFG)
+		reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+			(TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+			 TEGRA210_MBDRC_FILTER_COUNT));
+
+	switch (reg) {
+	case TEGRA210_MBDRC_CFG_RAM_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
+	.name			= "mbdrc",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_MBDRC_MAX_REG,
+	.writeable_reg		= tegra210_mbdrc_wr_reg,
+	.readable_reg		= tegra210_mbdrc_rd_reg,
+	.volatile_reg		= tegra210_mbdrc_volatile_reg,
+	.precious_reg		= tegra210_mbdrc_precious_reg,
+	.reg_defaults		= tegra210_mbdrc_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	u32 val = 0;
+	unsigned int i;
+
+	regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
+
+	if (val & TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
+		return 0;
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+			&conf->band_params[i];
+
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+					 reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
+					 0, (u32 *)&params->biquad_params[0],
+					 TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+	return 0;
+}
+
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+	unsigned int i;
+	u32 val;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	/* Initialize MBDRC registers and AHUB RAM with default params */
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
+		conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
+		conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
+		conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
+		conf->fliter_structure <<
+		TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
+		conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
+		__ffs(conf->frame_size) <<
+		TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
+		TEGRA210_MBDRC_CHANNEL_MASK_MASK,
+		conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+		TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+		conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+	for (i = 0; i < MBDRC_NUM_BAND; i++) {
+		const struct tegra210_mbdrc_band_params *params =
+						&conf->band_params[i];
+		u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IIR_CFG,
+			TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+			params->iir_stages <<
+				TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_ATTACK,
+			TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+			params->in_attack_tc <<
+				TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_IN_RELEASE,
+			TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+			params->in_release_tc <<
+				TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_ATTACK,
+			TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+			params->fast_attack_tc <<
+				TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
+
+		val = (((params->in_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->in_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->in_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->in_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+				   reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
+				   0xffffffff, val);
+
+		val = (((params->out_threshold[0] >>
+			 TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+			TEGRA210_MBDRC_THRESH_1ST_MASK) |
+			((params->out_threshold[1] >>
+			  TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_2ND_MASK) |
+			((params->out_threshold[2] >>
+			  TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_3RD_MASK) |
+			((params->out_threshold[3] >>
+			  TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+			 TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
+			0xffffffff, val);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_1ST,
+			TEGRA210_MBDRC_RATIO_1ST_MASK,
+			params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_2ND,
+			TEGRA210_MBDRC_RATIO_2ND_MASK,
+			params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_3RD,
+			TEGRA210_MBDRC_RATIO_3RD_MASK,
+			params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_4TH,
+			TEGRA210_MBDRC_RATIO_4TH_MASK,
+			params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_RATIO_5TH,
+			TEGRA210_MBDRC_RATIO_5TH_MASK,
+			params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
+			TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+			params->makeup_gain <<
+				TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_INIT_GAIN,
+			TEGRA210_MBDRC_INIT_GAIN_MASK,
+			params->gain_init <<
+				TEGRA210_MBDRC_INIT_GAIN_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
+			TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+			params->gain_attack_tc <<
+				TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
+			TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+			params->gain_release_tc <<
+				TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
+
+		regmap_update_bits(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_FAST_RELEASE,
+			TEGRA210_MBDRC_FAST_RELEASE_MASK,
+			params->fast_release_tc <<
+				TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
+
+		tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+			reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0,
+			(u32 *)&params->biquad_params[0],
+			TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
+				       ARRAY_SIZE(tegra210_mbdrc_controls));
+
+	return 0;
+}
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get MBDRC resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
+						  &tegra210_mbdrc_regmap_cfg);
+	if (IS_ERR(ope->mbdrc_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->mbdrc_regmap);
+	}
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
new file mode 100644
index 0000000..4c48da0
--- /dev/null
+++ b/sound/soc/tegra/tegra210_mbdrc.h
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_MBDRC_H__
+#define __TEGRA210_MBDRC_H__
+
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+/* Register offsets from TEGRA210_MBDRC*_BASE */
+#define TEGRA210_MBDRC_SOFT_RESET			0x4
+#define TEGRA210_MBDRC_CG				0x8
+#define TEGRA210_MBDRC_STATUS				0xc
+#define TEGRA210_MBDRC_CFG				0x28
+#define TEGRA210_MBDRC_CHANNEL_MASK			0x2c
+#define TEGRA210_MBDRC_MASTER_VOL			0x30
+#define TEGRA210_MBDRC_FAST_FACTOR			0x34
+
+#define TEGRA210_MBDRC_FILTER_COUNT			3
+#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE		0x4
+
+#define TEGRA210_MBDRC_IIR_CFG				0x38
+#define TEGRA210_MBDRC_IN_ATTACK			0x44
+#define TEGRA210_MBDRC_IN_RELEASE			0x50
+#define TEGRA210_MBDRC_FAST_ATTACK			0x5c
+#define TEGRA210_MBDRC_IN_THRESHOLD			0x68
+#define TEGRA210_MBDRC_OUT_THRESHOLD			0x74
+#define TEGRA210_MBDRC_RATIO_1ST			0x80
+#define TEGRA210_MBDRC_RATIO_2ND			0x8c
+#define TEGRA210_MBDRC_RATIO_3RD			0x98
+#define TEGRA210_MBDRC_RATIO_4TH			0xa4
+#define TEGRA210_MBDRC_RATIO_5TH			0xb0
+#define TEGRA210_MBDRC_MAKEUP_GAIN			0xbc
+#define TEGRA210_MBDRC_INIT_GAIN			0xc8
+#define TEGRA210_MBDRC_GAIN_ATTACK			0xd4
+#define TEGRA210_MBDRC_GAIN_RELEASE			0xe0
+#define TEGRA210_MBDRC_FAST_RELEASE			0xec
+#define TEGRA210_MBDRC_CFG_RAM_CTRL			0xf8
+#define TEGRA210_MBDRC_CFG_RAM_DATA			0x104
+
+#define TEGRA210_MBDRC_MAX_REG				(TEGRA210_MBDRC_CFG_RAM_DATA +		\
+							 (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *	\
+							  (TEGRA210_MBDRC_FILTER_COUNT - 1)))
+
+/* Fields for TEGRA210_MBDRC_CFG */
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT		16
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK		(0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT		14
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK		(0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+#define TEGRA210_MBDRC_CFG_PEAK				(1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT	13
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK	(0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX	(1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT		8
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK		(0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT		4
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK		(0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT		0
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK		(0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS		(0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */
+#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT		0
+#define TEGRA210_MBDRC_CHANNEL_MASK_MASK		(0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MASTER_VOL */
+#define TEGRA210_MBDRC_MASTER_VOL_SHIFT			23
+#define TEGRA210_MBDRC_MASTER_VOL_MIN			-256
+#define TEGRA210_MBDRC_MASTER_VOL_MAX			256
+
+/* Fields for TEGRA210_MBDRC_FAST_FACTOR */
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT	16
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK		(0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IIR_CFG */
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT		0
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK		(0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_ATTACK */
+#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_RELEASE */
+#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT		0
+#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK		(0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_ATTACK */
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT		0
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */
+#define TEGRA210_MBDRC_THRESH_4TH_SHIFT			24
+#define TEGRA210_MBDRC_THRESH_4TH_MASK			(0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_3RD_SHIFT			16
+#define TEGRA210_MBDRC_THRESH_3RD_MASK			(0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_2ND_SHIFT			8
+#define TEGRA210_MBDRC_THRESH_2ND_MASK			(0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_1ST_SHIFT			0
+#define TEGRA210_MBDRC_THRESH_1ST_MASK			(0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_1ST */
+#define TEGRA210_MBDRC_RATIO_1ST_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_1ST_MASK			(0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_2ND */
+#define TEGRA210_MBDRC_RATIO_2ND_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_2ND_MASK			(0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_3RD */
+#define TEGRA210_MBDRC_RATIO_3RD_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_3RD_MASK			(0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_4TH */
+#define TEGRA210_MBDRC_RATIO_4TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_4TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_5TH */
+#define TEGRA210_MBDRC_RATIO_5TH_SHIFT			0
+#define TEGRA210_MBDRC_RATIO_5TH_MASK			(0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */
+#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT		0
+#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK			(0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_INIT_GAIN */
+#define TEGRA210_MBDRC_INIT_GAIN_SHIFT			0
+#define TEGRA210_MBDRC_INIT_GAIN_MASK			(0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */
+#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_ATTACK_MASK			(0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */
+#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_GAIN_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_RELEASE */
+#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT		0
+#define TEGRA210_MBDRC_FAST_RELEASE_MASK		(0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_RAM_CTRL_RW_READ			0
+#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE		(1 << 14)
+#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/*
+ * Order and size of each structure element for following structures should not
+ * be altered size order of elements and their size are based on PEQ co-eff ram
+ * and shift ram layout.
+ */
+#define TEGRA210_MBDRC_THRESHOLD_NUM				4
+#define TEGRA210_MBDRC_RATIO_NUM				(TEGRA210_MBDRC_THRESHOLD_NUM + 1)
+#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES			8
+
+/* Order of these enums are same as the order of band specific hw registers */
+enum {
+	MBDRC_LOW_BAND,
+	MBDRC_MID_BAND,
+	MBDRC_HIGH_BAND,
+	MBDRC_NUM_BAND,
+};
+
+struct tegra210_mbdrc_band_params {
+	u32 band;
+	u32 iir_stages;
+	u32 in_attack_tc;
+	u32 in_release_tc;
+	u32 fast_attack_tc;
+	u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+	u32 ratio[TEGRA210_MBDRC_RATIO_NUM];
+	u32 makeup_gain;
+	u32 gain_init;
+	u32 gain_attack_tc;
+	u32 gain_release_tc;
+	u32 fast_release_tc;
+	/* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */
+	u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5];
+};
+
+struct tegra210_mbdrc_config {
+	unsigned int mode;
+	unsigned int rms_off;
+	unsigned int peak_rms_mode;
+	unsigned int fliter_structure;
+	unsigned int shift_ctrl;
+	unsigned int frame_size;
+	unsigned int channel_mask;
+	unsigned int fa_factor;	/* Fast attack factor */
+	unsigned int fr_factor;	/* Fast release factor */
+	struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND];
+};
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev);
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt);
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt);
+
+#endif
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
new file mode 100644
index 0000000..3dd2bde
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ope.c - Tegra210 OPE driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_ope_reg_defaults[] = {
+	{ TEGRA210_OPE_RX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_TX_INT_MASK, 0x00000001},
+	{ TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
+	{ TEGRA210_OPE_CG, 0x1},
+};
+
+static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
+				      struct snd_pcm_hw_params *params,
+				      unsigned int reg)
+{
+	int channels, audio_bits;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 2)
+		return -EINVAL;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+	cif_conf.audio_bits = audio_bits;
+	cif_conf.client_bits = audio_bits;
+
+	tegra_set_cif(ope->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
+	int err;
+
+	/* Set RX and TX CIF */
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_RX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
+		return err;
+	}
+
+	err = tegra210_ope_set_audio_cif(ope, params,
+					 TEGRA210_OPE_TX_CIF_CTRL);
+	if (err) {
+		dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
+		return err;
+	}
+
+	tegra210_mbdrc_hw_params(dai->component);
+
+	return err;
+}
+
+static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
+
+	tegra210_peq_component_init(cmpnt);
+	tegra210_mbdrc_component_init(cmpnt);
+
+	/*
+	 * The OPE, PEQ and MBDRC functionalities are combined under one
+	 * device registered by OPE driver. In fact OPE HW block includes
+	 * sub blocks PEQ and MBDRC. However driver registers separate
+	 * regmap interfaces for each of these. ASoC core depends on
+	 * dev_get_regmap() to populate the regmap field for a given ASoC
+	 * component. A component can have one regmap reference and since
+	 * the DAPM routes depend on OPE regmap only, below explicit
+	 * assignment is done to highlight this. This is needed for ASoC
+	 * core to access correct regmap during DAPM path setup.
+	 */
+	snd_soc_component_init_regmap(cmpnt, ope->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
+	.hw_params	= tegra210_ope_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_ope_dais[] = {
+	{
+		.name = "OPE-RX-CIF",
+		.playback = {
+			.stream_name = "RX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "RX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+	},
+	{
+		.name = "OPE-TX-CIF",
+		.playback = {
+			.stream_name = "TX-CIF-Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "TX-CIF-Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_ope_dai_ops,
+	}
+};
+
+static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
+			     TEGRA210_OPE_EN_SHIFT, 0),
+};
+
+#define OPE_ROUTES(sname)					\
+	{ "RX XBAR-" sname,	NULL,	"XBAR-TX" },		\
+	{ "RX-CIF-" sname,	NULL,	"RX XBAR-" sname },	\
+	{ "RX",			NULL,	"RX-CIF-" sname },	\
+	{ "TX-CIF-" sname,	NULL,	"TX" },			\
+	{ "TX XBAR-" sname,	NULL,	"TX-CIF-" sname },	\
+	{ "XBAR-RX",		NULL,	"TX XBAR-" sname }
+
+static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
+	{ "TX", NULL, "RX" },
+	OPE_ROUTES("Playback"),
+	OPE_ROUTES("Capture"),
+};
+
+static const char * const tegra210_ope_data_dir_text[] = {
+	"MBDRC to PEQ",
+	"PEQ to MBDRC"
+};
+
+static const struct soc_enum tegra210_ope_data_dir_enum =
+	SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
+			2, tegra210_ope_data_dir_text);
+
+static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+
+	ucontrol->value.enumerated.item[0] = ope->data_dir;
+
+	return 0;
+}
+
+static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int value = ucontrol->value.enumerated.item[0];
+
+	if (value == ope->data_dir)
+		return 0;
+
+	ope->data_dir = value;
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new tegra210_ope_controls[] = {
+	SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
+		     tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
+};
+
+static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
+	.probe			= tegra210_ope_component_probe,
+	.dapm_widgets		= tegra210_ope_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ope_widgets),
+	.dapm_routes		= tegra210_ope_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ope_routes),
+	.controls		= tegra210_ope_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_ope_controls),
+};
+
+static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
+	case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
+	case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
+	case TEGRA210_OPE_DIR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_ope_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_OPE_RX_STATUS:
+	case TEGRA210_OPE_RX_INT_STATUS:
+	case TEGRA210_OPE_TX_STATUS:
+	case TEGRA210_OPE_TX_INT_STATUS:
+	case TEGRA210_OPE_SOFT_RESET:
+	case TEGRA210_OPE_STATUS:
+	case TEGRA210_OPE_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_ope_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_OPE_DIR,
+	.writeable_reg		= tegra210_ope_wr_reg,
+	.readable_reg		= tegra210_ope_rd_reg,
+	.volatile_reg		= tegra210_ope_volatile_reg,
+	.reg_defaults		= tegra210_ope_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_ope_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_ope_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope;
+	void __iomem *regs;
+	int err;
+
+	ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
+	if (!ope)
+		return -ENOMEM;
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ope->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_ope_regmap_config);
+	if (IS_ERR(ope->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->regmap);
+	}
+
+	regcache_cache_only(ope->regmap, true);
+
+	dev_set_drvdata(dev, ope);
+
+	err = tegra210_peq_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "PEQ init failed\n");
+		return err;
+	}
+
+	err = tegra210_mbdrc_regmap_init(pdev);
+	if (err < 0) {
+		dev_err(dev, "MBDRC init failed\n");
+		return err;
+	}
+
+	err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
+					      tegra210_ope_dais,
+					      ARRAY_SIZE(tegra210_ope_dais));
+	if (err) {
+		dev_err(dev, "can't register OPE component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_ope_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
+			  ope->peq_biquad_shifts);
+
+	regcache_cache_only(ope->mbdrc_regmap, true);
+	regcache_cache_only(ope->peq_regmap, true);
+	regcache_cache_only(ope->regmap, true);
+
+	regcache_mark_dirty(ope->regmap);
+	regcache_mark_dirty(ope->peq_regmap);
+	regcache_mark_dirty(ope->mbdrc_regmap);
+
+	return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+{
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+	regcache_cache_only(ope->regmap, false);
+	regcache_cache_only(ope->peq_regmap, false);
+	regcache_cache_only(ope->mbdrc_regmap, false);
+
+	regcache_sync(ope->regmap);
+	regcache_sync(ope->peq_regmap);
+	regcache_sync(ope->mbdrc_regmap);
+
+	tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
+			     ope->peq_biquad_shifts);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_ope_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+			   tegra210_ope_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_ope_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ope" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
+
+static struct platform_driver tegra210_ope_driver = {
+	.driver = {
+		.name = "tegra210-ope",
+		.of_match_table = tegra210_ope_of_match,
+		.pm = &tegra210_ope_pm_ops,
+	},
+	.probe = tegra210_ope_probe,
+	.remove = tegra210_ope_remove,
+};
+module_platform_driver(tegra210_ope_driver)
+
+MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h
new file mode 100644
index 0000000..2835af6
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ope.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ope.h - Definitions for Tegra210 OPE driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_OPE_H__
+#define __TEGRA210_OPE_H__
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tegra210_peq.h"
+
+/*
+ * OPE_RX registers are with respect to XBAR.
+ * The data comes from XBAR to OPE
+ */
+#define TEGRA210_OPE_RX_STATUS			0xc
+#define TEGRA210_OPE_RX_INT_STATUS		0x10
+#define TEGRA210_OPE_RX_INT_MASK		0x14
+#define TEGRA210_OPE_RX_INT_SET			0x18
+#define TEGRA210_OPE_RX_INT_CLEAR		0x1c
+#define TEGRA210_OPE_RX_CIF_CTRL		0x20
+
+/*
+ * OPE_TX registers are with respect to XBAR.
+ * The data goes out from OPE to XBAR
+ */
+#define TEGRA210_OPE_TX_STATUS			0x4c
+#define TEGRA210_OPE_TX_INT_STATUS		0x50
+#define TEGRA210_OPE_TX_INT_MASK		0x54
+#define TEGRA210_OPE_TX_INT_SET			0x58
+#define TEGRA210_OPE_TX_INT_CLEAR		0x5c
+#define TEGRA210_OPE_TX_CIF_CTRL		0x60
+
+/* OPE Gloabal registers */
+#define TEGRA210_OPE_ENABLE			0x80
+#define TEGRA210_OPE_SOFT_RESET			0x84
+#define TEGRA210_OPE_CG				0x88
+#define TEGRA210_OPE_STATUS			0x8c
+#define TEGRA210_OPE_INT_STATUS			0x90
+#define TEGRA210_OPE_DIR			0x94
+
+/* Fields for TEGRA210_OPE_ENABLE */
+#define TEGRA210_OPE_EN_SHIFT			0
+#define TEGRA210_OPE_EN				(1 << TEGRA210_OPE_EN_SHIFT)
+
+/* Fields for TEGRA210_OPE_SOFT_RESET */
+#define TEGRA210_OPE_SOFT_RESET_SHIFT		0
+#define TEGRA210_OPE_SOFT_RESET_EN		(1 << TEGRA210_OPE_SOFT_RESET_SHIFT)
+
+#define TEGRA210_OPE_DIR_SHIFT			0
+
+struct tegra210_ope {
+	struct regmap *regmap;
+	struct regmap *peq_regmap;
+	struct regmap *mbdrc_regmap;
+	u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+	u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH];
+	unsigned int data_dir;
+};
+
+/* Extension of soc_bytes structure defined in sound/soc.h */
+struct tegra_soc_bytes {
+	struct soc_bytes soc;
+	u32 shift; /* Used as offset for AHUB RAM related programing */
+};
+
+/* Utility structures for using mixer control of type snd_soc_bytes */
+#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,		\
+			    xhandler_get, xhandler_put, xinfo)		\
+{									\
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,				\
+	.name	= xname,						\
+	.info	= xinfo,						\
+	.get	= xhandler_get,						\
+	.put	= xhandler_put,						\
+	.private_value = ((unsigned long)&(struct tegra_soc_bytes)	\
+	{								\
+		.soc.base	= xbase,				\
+		.soc.num_regs	= xregs,				\
+		.soc.mask	= xmask,				\
+		.shift		= xshift				\
+	})								\
+}
+
+#endif
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
new file mode 100644
index 0000000..205d956
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_peq.c - Tegra210 PEQ driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+
+static const struct reg_default tegra210_peq_reg_defaults[] = {
+	{ TEGRA210_PEQ_CFG, 0x00000013},
+	{ TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},
+	{ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},
+};
+
+static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {
+	1495012349, /* Pre-gain */
+
+	/* Gains : b0, b1, a0, a1, a2 */
+	536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */
+	134217728, -265414508, 131766272, 2140402222, -1071252997,  /* Band-1 */
+	268435456, -233515765, -33935948, 1839817267, -773826124,   /* Band-2 */
+	536870912, -672537913, 139851540, 1886437554, -824433167,   /* Band-3 */
+	268435456, -114439279, 173723964, 205743566, 278809729,     /* Band-4 */
+	1, 0, 0, 0, 0, /* Band-5 */
+	1, 0, 0, 0, 0, /* Band-6 */
+	1, 0, 0, 0, 0, /* Band-7 */
+	1, 0, 0, 0, 0, /* Band-8 */
+	1, 0, 0, 0, 0, /* Band-9 */
+	1, 0, 0, 0, 0, /* Band-10 */
+	1, 0, 0, 0, 0, /* Band-11 */
+
+	963423114, /* Post-gain */
+};
+
+static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {
+	23, /* Pre-shift */
+	30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */
+	28, /* Post-shift */
+};
+
+static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+
+static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				  unsigned int reg_data, unsigned int ram_offset,
+				  unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	/*
+	 * Since all ahub non-io modules work under same ahub clock it is not
+	 * necessary to check ahub read busy bit after every read.
+	 */
+	for (i = 0; i < size; i++)
+		regmap_read(regmap, reg_data, &data[i]);
+}
+
+static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+				   unsigned int reg_data, unsigned int ram_offset,
+				   unsigned int *data, size_t size)
+{
+	unsigned int val;
+	unsigned int i;
+
+	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+	val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;
+
+	regmap_write(regmap, reg_ctrl, val);
+
+	for (i = 0; i < size; i++)
+		regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_peq_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	unsigned int val;
+
+	regmap_read(ope->peq_regmap, mc->reg, &val);
+
+	ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
+
+	if (!mc->invert)
+		return 0;
+
+	ucontrol->value.integer.value[0] =
+		mc->max - ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int tegra210_peq_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	bool change = false;
+	unsigned int val;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	if (mc->invert)
+		val = mc->max - val;
+
+	val = val << mc->shift;
+
+	regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),
+				 val, &change);
+
+	return change ? 1 : 0;
+}
+
+static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			      params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		ucontrol->value.integer.value[i] = (long)data[i];
+
+	return 0;
+}
+
+static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	u32 i, reg_ctrl = params->soc.base;
+	u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+	s32 *data = (s32 *)biquad_coeff_buffer;
+
+	for (i = 0; i < params->soc.num_regs; i++)
+		data[i] = (s32)ucontrol->value.integer.value[i];
+
+	pm_runtime_get_sync(cmpnt->dev);
+
+	tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,
+			       params->shift, data, params->soc.num_regs);
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	return 1;
+}
+
+static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->value.integer.min = INT_MIN;
+	uinfo->value.integer.max = INT_MAX;
+	uinfo->count = params->num_regs;
+
+	return 0;
+}
+
+#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params",	  \
+		TEGRA210_PEQ_CFG_RAM_CTRL,				  \
+		TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan)				  \
+	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params",  \
+		TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,			  \
+		TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH,			  \
+		(TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f,	  \
+		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \
+		tegra210_peq_param_info)
+
+static const struct snd_kcontrol_new tegra210_peq_controls[] = {
+	SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,
+		       TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,
+		       TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,
+		       tegra210_peq_get, tegra210_peq_put),
+
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),
+	TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),
+
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),
+	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),
+};
+
+static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_CG:
+	case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_peq_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_PEQ_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_SOFT_RESET:
+	case TEGRA210_PEQ_STATUS:
+	case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_PEQ_CFG_RAM_DATA:
+	case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tegra210_peq_regmap_config = {
+	.name			= "peq",
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+	.writeable_reg		= tegra210_peq_wr_reg,
+	.readable_reg		= tegra210_peq_rd_reg,
+	.volatile_reg		= tegra210_peq_volatile_reg,
+	.precious_reg		= tegra210_peq_precious_reg,
+	.reg_defaults		= tegra210_peq_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_peq_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_write_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+}
+
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts)
+{
+	unsigned int i;
+
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			biquad_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		tegra210_peq_read_ram(regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			biquad_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+	}
+}
+
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt)
+{
+	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int i;
+
+	pm_runtime_get_sync(cmpnt->dev);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_MODE_MASK,
+		0 << TEGRA210_PEQ_CFG_MODE_SHIFT);
+	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,
+		(TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<
+		TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);
+
+	/* Initialize PEQ AHUB RAM with default params */
+	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+
+		/* Set default gain params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_CTRL,
+			TEGRA210_PEQ_CFG_RAM_DATA,
+			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_gains,
+			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+		/* Set default shift params */
+		tegra210_peq_write_ram(ope->peq_regmap,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+			(u32 *)&biquad_init_shifts,
+			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+	}
+
+	pm_runtime_put_sync(cmpnt->dev);
+
+	snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,
+				       ARRAY_SIZE(tegra210_peq_controls));
+
+	return 0;
+}
+
+int tegra210_peq_regmap_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_ope *ope = dev_get_drvdata(dev);
+	struct device_node *child;
+	struct resource mem;
+	void __iomem *regs;
+	int err;
+
+	child = of_get_child_by_name(dev->of_node, "equalizer");
+	if (!child)
+		return -ENODEV;
+
+	err = of_address_to_resource(child, 0, &mem);
+	of_node_put(child);
+	if (err < 0) {
+		dev_err(dev, "fail to get PEQ resource\n");
+		return err;
+	}
+
+	mem.flags = IORESOURCE_MEM;
+	regs = devm_ioremap_resource(dev, &mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+	ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
+						&tegra210_peq_regmap_config);
+	if (IS_ERR(ope->peq_regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(ope->peq_regmap);
+	}
+
+	regcache_cache_only(ope->peq_regmap, true);
+
+	return 0;
+}
diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h
new file mode 100644
index 0000000..6d3de4f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_peq.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_peq.h - Definitions for Tegra210 PEQ driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_PEQ_H__
+#define __TEGRA210_PEQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+/* Register offsets from PEQ base */
+#define TEGRA210_PEQ_SOFT_RESET				0x0
+#define TEGRA210_PEQ_CG					0x4
+#define TEGRA210_PEQ_STATUS				0x8
+#define TEGRA210_PEQ_CFG				0xc
+#define TEGRA210_PEQ_CFG_RAM_CTRL			0x10
+#define TEGRA210_PEQ_CFG_RAM_DATA			0x14
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL			0x18
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA			0x1c
+
+/* Fields in TEGRA210_PEQ_CFG */
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT		2
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK		(0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT)
+
+#define TEGRA210_PEQ_CFG_MODE_SHIFT			0
+#define TEGRA210_PEQ_CFG_MODE_MASK			(0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT)
+
+#define TEGRA210_PEQ_RAM_CTRL_RW_READ			0
+#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE			(1 << 14)
+#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN		(1 << 13)
+#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN		(1 << 12)
+#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK		0x1ff
+
+/* PEQ register definition ends here */
+#define TEGRA210_PEQ_MAX_BIQUAD_STAGES			12
+
+#define TEGRA210_PEQ_MAX_CHANNELS			8
+
+#define TEGRA210_PEQ_BIQUAD_INIT_STAGE			5
+
+#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5)
+#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES)
+
+int tegra210_peq_regmap_init(struct platform_device *pdev);
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt);
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+			  u32 *biquad_shifts);
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+		       u32 *biquad_shifts);
+
+#endif
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 3/6] ASoC: tegra: AHUB routes for OPE module
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Add AHUB routes for OPE module. The OPE module can be plugged into audio
path as per the need. The routing controls can be used to setup the audio
path with OPE similar to the already existing routes. The support is added
on Tegra210 and later Tegra SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/tegra210_ahub.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index e1f90da..b38d205 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
 	DAI(MIXER1 TX3),
 	DAI(MIXER1 TX4),
 	DAI(MIXER1 TX5),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
+	DAI(OPE2 RX),
+	DAI(OPE2 TX),
 };
 
 static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
@@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
 	DAI(ASRC1 RX6),
 	DAI(ASRC1 TX6),
 	DAI(ASRC1 RX7),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
 };
 
 static const char * const tegra210_ahub_mux_texts[] = {
@@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = {
 	"MIXER1 TX3",
 	"MIXER1 TX4",
 	"MIXER1 TX5",
+	"OPE1",
+	"OPE2",
 };
 
 static const char * const tegra186_ahub_mux_texts[] = {
@@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = {
 	"ASRC1 TX4",
 	"ASRC1 TX5",
 	"ASRC1 TX6",
+	"OPE1",
 };
 
 static const unsigned int tegra210_ahub_mux_values[] = {
@@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = {
 	MUX_VALUE(1, 2),
 	MUX_VALUE(1, 3),
 	MUX_VALUE(1, 4),
+	/* OPE */
+	MUX_VALUE(2, 0),
+	MUX_VALUE(2, 1),
 };
 
 static const unsigned int tegra186_ahub_mux_values[] = {
@@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = {
 	MUX_VALUE(3, 27),
 	MUX_VALUE(3, 28),
 	MUX_VALUE(3, 29),
+	/* OPE */
+	MUX_VALUE(2, 0),
 };
 
 /* Controls for t210 */
@@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26);
 MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27);
 MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28);
 MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
+MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40);
+MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41);
 
 /* Controls for t186 */
 MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
@@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f);
 MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70);
 MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71);
 MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72);
+MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40);
 
 /* Controls for t234 */
 MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44);
@@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
 	TX_WIDGETS("MIXER1 TX3"),
 	TX_WIDGETS("MIXER1 TX4"),
 	TX_WIDGETS("MIXER1 TX5"),
+	WIDGETS("OPE1", t210_ope1_tx),
+	WIDGETS("OPE2", t210_ope2_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
@@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
@@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 #define TEGRA_COMMON_MUX_ROUTES(name)					\
@@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"MIXER1 TX2",	"MIXER1 TX2 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX3",	"MIXER1 TX3 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX4",	"MIXER1 TX4 XBAR-RX" },	\
-	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" },
+	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" }, \
+	{ name " Mux",		"OPE1",		"OPE1 XBAR-RX" },
+
+#define TEGRA210_ONLY_MUX_ROUTES(name)					\
+	{ name " Mux",          "OPE2",         "OPE2 XBAR-RX" },
 
 #define TEGRA186_ONLY_MUX_ROUTES(name)					\
 	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
@@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"ASRC1 TX5",	"ASRC1 TX5 XBAR-RX" },	\
 	{ name " Mux",		"ASRC1 TX6",	"ASRC1 TX6 XBAR-RX" },
 
-#define TEGRA210_MUX_ROUTES(name)						\
-	TEGRA_COMMON_MUX_ROUTES(name)
+#define TEGRA210_MUX_ROUTES(name)					\
+	TEGRA_COMMON_MUX_ROUTES(name)					\
+	TEGRA210_ONLY_MUX_ROUTES(name)
 
-#define TEGRA186_MUX_ROUTES(name)						\
+#define TEGRA186_MUX_ROUTES(name)					\
 	TEGRA_COMMON_MUX_ROUTES(name)					\
 	TEGRA186_ONLY_MUX_ROUTES(name)
 
@@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
 	TEGRA210_MUX_ROUTES("MIXER1 RX8")
 	TEGRA210_MUX_ROUTES("MIXER1 RX9")
 	TEGRA210_MUX_ROUTES("MIXER1 RX10")
+	TEGRA210_MUX_ROUTES("OPE1")
+	TEGRA210_MUX_ROUTES("OPE2")
 };
 
 static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
@@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
 	TEGRA186_MUX_ROUTES("ASRC1 RX5")
 	TEGRA186_MUX_ROUTES("ASRC1 RX6")
 	TEGRA186_MUX_ROUTES("ASRC1 RX7")
+	TEGRA186_MUX_ROUTES("OPE1")
 };
 
 static const struct snd_soc_component_driver tegra210_ahub_component = {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 3/6] ASoC: tegra: AHUB routes for OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

Add AHUB routes for OPE module. The OPE module can be plugged into audio
path as per the need. The routing controls can be used to setup the audio
path with OPE similar to the already existing routes. The support is added
on Tegra210 and later Tegra SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/tegra210_ahub.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index e1f90da..b38d205 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
 	DAI(MIXER1 TX3),
 	DAI(MIXER1 TX4),
 	DAI(MIXER1 TX5),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
+	DAI(OPE2 RX),
+	DAI(OPE2 TX),
 };
 
 static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
@@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
 	DAI(ASRC1 RX6),
 	DAI(ASRC1 TX6),
 	DAI(ASRC1 RX7),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
 };
 
 static const char * const tegra210_ahub_mux_texts[] = {
@@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = {
 	"MIXER1 TX3",
 	"MIXER1 TX4",
 	"MIXER1 TX5",
+	"OPE1",
+	"OPE2",
 };
 
 static const char * const tegra186_ahub_mux_texts[] = {
@@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = {
 	"ASRC1 TX4",
 	"ASRC1 TX5",
 	"ASRC1 TX6",
+	"OPE1",
 };
 
 static const unsigned int tegra210_ahub_mux_values[] = {
@@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = {
 	MUX_VALUE(1, 2),
 	MUX_VALUE(1, 3),
 	MUX_VALUE(1, 4),
+	/* OPE */
+	MUX_VALUE(2, 0),
+	MUX_VALUE(2, 1),
 };
 
 static const unsigned int tegra186_ahub_mux_values[] = {
@@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = {
 	MUX_VALUE(3, 27),
 	MUX_VALUE(3, 28),
 	MUX_VALUE(3, 29),
+	/* OPE */
+	MUX_VALUE(2, 0),
 };
 
 /* Controls for t210 */
@@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26);
 MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27);
 MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28);
 MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
+MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40);
+MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41);
 
 /* Controls for t186 */
 MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
@@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f);
 MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70);
 MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71);
 MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72);
+MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40);
 
 /* Controls for t234 */
 MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44);
@@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
 	TX_WIDGETS("MIXER1 TX3"),
 	TX_WIDGETS("MIXER1 TX4"),
 	TX_WIDGETS("MIXER1 TX5"),
+	WIDGETS("OPE1", t210_ope1_tx),
+	WIDGETS("OPE2", t210_ope2_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
@@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
@@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 #define TEGRA_COMMON_MUX_ROUTES(name)					\
@@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"MIXER1 TX2",	"MIXER1 TX2 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX3",	"MIXER1 TX3 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX4",	"MIXER1 TX4 XBAR-RX" },	\
-	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" },
+	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" }, \
+	{ name " Mux",		"OPE1",		"OPE1 XBAR-RX" },
+
+#define TEGRA210_ONLY_MUX_ROUTES(name)					\
+	{ name " Mux",          "OPE2",         "OPE2 XBAR-RX" },
 
 #define TEGRA186_ONLY_MUX_ROUTES(name)					\
 	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
@@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"ASRC1 TX5",	"ASRC1 TX5 XBAR-RX" },	\
 	{ name " Mux",		"ASRC1 TX6",	"ASRC1 TX6 XBAR-RX" },
 
-#define TEGRA210_MUX_ROUTES(name)						\
-	TEGRA_COMMON_MUX_ROUTES(name)
+#define TEGRA210_MUX_ROUTES(name)					\
+	TEGRA_COMMON_MUX_ROUTES(name)					\
+	TEGRA210_ONLY_MUX_ROUTES(name)
 
-#define TEGRA186_MUX_ROUTES(name)						\
+#define TEGRA186_MUX_ROUTES(name)					\
 	TEGRA_COMMON_MUX_ROUTES(name)					\
 	TEGRA186_ONLY_MUX_ROUTES(name)
 
@@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
 	TEGRA210_MUX_ROUTES("MIXER1 RX8")
 	TEGRA210_MUX_ROUTES("MIXER1 RX9")
 	TEGRA210_MUX_ROUTES("MIXER1 RX10")
+	TEGRA210_MUX_ROUTES("OPE1")
+	TEGRA210_MUX_ROUTES("OPE2")
 };
 
 static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
@@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
 	TEGRA186_MUX_ROUTES("ASRC1 RX5")
 	TEGRA186_MUX_ROUTES("ASRC1 RX6")
 	TEGRA186_MUX_ROUTES("ASRC1 RX7")
+	TEGRA186_MUX_ROUTES("OPE1")
 };
 
 static const struct snd_soc_component_driver tegra210_ahub_component = {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 3/6] ASoC: tegra: AHUB routes for OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Add AHUB routes for OPE module. The OPE module can be plugged into audio
path as per the need. The routing controls can be used to setup the audio
path with OPE similar to the already existing routes. The support is added
on Tegra210 and later Tegra SoCs where OPE module is present.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/tegra210_ahub.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index e1f90da..b38d205 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
 	DAI(MIXER1 TX3),
 	DAI(MIXER1 TX4),
 	DAI(MIXER1 TX5),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
+	DAI(OPE2 RX),
+	DAI(OPE2 TX),
 };
 
 static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
@@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
 	DAI(ASRC1 RX6),
 	DAI(ASRC1 TX6),
 	DAI(ASRC1 RX7),
+	/* XBAR -> OPE -> XBAR */
+	DAI(OPE1 RX),
+	DAI(OPE1 TX),
 };
 
 static const char * const tegra210_ahub_mux_texts[] = {
@@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = {
 	"MIXER1 TX3",
 	"MIXER1 TX4",
 	"MIXER1 TX5",
+	"OPE1",
+	"OPE2",
 };
 
 static const char * const tegra186_ahub_mux_texts[] = {
@@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = {
 	"ASRC1 TX4",
 	"ASRC1 TX5",
 	"ASRC1 TX6",
+	"OPE1",
 };
 
 static const unsigned int tegra210_ahub_mux_values[] = {
@@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = {
 	MUX_VALUE(1, 2),
 	MUX_VALUE(1, 3),
 	MUX_VALUE(1, 4),
+	/* OPE */
+	MUX_VALUE(2, 0),
+	MUX_VALUE(2, 1),
 };
 
 static const unsigned int tegra186_ahub_mux_values[] = {
@@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = {
 	MUX_VALUE(3, 27),
 	MUX_VALUE(3, 28),
 	MUX_VALUE(3, 29),
+	/* OPE */
+	MUX_VALUE(2, 0),
 };
 
 /* Controls for t210 */
@@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26);
 MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27);
 MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28);
 MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
+MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40);
+MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41);
 
 /* Controls for t186 */
 MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
@@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f);
 MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70);
 MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71);
 MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72);
+MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40);
 
 /* Controls for t234 */
 MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44);
@@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
 	TX_WIDGETS("MIXER1 TX3"),
 	TX_WIDGETS("MIXER1 TX4"),
 	TX_WIDGETS("MIXER1 TX5"),
+	WIDGETS("OPE1", t210_ope1_tx),
+	WIDGETS("OPE2", t210_ope2_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
@@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
@@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	TX_WIDGETS("ASRC1 TX4"),
 	TX_WIDGETS("ASRC1 TX5"),
 	TX_WIDGETS("ASRC1 TX6"),
+	WIDGETS("OPE1", t186_ope1_tx),
 };
 
 #define TEGRA_COMMON_MUX_ROUTES(name)					\
@@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"MIXER1 TX2",	"MIXER1 TX2 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX3",	"MIXER1 TX3 XBAR-RX" },	\
 	{ name " Mux",		"MIXER1 TX4",	"MIXER1 TX4 XBAR-RX" },	\
-	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" },
+	{ name " Mux",		"MIXER1 TX5",	"MIXER1 TX5 XBAR-RX" }, \
+	{ name " Mux",		"OPE1",		"OPE1 XBAR-RX" },
+
+#define TEGRA210_ONLY_MUX_ROUTES(name)					\
+	{ name " Mux",          "OPE2",         "OPE2 XBAR-RX" },
 
 #define TEGRA186_ONLY_MUX_ROUTES(name)					\
 	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
@@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
 	{ name " Mux",		"ASRC1 TX5",	"ASRC1 TX5 XBAR-RX" },	\
 	{ name " Mux",		"ASRC1 TX6",	"ASRC1 TX6 XBAR-RX" },
 
-#define TEGRA210_MUX_ROUTES(name)						\
-	TEGRA_COMMON_MUX_ROUTES(name)
+#define TEGRA210_MUX_ROUTES(name)					\
+	TEGRA_COMMON_MUX_ROUTES(name)					\
+	TEGRA210_ONLY_MUX_ROUTES(name)
 
-#define TEGRA186_MUX_ROUTES(name)						\
+#define TEGRA186_MUX_ROUTES(name)					\
 	TEGRA_COMMON_MUX_ROUTES(name)					\
 	TEGRA186_ONLY_MUX_ROUTES(name)
 
@@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
 	TEGRA210_MUX_ROUTES("MIXER1 RX8")
 	TEGRA210_MUX_ROUTES("MIXER1 RX9")
 	TEGRA210_MUX_ROUTES("MIXER1 RX10")
+	TEGRA210_MUX_ROUTES("OPE1")
+	TEGRA210_MUX_ROUTES("OPE2")
 };
 
 static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
@@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
 	TEGRA186_MUX_ROUTES("ASRC1 RX5")
 	TEGRA186_MUX_ROUTES("ASRC1 RX6")
 	TEGRA186_MUX_ROUTES("ASRC1 RX7")
+	TEGRA186_MUX_ROUTES("OPE1")
 };
 
 static const struct snd_soc_component_driver tegra210_ahub_component = {
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 4/6] arm64: defconfig: Build Tegra OPE module
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Output Processing Engine (OPE) module is a client of AHUB on Tegra210
and later generations of Tegra SoCs. Enable the driver build to use
this in audio path.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 7d11053..3e154cb 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -808,6 +808,7 @@ CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA210_AHUB=m
 CONFIG_SND_SOC_TEGRA210_DMIC=m
 CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA210_OPE=m
 CONFIG_SND_SOC_TEGRA186_ASRC=m
 CONFIG_SND_SOC_TEGRA186_DSPK=m
 CONFIG_SND_SOC_TEGRA210_ADMAIF=m
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 4/6] arm64: defconfig: Build Tegra OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

Output Processing Engine (OPE) module is a client of AHUB on Tegra210
and later generations of Tegra SoCs. Enable the driver build to use
this in audio path.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 7d11053..3e154cb 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -808,6 +808,7 @@ CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA210_AHUB=m
 CONFIG_SND_SOC_TEGRA210_DMIC=m
 CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA210_OPE=m
 CONFIG_SND_SOC_TEGRA186_ASRC=m
 CONFIG_SND_SOC_TEGRA186_DSPK=m
 CONFIG_SND_SOC_TEGRA210_ADMAIF=m
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 4/6] arm64: defconfig: Build Tegra OPE module
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Output Processing Engine (OPE) module is a client of AHUB on Tegra210
and later generations of Tegra SoCs. Enable the driver build to use
this in audio path.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 7d11053..3e154cb 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -808,6 +808,7 @@ CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA210_AHUB=m
 CONFIG_SND_SOC_TEGRA210_DMIC=m
 CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA210_OPE=m
 CONFIG_SND_SOC_TEGRA186_ASRC=m
 CONFIG_SND_SOC_TEGRA186_DSPK=m
 CONFIG_SND_SOC_TEGRA210_ADMAIF=m
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 5/6] arm64: tegra: Add OPE device on Tegra210 and later
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Output Processing Engine (OPE) is a client of AHUB and is present on
Tegra210 and later generations of Tegra SoC. Add this device on the
relevant SoC DTSI files.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 40 ++++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra234.dtsi | 23 ++++++++++++++++++
 4 files changed, 109 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 0e9afc3..cd8c4f3 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -509,6 +509,29 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@2908000 {
+				compatible = "nvidia,tegra186-ope",
+					     "nvidia,tegra210-ope";
+				reg = <0x2908000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@2908100 {
+					compatible = "nvidia,tegra186-peq",
+						     "nvidia,tegra210-peq";
+					reg = <0x2908100 0x100>;
+				};
+
+				dynamic-range-compressor@2908200 {
+					compatible = "nvidia,tegra186-mbdrc",
+						     "nvidia,tegra210-mbdrc";
+					reg = <0x2908200 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@290bb00 {
 				compatible = "nvidia,tegra186-amixer",
 					     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index d1f8248..e65d1b0 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -562,6 +562,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra194-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra194-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra194-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_amixer: amixer@290bb00 {
 					compatible = "nvidia,tegra194-amixer",
 						     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 4f0e51f..04383a1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1723,6 +1723,46 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@702d8000 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@702d8100 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8100 0x100>;
+				};
+
+				dynamic-range-compressor@702d8200 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8200 0x200>;
+				};
+			};
+
+			tegra_ope2: processing-engine@702d8400 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8400 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE2";
+				status = "disabled";
+
+				equalizer@702d8500 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8500 0x100>;
+				};
+
+				dynamic-range-compressor@702d8600 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8600 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@702dbb00 {
 				compatible = "nvidia,tegra210-amixer";
 				reg = <0x702dbb00 0x800>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index cb3af53..7e07684 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -304,6 +304,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra234-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra234-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra234-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_mvc1: mvc@290a000 {
 					compatible = "nvidia,tegra234-mvc",
 						     "nvidia,tegra210-mvc";
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 5/6] arm64: tegra: Add OPE device on Tegra210 and later
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

Output Processing Engine (OPE) is a client of AHUB and is present on
Tegra210 and later generations of Tegra SoC. Add this device on the
relevant SoC DTSI files.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 40 ++++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra234.dtsi | 23 ++++++++++++++++++
 4 files changed, 109 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 0e9afc3..cd8c4f3 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -509,6 +509,29 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@2908000 {
+				compatible = "nvidia,tegra186-ope",
+					     "nvidia,tegra210-ope";
+				reg = <0x2908000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@2908100 {
+					compatible = "nvidia,tegra186-peq",
+						     "nvidia,tegra210-peq";
+					reg = <0x2908100 0x100>;
+				};
+
+				dynamic-range-compressor@2908200 {
+					compatible = "nvidia,tegra186-mbdrc",
+						     "nvidia,tegra210-mbdrc";
+					reg = <0x2908200 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@290bb00 {
 				compatible = "nvidia,tegra186-amixer",
 					     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index d1f8248..e65d1b0 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -562,6 +562,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra194-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra194-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra194-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_amixer: amixer@290bb00 {
 					compatible = "nvidia,tegra194-amixer",
 						     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 4f0e51f..04383a1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1723,6 +1723,46 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@702d8000 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@702d8100 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8100 0x100>;
+				};
+
+				dynamic-range-compressor@702d8200 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8200 0x200>;
+				};
+			};
+
+			tegra_ope2: processing-engine@702d8400 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8400 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE2";
+				status = "disabled";
+
+				equalizer@702d8500 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8500 0x100>;
+				};
+
+				dynamic-range-compressor@702d8600 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8600 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@702dbb00 {
 				compatible = "nvidia,tegra210-amixer";
 				reg = <0x702dbb00 0x800>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index cb3af53..7e07684 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -304,6 +304,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra234-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra234-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra234-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_mvc1: mvc@290a000 {
 					compatible = "nvidia,tegra234-mvc",
 						     "nvidia,tegra210-mvc";
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 5/6] arm64: tegra: Add OPE device on Tegra210 and later
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Output Processing Engine (OPE) is a client of AHUB and is present on
Tegra210 and later generations of Tegra SoC. Add this device on the
relevant SoC DTSI files.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 23 ++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 40 ++++++++++++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra234.dtsi | 23 ++++++++++++++++++
 4 files changed, 109 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 0e9afc3..cd8c4f3 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -509,6 +509,29 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@2908000 {
+				compatible = "nvidia,tegra186-ope",
+					     "nvidia,tegra210-ope";
+				reg = <0x2908000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@2908100 {
+					compatible = "nvidia,tegra186-peq",
+						     "nvidia,tegra210-peq";
+					reg = <0x2908100 0x100>;
+				};
+
+				dynamic-range-compressor@2908200 {
+					compatible = "nvidia,tegra186-mbdrc",
+						     "nvidia,tegra210-mbdrc";
+					reg = <0x2908200 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@290bb00 {
 				compatible = "nvidia,tegra186-amixer",
 					     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index d1f8248..e65d1b0 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -562,6 +562,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra194-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra194-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra194-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_amixer: amixer@290bb00 {
 					compatible = "nvidia,tegra194-amixer",
 						     "nvidia,tegra210-amixer";
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 4f0e51f..04383a1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1723,6 +1723,46 @@
 				status = "disabled";
 			};
 
+			tegra_ope1: processing-engine@702d8000 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8000 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE1";
+				status = "disabled";
+
+				equalizer@702d8100 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8100 0x100>;
+				};
+
+				dynamic-range-compressor@702d8200 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8200 0x200>;
+				};
+			};
+
+			tegra_ope2: processing-engine@702d8400 {
+				compatible = "nvidia,tegra210-ope";
+				reg = <0x702d8400 0x100>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
+				sound-name-prefix = "OPE2";
+				status = "disabled";
+
+				equalizer@702d8500 {
+					compatible = "nvidia,tegra210-peq";
+					reg = <0x702d8500 0x100>;
+				};
+
+				dynamic-range-compressor@702d8600 {
+					compatible = "nvidia,tegra210-mbdrc";
+					reg = <0x702d8600 0x200>;
+				};
+			};
+
 			tegra_amixer: amixer@702dbb00 {
 				compatible = "nvidia,tegra210-amixer";
 				reg = <0x702dbb00 0x800>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index cb3af53..7e07684 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -304,6 +304,29 @@
 					status = "disabled";
 				};
 
+				tegra_ope1: processing-engine@2908000 {
+					compatible = "nvidia,tegra234-ope",
+						     "nvidia,tegra210-ope";
+					reg = <0x2908000 0x100>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					ranges;
+					sound-name-prefix = "OPE1";
+					status = "disabled";
+
+					equalizer@2908100 {
+						compatible = "nvidia,tegra234-peq",
+							     "nvidia,tegra210-peq";
+						reg = <0x2908100 0x100>;
+					};
+
+					dynamic-range-compressor@2908200 {
+						compatible = "nvidia,tegra234-mbdrc",
+							     "nvidia,tegra210-mbdrc";
+						reg = <0x2908200 0x200>;
+					};
+				};
+
 				tegra_mvc1: mvc@290a000 {
 					compatible = "nvidia,tegra234-mvc",
 						     "nvidia,tegra210-mvc";
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 6/6] arm64: tegra: Enable OPE on various platforms
  2022-05-27 10:26 ` Sameer Pujar
  (?)
@ 2022-05-27 10:26   ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Enable OPE module usage on various Jetson platforms. This can be plugged
into an audio path using ALSA mixer controls. Add audio-graph-port binding
to use OPE device with generic audio-graph based sound card.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 43 +++++++++++
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 84 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 84 ++++++++++++++++++++++
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  | 43 +++++++++++
 6 files changed, 340 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index 70737a0..bd18977 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -915,6 +915,22 @@
 						remote-endpoint = <&asrc_in7_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@70 {
+					reg = <0x70>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@71 {
+					reg = <0x71>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
 			};
 
 			admaif@290f000 {
@@ -1911,6 +1927,31 @@
 				};
 			};
 
+			processing-engine@2908000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@290bb00 {
 				status = "okay";
 
@@ -2552,6 +2593,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2571,6 +2613,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* I/O */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index bce518a..fafd707 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -868,6 +868,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1710,6 +1726,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2273,6 +2314,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2291,6 +2333,7 @@
 		       <&mixer_out4_port>, <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
index 7acc32d..4cee935 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
@@ -878,6 +878,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1770,6 +1786,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2323,6 +2364,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2342,6 +2384,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s3_port>, <&i2s5_port>,
 		       <&dmic1_port>, <&dmic2_port>, <&dmic4_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 328fbfe..1e26ca9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -682,6 +682,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1251,6 +1301,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1281,6 +1363,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1293,6 +1376,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 746bd52..749b44c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -1074,6 +1074,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1611,6 +1661,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1884,6 +1966,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1896,6 +1979,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s3_port>, <&i2s4_port>,
 		       <&dmic1_port>, <&dmic2_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
index eaf1994..3f6c399 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
@@ -867,6 +867,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				i2s@2901000 {
@@ -1490,6 +1506,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				mvc@290a000 {
 					status = "okay";
 
@@ -2044,6 +2085,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2062,6 +2104,7 @@
 		       <&mix_out4_port>, <&mix_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 6/6] arm64: tegra: Enable OPE on various platforms
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, Sameer Pujar, linux-kernel, jonathanh,
	linux-tegra, linux-arm-kernel

Enable OPE module usage on various Jetson platforms. This can be plugged
into an audio path using ALSA mixer controls. Add audio-graph-port binding
to use OPE device with generic audio-graph based sound card.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 43 +++++++++++
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 84 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 84 ++++++++++++++++++++++
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  | 43 +++++++++++
 6 files changed, 340 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index 70737a0..bd18977 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -915,6 +915,22 @@
 						remote-endpoint = <&asrc_in7_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@70 {
+					reg = <0x70>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@71 {
+					reg = <0x71>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
 			};
 
 			admaif@290f000 {
@@ -1911,6 +1927,31 @@
 				};
 			};
 
+			processing-engine@2908000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@290bb00 {
 				status = "okay";
 
@@ -2552,6 +2593,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2571,6 +2613,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* I/O */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index bce518a..fafd707 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -868,6 +868,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1710,6 +1726,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2273,6 +2314,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2291,6 +2333,7 @@
 		       <&mixer_out4_port>, <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
index 7acc32d..4cee935 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
@@ -878,6 +878,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1770,6 +1786,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2323,6 +2364,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2342,6 +2384,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s3_port>, <&i2s5_port>,
 		       <&dmic1_port>, <&dmic2_port>, <&dmic4_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 328fbfe..1e26ca9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -682,6 +682,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1251,6 +1301,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1281,6 +1363,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1293,6 +1376,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 746bd52..749b44c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -1074,6 +1074,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1611,6 +1661,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1884,6 +1966,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1896,6 +1979,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s3_port>, <&i2s4_port>,
 		       <&dmic1_port>, <&dmic2_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
index eaf1994..3f6c399 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
@@ -867,6 +867,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				i2s@2901000 {
@@ -1490,6 +1506,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				mvc@290a000 {
 					status = "okay";
 
@@ -2044,6 +2085,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2062,6 +2104,7 @@
 		       <&mix_out4_port>, <&mix_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 6/6] arm64: tegra: Enable OPE on various platforms
@ 2022-05-27 10:26   ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-27 10:26 UTC (permalink / raw)
  To: broonie, robh+dt, krzysztof.kozlowski+dt, thierry.reding,
	catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Sameer Pujar

Enable OPE module usage on various Jetson platforms. This can be plugged
into an audio path using ALSA mixer controls. Add audio-graph-port binding
to use OPE device with generic audio-graph based sound card.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 43 +++++++++++
 .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi | 43 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 84 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 84 ++++++++++++++++++++++
 .../dts/nvidia/tegra234-p3737-0000+p3701-0000.dts  | 43 +++++++++++
 6 files changed, 340 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index 70737a0..bd18977 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -915,6 +915,22 @@
 						remote-endpoint = <&asrc_in7_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@70 {
+					reg = <0x70>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@71 {
+					reg = <0x71>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
 			};
 
 			admaif@290f000 {
@@ -1911,6 +1927,31 @@
 				};
 			};
 
+			processing-engine@2908000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@290bb00 {
 				status = "okay";
 
@@ -2552,6 +2593,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2571,6 +2613,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* I/O */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index bce518a..fafd707 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -868,6 +868,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1710,6 +1726,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2273,6 +2314,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2291,6 +2333,7 @@
 		       <&mixer_out4_port>, <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
index 7acc32d..4cee935 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
@@ -878,6 +878,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				admaif@290f000 {
@@ -1770,6 +1786,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				amixer@290bb00 {
 					status = "okay";
 
@@ -2323,6 +2364,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2342,6 +2384,7 @@
 		       <&mixer_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s3_port>, <&i2s5_port>,
 		       <&dmic1_port>, <&dmic2_port>, <&dmic4_port>,
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 328fbfe..1e26ca9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -682,6 +682,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1251,6 +1301,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1281,6 +1363,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1293,6 +1376,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
 		       <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 746bd52..749b44c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -1074,6 +1074,56 @@
 				};
 			};
 
+			processing-engine@702d8000 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope1_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_in_ep>;
+						};
+					};
+
+					ope1_out_port: port@1 {
+						reg = <0x1>;
+
+						ope1_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope1_out_ep>;
+						};
+					};
+				};
+			};
+
+			processing-engine@702d8400 {
+				status = "okay";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0x0>;
+
+						ope2_cif_in_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_in_ep>;
+						};
+					};
+
+					ope2_out_port: port@1 {
+						reg = <0x1>;
+
+						ope2_cif_out_ep: endpoint {
+							remote-endpoint = <&xbar_ope2_out_ep>;
+						};
+					};
+				};
+			};
+
 			amixer@702dbb00 {
 				status = "okay";
 
@@ -1611,6 +1661,38 @@
 						remote-endpoint = <&mixer_out5_ep>;
 					};
 				};
+
+				xbar_ope1_in_port: port@41 {
+					reg = <0x41>;
+
+					xbar_ope1_in_ep: endpoint {
+						remote-endpoint = <&ope1_cif_in_ep>;
+					};
+				};
+
+				port@42 {
+					reg = <0x42>;
+
+					xbar_ope1_out_ep: endpoint {
+						remote-endpoint = <&ope1_cif_out_ep>;
+					};
+				};
+
+				xbar_ope2_in_port: port@43 {
+					reg = <0x43>;
+
+					xbar_ope2_in_ep: endpoint {
+						remote-endpoint = <&ope2_cif_in_ep>;
+					};
+				};
+
+				port@44 {
+					reg = <0x44>;
+
+					xbar_ope2_out_ep: endpoint {
+						remote-endpoint = <&ope2_cif_out_ep>;
+					};
+				};
 			};
 		};
 	};
@@ -1884,6 +1966,7 @@
 		       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
 		       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
 		       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+		       <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -1896,6 +1979,7 @@
 		       <&mixer_out1_port>, <&mixer_out2_port>,
 		       <&mixer_out3_port>, <&mixer_out4_port>,
 		       <&mixer_out5_port>,
+		       <&ope1_out_port>, <&ope2_out_port>,
 		       /* I/O DAP Ports */
 		       <&i2s3_port>, <&i2s4_port>,
 		       <&dmic1_port>, <&dmic2_port>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
index eaf1994..3f6c399 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
@@ -867,6 +867,22 @@
 							remote-endpoint = <&asrc_in7_ep>;
 						};
 					};
+
+					xbar_ope1_in_port: port@70 {
+						reg = <0x70>;
+
+						xbar_ope1_in_ep: endpoint {
+							remote-endpoint = <&ope1_cif_in_ep>;
+						};
+					};
+
+					port@71 {
+						reg = <0x71>;
+
+						xbar_ope1_out_ep: endpoint {
+							remote-endpoint = <&ope1_cif_out_ep>;
+						};
+					};
 				};
 
 				i2s@2901000 {
@@ -1490,6 +1506,31 @@
 					};
 				};
 
+				processing-engine@2908000 {
+					status = "okay";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0x0>;
+
+							ope1_cif_in_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_in_ep>;
+							};
+						};
+
+						ope1_out_port: port@1 {
+							reg = <0x1>;
+
+							ope1_cif_out_ep: endpoint {
+								remote-endpoint = <&xbar_ope1_out_ep>;
+							};
+						};
+					};
+				};
+
 				mvc@290a000 {
 					status = "okay";
 
@@ -2044,6 +2085,7 @@
 		       <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>,
 		       <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>,
 		       <&xbar_asrc_in7_port>,
+		       <&xbar_ope1_in_port>,
 		       /* HW accelerators */
 		       <&sfc1_out_port>, <&sfc2_out_port>,
 		       <&sfc3_out_port>, <&sfc4_out_port>,
@@ -2062,6 +2104,7 @@
 		       <&mix_out4_port>, <&mix_out5_port>,
 		       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
 		       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+		       <&ope1_out_port>,
 		       /* BE I/O Ports */
 		       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
 		       <&dmic3_port>;
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
  2022-05-27 10:26   ` Sameer Pujar
  (?)
@ 2022-05-29 14:09     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-29 14:09 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel

On 27/05/2022 12:26, Sameer Pujar wrote:
> This patch adds YAML schema for DT bindings of Output Processing
> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
> binding doc for these blocks are added as well. The OPE will be
> registered as an ASoC component and can be plugged into an audio
> path as per need via ALSA mixer controls. The DT bindings are
> applicable on Tegra210 and later SoCs where OPE module is present.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
>  .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>  .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>  .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>  .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>  4 files changed, 186 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> index 6df6f85..47b6e71 100644
> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> @@ -110,6 +110,10 @@ patternProperties:
>      type: object
>      $ref: nvidia,tegra186-asrc.yaml#
>  
> +  '^processing-engine@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-ope.yaml#
> +
>  required:
>    - compatible
>    - reg
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> new file mode 100644
> index 0000000..0d55328
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> @@ -0,0 +1,47 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 MBDRC Device Tree Bindings

Previous comments - s/Device Tree Bindings//
 -  still applies. Please do not ignore it.

> +
> +description:
> +  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
> +  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
> +  Audio Client Interface (ACIF). MBDRC can be used as a traditional
> +  single full band or a dual band or a multi band dynamic processor.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-mbdrc
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-mbdrc
> +              - nvidia,tegra194-mbdrc
> +              - nvidia,tegra186-mbdrc
> +          - const: nvidia,tegra210-mbdrc
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    dynamic-range-compressor@702d8200 {
> +        compatible = "nvidia,tegra210-mbdrc";
> +        reg = <0x702d8200 0x200>;
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> new file mode 100644
> index 0000000..7cbc756
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 OPE Device Tree Bindings

Ditto.

> +
> +description:
> +  The Output Processing Engine (OPE) is one of the AHUB client. It has
> +  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
> +  sub blocks for data processing.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +allOf:
> +  - $ref: name-prefix.yaml#
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-ope
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-ope
> +              - nvidia,tegra194-ope
> +              - nvidia,tegra186-ope
> +          - const: nvidia,tegra210-ope
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 1
> +
> +  ranges: true
> +
> +  sound-name-prefix:
> +    pattern: "^OPE[1-9]$"
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    properties:
> +      port@0:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF (Audio Client Interface) input port. This is connected
> +          to corresponding ACIF output port on AHUB (Audio Hub).
> +
> +      port@1:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF output port. This is connected to corresponding ACIF
> +          input port on AHUB.
> +
> +patternProperties:
> +  '^equalizer@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-peq.yaml#
> +
> +  '^dynamic-range-compressor@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-mbdrc.yaml#
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    processing-engine@702d8000 {
> +        compatible = "nvidia,tegra210-ope";
> +        reg = <0x702d8000 0x100>;
> +        sound-name-prefix = "OPE1";
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> new file mode 100644
> index 0000000..fea4c63
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 PEQ Device Tree Bindings

Ditto

> +
> +description:
> +  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
> +  each filter tuned based on certain parameters. It can be used to
> +  equalize the irregularities in the speaker frequency response.
> +  PEQ sits inside Output Processing Engine (OPE) which interfaces
> +  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-peq
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-peq
> +              - nvidia,tegra194-peq
> +              - nvidia,tegra186-peq
> +          - const: nvidia,tegra210-peq
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    equalizer@702d8100 {
> +        compatible = "nvidia,tegra210-peq";
> +        reg = <0x702d8100 0x100>;
> +    };
> +
> +...


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-29 14:09     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-29 14:09 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, linux-kernel, jonathanh, linux-tegra,
	linux-arm-kernel

On 27/05/2022 12:26, Sameer Pujar wrote:
> This patch adds YAML schema for DT bindings of Output Processing
> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
> binding doc for these blocks are added as well. The OPE will be
> registered as an ASoC component and can be plugged into an audio
> path as per need via ALSA mixer controls. The DT bindings are
> applicable on Tegra210 and later SoCs where OPE module is present.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
>  .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>  .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>  .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>  .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>  4 files changed, 186 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> index 6df6f85..47b6e71 100644
> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> @@ -110,6 +110,10 @@ patternProperties:
>      type: object
>      $ref: nvidia,tegra186-asrc.yaml#
>  
> +  '^processing-engine@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-ope.yaml#
> +
>  required:
>    - compatible
>    - reg
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> new file mode 100644
> index 0000000..0d55328
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> @@ -0,0 +1,47 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 MBDRC Device Tree Bindings

Previous comments - s/Device Tree Bindings//
 -  still applies. Please do not ignore it.

> +
> +description:
> +  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
> +  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
> +  Audio Client Interface (ACIF). MBDRC can be used as a traditional
> +  single full band or a dual band or a multi band dynamic processor.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-mbdrc
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-mbdrc
> +              - nvidia,tegra194-mbdrc
> +              - nvidia,tegra186-mbdrc
> +          - const: nvidia,tegra210-mbdrc
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    dynamic-range-compressor@702d8200 {
> +        compatible = "nvidia,tegra210-mbdrc";
> +        reg = <0x702d8200 0x200>;
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> new file mode 100644
> index 0000000..7cbc756
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 OPE Device Tree Bindings

Ditto.

> +
> +description:
> +  The Output Processing Engine (OPE) is one of the AHUB client. It has
> +  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
> +  sub blocks for data processing.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +allOf:
> +  - $ref: name-prefix.yaml#
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-ope
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-ope
> +              - nvidia,tegra194-ope
> +              - nvidia,tegra186-ope
> +          - const: nvidia,tegra210-ope
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 1
> +
> +  ranges: true
> +
> +  sound-name-prefix:
> +    pattern: "^OPE[1-9]$"
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    properties:
> +      port@0:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF (Audio Client Interface) input port. This is connected
> +          to corresponding ACIF output port on AHUB (Audio Hub).
> +
> +      port@1:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF output port. This is connected to corresponding ACIF
> +          input port on AHUB.
> +
> +patternProperties:
> +  '^equalizer@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-peq.yaml#
> +
> +  '^dynamic-range-compressor@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-mbdrc.yaml#
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    processing-engine@702d8000 {
> +        compatible = "nvidia,tegra210-ope";
> +        reg = <0x702d8000 0x100>;
> +        sound-name-prefix = "OPE1";
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> new file mode 100644
> index 0000000..fea4c63
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 PEQ Device Tree Bindings

Ditto

> +
> +description:
> +  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
> +  each filter tuned based on certain parameters. It can be used to
> +  equalize the irregularities in the speaker frequency response.
> +  PEQ sits inside Output Processing Engine (OPE) which interfaces
> +  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-peq
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-peq
> +              - nvidia,tegra194-peq
> +              - nvidia,tegra186-peq
> +          - const: nvidia,tegra210-peq
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    equalizer@702d8100 {
> +        compatible = "nvidia,tegra210-peq";
> +        reg = <0x702d8100 0x100>;
> +    };
> +
> +...


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-29 14:09     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-29 14:09 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel

On 27/05/2022 12:26, Sameer Pujar wrote:
> This patch adds YAML schema for DT bindings of Output Processing
> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
> binding doc for these blocks are added as well. The OPE will be
> registered as an ASoC component and can be plugged into an audio
> path as per need via ALSA mixer controls. The DT bindings are
> applicable on Tegra210 and later SoCs where OPE module is present.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
>  .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>  .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>  .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>  .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>  4 files changed, 186 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>  create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> index 6df6f85..47b6e71 100644
> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
> @@ -110,6 +110,10 @@ patternProperties:
>      type: object
>      $ref: nvidia,tegra186-asrc.yaml#
>  
> +  '^processing-engine@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-ope.yaml#
> +
>  required:
>    - compatible
>    - reg
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> new file mode 100644
> index 0000000..0d55328
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
> @@ -0,0 +1,47 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 MBDRC Device Tree Bindings

Previous comments - s/Device Tree Bindings//
 -  still applies. Please do not ignore it.

> +
> +description:
> +  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
> +  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
> +  Audio Client Interface (ACIF). MBDRC can be used as a traditional
> +  single full band or a dual band or a multi band dynamic processor.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-mbdrc
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-mbdrc
> +              - nvidia,tegra194-mbdrc
> +              - nvidia,tegra186-mbdrc
> +          - const: nvidia,tegra210-mbdrc
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    dynamic-range-compressor@702d8200 {
> +        compatible = "nvidia,tegra210-mbdrc";
> +        reg = <0x702d8200 0x200>;
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> new file mode 100644
> index 0000000..7cbc756
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
> @@ -0,0 +1,87 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 OPE Device Tree Bindings

Ditto.

> +
> +description:
> +  The Output Processing Engine (OPE) is one of the AHUB client. It has
> +  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
> +  sub blocks for data processing.
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +allOf:
> +  - $ref: name-prefix.yaml#
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-ope
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-ope
> +              - nvidia,tegra194-ope
> +              - nvidia,tegra186-ope
> +          - const: nvidia,tegra210-ope
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 1
> +
> +  ranges: true
> +
> +  sound-name-prefix:
> +    pattern: "^OPE[1-9]$"
> +
> +  ports:
> +    $ref: /schemas/graph.yaml#/properties/ports
> +    properties:
> +      port@0:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF (Audio Client Interface) input port. This is connected
> +          to corresponding ACIF output port on AHUB (Audio Hub).
> +
> +      port@1:
> +        $ref: audio-graph-port.yaml#
> +        unevaluatedProperties: false
> +        description:
> +          OPE ACIF output port. This is connected to corresponding ACIF
> +          input port on AHUB.
> +
> +patternProperties:
> +  '^equalizer@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-peq.yaml#
> +
> +  '^dynamic-range-compressor@[0-9a-f]+$':
> +    type: object
> +    $ref: nvidia,tegra210-mbdrc.yaml#
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    processing-engine@702d8000 {
> +        compatible = "nvidia,tegra210-ope";
> +        reg = <0x702d8000 0x100>;
> +        sound-name-prefix = "OPE1";
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> new file mode 100644
> index 0000000..fea4c63
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra210 PEQ Device Tree Bindings

Ditto

> +
> +description:
> +  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
> +  each filter tuned based on certain parameters. It can be used to
> +  equalize the irregularities in the speaker frequency response.
> +  PEQ sits inside Output Processing Engine (OPE) which interfaces
> +  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
> +
> +maintainers:
> +  - Jon Hunter <jonathanh@nvidia.com>
> +  - Mohan Kumar <mkumard@nvidia.com>
> +  - Sameer Pujar <spujar@nvidia.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: nvidia,tegra210-peq
> +      - items:
> +          - enum:
> +              - nvidia,tegra234-peq
> +              - nvidia,tegra194-peq
> +              - nvidia,tegra186-peq
> +          - const: nvidia,tegra210-peq
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    equalizer@702d8100 {
> +        compatible = "nvidia,tegra210-peq";
> +        reg = <0x702d8100 0x100>;
> +    };
> +
> +...


Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
  2022-05-29 14:09     ` Krzysztof Kozlowski
  (?)
@ 2022-05-30  4:21       ` Sameer Pujar
  -1 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-30  4:21 UTC (permalink / raw)
  To: Krzysztof Kozlowski, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel


On 29-05-2022 19:39, Krzysztof Kozlowski wrote:
> On 27/05/2022 12:26, Sameer Pujar wrote:
>> This patch adds YAML schema for DT bindings of Output Processing
>> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
>> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
>> binding doc for these blocks are added as well. The OPE will be
>> registered as an ASoC component and can be plugged into an audio
>> path as per need via ALSA mixer controls. The DT bindings are
>> applicable on Tegra210 and later SoCs where OPE module is present.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
>>   .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>>   .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>>   .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>>   .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>>   4 files changed, 186 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> index 6df6f85..47b6e71 100644
>> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> @@ -110,6 +110,10 @@ patternProperties:
>>       type: object
>>       $ref: nvidia,tegra186-asrc.yaml#
>>
>> +  '^processing-engine@[0-9a-f]+$':
>> +    type: object
>> +    $ref: nvidia,tegra210-ope.yaml#
>> +
>>   required:
>>     - compatible
>>     - reg
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> new file mode 100644
>> index 0000000..0d55328
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> @@ -0,0 +1,47 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Tegra210 MBDRC Device Tree Bindings
> Previous comments - s/Device Tree Bindings//
>   -  still applies. Please do not ignore it.

I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-30  4:21       ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-30  4:21 UTC (permalink / raw)
  To: Krzysztof Kozlowski, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, linux-kernel, jonathanh, linux-tegra,
	linux-arm-kernel


On 29-05-2022 19:39, Krzysztof Kozlowski wrote:
> On 27/05/2022 12:26, Sameer Pujar wrote:
>> This patch adds YAML schema for DT bindings of Output Processing
>> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
>> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
>> binding doc for these blocks are added as well. The OPE will be
>> registered as an ASoC component and can be plugged into an audio
>> path as per need via ALSA mixer controls. The DT bindings are
>> applicable on Tegra210 and later SoCs where OPE module is present.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
>>   .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>>   .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>>   .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>>   .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>>   4 files changed, 186 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> index 6df6f85..47b6e71 100644
>> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> @@ -110,6 +110,10 @@ patternProperties:
>>       type: object
>>       $ref: nvidia,tegra186-asrc.yaml#
>>
>> +  '^processing-engine@[0-9a-f]+$':
>> +    type: object
>> +    $ref: nvidia,tegra210-ope.yaml#
>> +
>>   required:
>>     - compatible
>>     - reg
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> new file mode 100644
>> index 0000000..0d55328
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> @@ -0,0 +1,47 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Tegra210 MBDRC Device Tree Bindings
> Previous comments - s/Device Tree Bindings//
>   -  still applies. Please do not ignore it.

I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-30  4:21       ` Sameer Pujar
  0 siblings, 0 replies; 30+ messages in thread
From: Sameer Pujar @ 2022-05-30  4:21 UTC (permalink / raw)
  To: Krzysztof Kozlowski, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel


On 29-05-2022 19:39, Krzysztof Kozlowski wrote:
> On 27/05/2022 12:26, Sameer Pujar wrote:
>> This patch adds YAML schema for DT bindings of Output Processing
>> Engine (OPE) module. It consists of Parametric Equalizer (PEQ)
>> and Multi Band Dynamic Range Compressor (MBDRC) sub blocks and
>> binding doc for these blocks are added as well. The OPE will be
>> registered as an ASoC component and can be plugged into an audio
>> path as per need via ALSA mixer controls. The DT bindings are
>> applicable on Tegra210 and later SoCs where OPE module is present.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
>>   .../bindings/sound/nvidia,tegra210-ahub.yaml       |  4 +
>>   .../bindings/sound/nvidia,tegra210-mbdrc.yaml      | 47 ++++++++++++
>>   .../bindings/sound/nvidia,tegra210-ope.yaml        | 87 ++++++++++++++++++++++
>>   .../bindings/sound/nvidia,tegra210-peq.yaml        | 48 ++++++++++++
>>   4 files changed, 186 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
>>   create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> index 6df6f85..47b6e71 100644
>> --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
>> @@ -110,6 +110,10 @@ patternProperties:
>>       type: object
>>       $ref: nvidia,tegra186-asrc.yaml#
>>
>> +  '^processing-engine@[0-9a-f]+$':
>> +    type: object
>> +    $ref: nvidia,tegra210-ope.yaml#
>> +
>>   required:
>>     - compatible
>>     - reg
>> diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> new file mode 100644
>> index 0000000..0d55328
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>> @@ -0,0 +1,47 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Tegra210 MBDRC Device Tree Bindings
> Previous comments - s/Device Tree Bindings//
>   -  still applies. Please do not ignore it.

I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
  2022-05-30  4:21       ` Sameer Pujar
  (?)
@ 2022-05-30  6:47         ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-30  6:47 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel

On 30/05/2022 06:21, Sameer Pujar wrote:
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>> @@ -0,0 +1,47 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Tegra210 MBDRC Device Tree Bindings
>> Previous comments - s/Device Tree Bindings//
>>   -  still applies. Please do not ignore it.
> 
> I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.

Yes, acronym is okay. Just remove the "Device Tree Bindings".


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-30  6:47         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-30  6:47 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: devicetree, alsa-devel, linux-kernel, jonathanh, linux-tegra,
	linux-arm-kernel

On 30/05/2022 06:21, Sameer Pujar wrote:
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>> @@ -0,0 +1,47 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Tegra210 MBDRC Device Tree Bindings
>> Previous comments - s/Device Tree Bindings//
>>   -  still applies. Please do not ignore it.
> 
> I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.

Yes, acronym is okay. Just remove the "Device Tree Bindings".


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module
@ 2022-05-30  6:47         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-30  6:47 UTC (permalink / raw)
  To: Sameer Pujar, broonie, robh+dt, krzysztof.kozlowski+dt,
	thierry.reding, catalin.marinas, will, perex, tiwai
  Cc: jonathanh, alsa-devel, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel

On 30/05/2022 06:21, Sameer Pujar wrote:
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
>>> @@ -0,0 +1,47 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Tegra210 MBDRC Device Tree Bindings
>> Previous comments - s/Device Tree Bindings//
>>   -  still applies. Please do not ignore it.
> 
> I did not ignore this. There was a comment from Mark on this earlier (v1) and I did not see further reply from you. I thought you were OK with the way it is. So if you are saying acronym part is OK and just to remove "Device Tree Bindings" I can send a v3 for this.

Yes, acronym is okay. Just remove the "Device Tree Bindings".


Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2022-05-30  6:48 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-27 10:26 [PATCH v2 0/6] OPE support on Tegra210 and later Sameer Pujar
2022-05-27 10:26 ` Sameer Pujar
2022-05-27 10:26 ` Sameer Pujar
2022-05-27 10:26 ` [PATCH v2 1/6] ASoC: tegra: Add binding doc for OPE module Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-29 14:09   ` Krzysztof Kozlowski
2022-05-29 14:09     ` Krzysztof Kozlowski
2022-05-29 14:09     ` Krzysztof Kozlowski
2022-05-30  4:21     ` Sameer Pujar
2022-05-30  4:21       ` Sameer Pujar
2022-05-30  4:21       ` Sameer Pujar
2022-05-30  6:47       ` Krzysztof Kozlowski
2022-05-30  6:47         ` Krzysztof Kozlowski
2022-05-30  6:47         ` Krzysztof Kozlowski
2022-05-27 10:26 ` [PATCH v2 2/6] ASoC: tegra: Add Tegra210 based OPE driver Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26 ` [PATCH v2 3/6] ASoC: tegra: AHUB routes for OPE module Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26 ` [PATCH v2 4/6] arm64: defconfig: Build Tegra " Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26 ` [PATCH v2 5/6] arm64: tegra: Add OPE device on Tegra210 and later Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26 ` [PATCH v2 6/6] arm64: tegra: Enable OPE on various platforms Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar
2022-05-27 10:26   ` Sameer Pujar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.