diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2021-09-30 12:19:47 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2021-09-30 12:19:49 +1000 |
commit | 0d011158a9f0a71a447a25555ebb676fd722e92f (patch) | |
tree | a40cc42d0bc749e8cd6e29e77f6048b7fa14cac1 | |
parent | 8809089aff47ca522e3551f0d73a46aa3b1b8a82 (diff) | |
parent | f12521aa0c1370add6b0432ee934eb6c30ca441c (diff) | |
download | devel-0d011158a9f0a71a447a25555ebb676fd722e92f.tar.gz |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
251 files changed, 19351 insertions, 2713 deletions
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt deleted file mode 100644 index 641edf75e18466..00000000000000 --- a/Documentation/devicetree/bindings/sound/bt-sco.txt +++ /dev/null @@ -1,13 +0,0 @@ -Bluetooth-SCO audio CODEC - -This device support generic Bluetooth SCO link. - -Required properties: - - - compatible : "delta,dfbmcs320" or "linux,bt-sco" - -Example: - -codec: bt_sco { - compatible = "delta,dfbmcs320"; -}; diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml new file mode 100644 index 00000000000000..3235702ce402d1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml @@ -0,0 +1,157 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs35l41.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS35L41 Speaker Amplifier + +maintainers: + - david.rhodes@cirrus.com + +description: | + CS35L41 is a boosted mono Class D amplifier with DSP + speaker protection and equalization + +properties: + compatible: + enum: + - cirrus,cs35l40 + - cirrus,cs35l41 + + reg: + maxItems: 1 + + '#sound-dai-cells': + description: + The first cell indicating the audio interface. + const: 1 + + reset-gpios: + maxItems: 1 + + VA-supply: + description: voltage regulator phandle for the VA supply + + VP-supply: + description: voltage regulator phandle for the VP supply + + cirrus,boost-peak-milliamp: + description: + Boost-converter peak current limit in mA. + Configures the peak current by monitoring the current through the boost FET. + Range starts at 1600 mA and goes to a maximum of 4500 mA with increments + of 50 mA. See section 4.3.6 of the datasheet for details. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 1600 + maximum: 4500 + default: 4500 + + cirrus,boost-ind-nanohenry: + description: + Boost inductor value, expressed in nH. Valid + values include 1000, 1200, 1500 and 2200. + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 1000 + maximum: 2200 + + cirrus,boost-cap-microfarad: + description: + Total equivalent boost capacitance on the VBST + and VAMP pins, derated at 11 volts DC. The value must be rounded to the + nearest integer and expressed in uF. + $ref: "/schemas/types.yaml#/definitions/uint32" + + cirrus,asp-sdout-hiz: + description: + Audio serial port SDOUT Hi-Z control. Sets the Hi-Z + configuration for SDOUT pin of amplifier. + 0 = Logic 0 during unused slots, and while all transmit channels disabled + 1 = Hi-Z during unused slots but logic 0 while all transmit channels disabled + 2 = (Default) Logic 0 during unused slots, but Hi-Z while all transmit channels disabled + 3 = Hi-Z during unused slots and while all transmit channels disabled + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 3 + default: 2 + + cirrus,gpio1-polarity-invert: + description: + Boolean which specifies whether the GPIO1 + level is inverted. If this property is not present the level is not inverted. + type: boolean + + cirrus,gpio1-output-enable: + description: + Boolean which specifies whether the GPIO1 pin + is configured as an output. If this property is not present the + pin will be configured as an input. + type: boolean + + cirrus,gpio1-src-select: + description: + Configures the function of the GPIO1 pin. + Note that the options are different from the GPIO2 pin + 0 = High Impedance (Default) + 1 = GPIO + 2 = Sync + 3 = MCLK input + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 3 + + cirrus,gpio2-polarity-invert: + description: + Boolean which specifies whether the GPIO2 + level is inverted. If this property is not present the level is not inverted. + type: boolean + + cirrus,gpio2-output-enable: + description: + Boolean which specifies whether the GPIO2 pin + is configured as an output. If this property is not present the + pin will be configured as an input. + type: boolean + + cirrus,gpio2-src-select: + description: + Configures the function of the GPIO2 pin. + Note that the options are different from the GPIO1 pin. + 0 = High Impedance (Default) + 1 = GPIO + 2 = Open Drain INTB + 3 = MCLK input + 4 = Push-pull INTB (active low) + 5 = Push-pull INT (active high) + $ref: "/schemas/types.yaml#/definitions/uint32" + minimum: 0 + maximum: 5 + +required: + - compatible + - reg + - "#sound-dai-cells" + - cirrus,boost-peak-milliamp + - cirrus,boost-ind-nanohenry + - cirrus,boost-cap-microfarad + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + cs35l41: cs35l41@2 { + #sound-dai-cells = <1>; + compatible = "cirrus,cs35l41"; + reg = <2>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&gpio 110 0>; + cirrus,boost-peak-milliamp = <4500>; + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-cap-microfarad = <15>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml new file mode 100644 index 00000000000000..e3a1f485f6642f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/linux,bt-sco.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/linux,bt-sco.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bluetooth SCO Audio Codec Device Tree Bindings + +maintainers: + - Mark Brown <broonie@kernel.org> + +properties: + '#sound-dai-cells': + enum: + - 0 + + # For Wideband PCM + - 1 + + compatible: + enum: + - delta,dfbmcs320 + - linux,bt-sco + +required: + - '#sound-dai-cells' + - compatible + +additionalProperties: false + +examples: + - | + codec { + #sound-dai-cells = <0>; + compatible = "linux,bt-sco"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml new file mode 100644 index 00000000000000..c6b070e1d01472 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/linux,spdif-dit.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/linux,spdif-dit.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dummy SPDIF Transmitter Device Tree Bindings + +maintainers: + - Mark Brown <broonie@kernel.org> + +properties: + compatible: + const: linux,spdif-dit + + "#sound-dai-cells": + const: 0 + +required: + - "#sound-dai-cells" + - compatible + +additionalProperties: false + +examples: + - | + spdif-out { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/name-prefix.txt b/Documentation/devicetree/bindings/sound/name-prefix.txt deleted file mode 100644 index 64577590865706..00000000000000 --- a/Documentation/devicetree/bindings/sound/name-prefix.txt +++ /dev/null @@ -1,24 +0,0 @@ -Name prefix: - -Card implementing the routing property define the connection between -audio components as list of string pair. Component using the same -sink/source names may use the name prefix property to prepend the -name of their sinks/sources with the provided string. - -Optional name prefix property: -- sound-name-prefix : string using as prefix for the sink/source names of - the component. - -Example: Two instances of the same component. - -amp0: analog-amplifier@0 { - compatible = "simple-audio-amplifier"; - enable-gpios = <&gpio GPIOH_3 0>; - sound-name-prefix = "FRONT"; -}; - -amp1: analog-amplifier@1 { - compatible = "simple-audio-amplifier"; - enable-gpios = <&gpio GPIOH_4 0>; - sound-name-prefix = "BACK"; -}; diff --git a/Documentation/devicetree/bindings/sound/name-prefix.yaml b/Documentation/devicetree/bindings/sound/name-prefix.yaml new file mode 100644 index 00000000000000..2fe57f87ac52f2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/name-prefix.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/name-prefix.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Component sound name prefix + +maintainers: + - Jerome Brunet <jbrunet@baylibre.com> + +properties: + sound-name-prefix: + $ref: /schemas/types.yaml#/definitions/string + description: | + Card implementing the routing property define the connection between + audio components as list of string pair. Component using the same + sink/source names may use this property to prepend the name of their + sinks/sources with the provided string. + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml index 5f6b37c251a82d..0912d3e3fd8ec6 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml @@ -17,6 +17,9 @@ maintainers: - Jon Hunter <jonathanh@nvidia.com> - Sameer Pujar <spujar@nvidia.com> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^dspk@[0-9a-f]*$" @@ -48,12 +51,6 @@ properties: sound-name-prefix: pattern: "^DSPK[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "DSPK1" or "DSPKx", where x depends on the maximum - available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml new file mode 100644 index 00000000000000..c4ba12ea361182 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-adx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 ADX Device Tree Bindings + +description: | + The Audio Demultiplexer (ADX) block takes an input stream with up to + 16 channels and demultiplexes it into four output streams of up to 16 + channels each. A byte RAM helps to form output frames by any combination + of bytes from the input frame. Its design is identical to that of byte + RAM in the AMX except that the data flow direction is reversed. + +maintainers: + - Jon Hunter <jonathanh@nvidia.com> + - Mohan Kumar <mkumard@nvidia.com> + - Sameer Pujar <spujar@nvidia.com> + +allOf: + - $ref: name-prefix.yaml# + +properties: + $nodename: + pattern: "^adx@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-adx + - items: + - enum: + - nvidia,tegra194-adx + - nvidia,tegra186-adx + - const: nvidia,tegra210-adx + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^ADX[1-9]$" + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + ADX has one input and four outputs. Accordingly ACIF (Audio Client + Interface) port nodes are defined to represent ADX input (port 0) + and outputs (ports 1 to 4). These are connected to corresponding + ports on AHUB (Audio Hub). + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: ADX ACIF input port + patternProperties: + '^port@[1-4]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: ADX ACIF output ports + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + adx@702d3800 { + compatible = "nvidia,tegra210-adx"; + reg = <0x702d3800 0x100>; + sound-name-prefix = "ADX1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml index 1118a94883450f..df81d208184a49 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml @@ -85,6 +85,26 @@ patternProperties: type: object $ref: nvidia,tegra186-dspk.yaml# + '^mvc@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-mvc.yaml# + + '^sfc@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-sfc.yaml# + + '^amx@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-amx.yaml# + + '^adx@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-adx.yaml# + + '^amixer@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-mixer.yaml# + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml new file mode 100644 index 00000000000000..bb2111afe5a85b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-amx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 AMX Device Tree Bindings + +description: | + The Audio Multiplexer (AMX) block can multiplex up to four input streams + each of which can have maximum 16 channels and generate an output stream + with maximum 16 channels. A byte RAM helps to form an output frame by + any combination of bytes from the input frames. + +maintainers: + - Jon Hunter <jonathanh@nvidia.com> + - Mohan Kumar <mkumard@nvidia.com> + - Sameer Pujar <spujar@nvidia.com> + +allOf: + - $ref: name-prefix.yaml# + +properties: + $nodename: + pattern: "^amx@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-amx + - items: + - const: nvidia,tegra186-amx + - const: nvidia,tegra210-amx + - const: nvidia,tegra194-amx + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^AMX[1-9]$" + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + AMX has four inputs and one output. Accordingly ACIF (Audio Client + Interfaces) port nodes are defined to represent AMX inputs (port 0 + to 3) and output (port 4). These are connected to corresponding + ports on AHUB (Audio Hub). + + patternProperties: + '^port@[0-3]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: AMX ACIF input ports + + properties: + port@4: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: AMX ACIF output port + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + amx@702d3000 { + compatible = "nvidia,tegra210-amx"; + reg = <0x702d3000 0x100>; + sound-name-prefix = "AMX1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml index fd275a57505517..62db982bb01d04 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml @@ -16,6 +16,9 @@ maintainers: - Jon Hunter <jonathanh@nvidia.com> - Sameer Pujar <spujar@nvidia.com> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^dmic@[0-9a-f]*$" @@ -49,12 +52,6 @@ properties: sound-name-prefix: pattern: "^DMIC[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends - on the maximum available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml index 63370709c7681b..f954be636697fa 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml @@ -16,6 +16,9 @@ maintainers: - Jon Hunter <jonathanh@nvidia.com> - Sameer Pujar <spujar@nvidia.com> +allOf: + - $ref: name-prefix.yaml# + properties: $nodename: pattern: "^i2s@[0-9a-f]*$" @@ -65,12 +68,6 @@ properties: sound-name-prefix: pattern: "^I2S[1-9]$" - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. - The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends - on the maximum available instances on a Tegra SoC. ports: $ref: /schemas/graph.yaml#/properties/ports diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml new file mode 100644 index 00000000000000..428f3c851941af --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mixer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 Mixer Device Tree Bindings + +description: | + The Mixer supports mixing of up to ten 7.1 audio input streams and + generate five outputs (each of which can be any combination of the + ten input streams). + +maintainers: + - Jon Hunter <jonathanh@nvidia.com> + - Mohan Kumar <mkumard@nvidia.com> + - Sameer Pujar <spujar@nvidia.com> + +allOf: + - $ref: name-prefix.yaml# + +properties: + $nodename: + pattern: "^amixer@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-amixer + - items: + - enum: + - nvidia,tegra194-amixer + - nvidia,tegra186-amixer + - const: nvidia,tegra210-amixer + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^MIXER[1-9]$" + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + Mixer has ten inputs and five outputs. Accordingly ACIF (Audio + Client Interfaces) port nodes are defined to represent Mixer + inputs (port 0 to 9) and outputs (port 10 to 14). These are + connected to corresponding ports on AHUB (Audio Hub). + + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: Mixer ACIF input ports + '^port@[10-14]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: Mixer ACIF output ports + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + amixer@702dbb00 { + compatible = "nvidia,tegra210-amixer"; + reg = <0x702dbb00 0x800>; + sound-name-prefix = "MIXER1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml new file mode 100644 index 00000000000000..e2f5a8591d8f66 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mvc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 MVC Device Tree Bindings + +description: | + The Master Volume Control (MVC) provides gain or attenuation to a digital + signal path. It can be used in input or output signal path for per-stream + volume control or it can be used as master volume control. The MVC block + has one input and one output. The input digital stream can be mono or + multi-channel (up to 7.1 channels) stream. An independent mute control is + also included in the MVC block. + +maintainers: + - Jon Hunter <jonathanh@nvidia.com> + - Mohan Kumar <mkumard@nvidia.com> + - Sameer Pujar <spujar@nvidia.com> + +allOf: + - $ref: name-prefix.yaml# + +properties: + $nodename: + pattern: "^mvc@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-mvc + - items: + - enum: + - nvidia,tegra194-mvc + - nvidia,tegra186-mvc + - const: nvidia,tegra210-mvc + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^MVC[1-9]$" + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + MVC 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: | + MVC ACIF output port. This is connected to corresponding ACIF + input port on AHUB. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + mvc@702da000 { + compatible = "nvidia,tegra210-mvc"; + reg = <0x702da000 0x200>; + sound-name-prefix = "MVC1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml new file mode 100644 index 00000000000000..41ad6517354851 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-sfc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 SFC Device Tree Bindings + +description: | + The Sampling Frequency Converter (SFC) converts the sampling frequency + of the input signal from one frequency to another. It supports sampling + frequency conversions of streams of up to two channels (stereo). + +maintainers: + - Jon Hunter <jonathanh@nvidia.com> + - Mohan Kumar <mkumard@nvidia.com> + - Sameer Pujar <spujar@nvidia.com> + +allOf: + - $ref: name-prefix.yaml# + +properties: + $nodename: + pattern: "^sfc@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-sfc + - items: + - enum: + - nvidia,tegra194-sfc + - nvidia,tegra186-sfc + - const: nvidia,tegra210-sfc + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^SFC[1-9]$" + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + SFC 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: | + SFC ACIF output port. This is connected to corresponding ACIF + input port on AHUB. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + sfc@702d2000 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2000 0x200>; + sound-name-prefix = "SFC1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml index ffb8fcfeb62959..7667471be1e480 100644 --- a/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml +++ b/Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml @@ -9,6 +9,9 @@ title: NXP/Goodix TFA989X (TFA1) Audio Amplifiers maintainers: - Stephan Gerhold <stephan@gerhold.net> +allOf: + - $ref: name-prefix.yaml# + properties: compatible: enum: @@ -21,11 +24,7 @@ properties: '#sound-dai-cells': const: 0 - sound-name-prefix: - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. + sound-name-prefix: true vddd-supply: description: regulator phandle for the VDDD power supply. diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt index 2d6fb2ea75a099..1677448347daea 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt +++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt @@ -12,7 +12,7 @@ used by all apr services. Must contain the following properties. from DSP. example "qcom,q6afe" -= AFE DAIs (Digial Audio Interface) += AFE DAIs (Digital Audio Interface) "dais" subnode of the AFE node. It represents afe dais, each afe dai is a subnode of "dais" representing board specific dai setup. "dais" node should have following properties followed by dai children. diff --git a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt index 8c4883becae9f8..0d0075125243ec 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6asm.txt +++ b/Documentation/devicetree/bindings/sound/qcom,q6asm.txt @@ -14,7 +14,7 @@ used by the apr service device. from DSP. example "qcom,q6asm-v2.0" -= ASM DAIs (Digial Audio Interface) += ASM DAIs (Digital Audio Interface) "dais" subnode of the ASM node represents dai specific configuration - compatible: diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml new file mode 100644 index 00000000000000..7a5f1d0fd3e283 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5682s.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5682s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek rt5682s codec devicetree bindings + +maintainers: + - Derek Fang <derek.fang@realtek.com> + +description: | + Rt5682s(ALC5682I-VS) is a rt5682i variant which supports I2C only. + +properties: + compatible: + const: realtek,rt5682s + + reg: + maxItems: 1 + description: I2C address of the device. + + interrupts: + description: The CODEC's interrupt output. + + realtek,dmic1-data-pin: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 data is not used + - 1 # using GPIO2 pin as dmic1 data pin + - 2 # using GPIO5 pin as dmic1 data pin + + realtek,dmic1-clk-pin: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 clk is not used + - 1 # using GPIO1 pin as dmic1 clock pin + - 2 # using GPIO3 pin as dmic1 clock pin + + realtek,jd-src: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # No JD is used + - 1 # using JD1 as JD source + + realtek,ldo1-en-gpios: + description: | + The GPIO that controls the CODEC's LDO1_EN pin. + + realtek,dmic-clk-rate-hz: + description: | + Set the clock rate (hz) for the requirement of the particular DMIC. + + realtek,dmic-delay-ms: + description: | + Set the delay time (ms) for the requirement of the particular DMIC. + + realtek,dmic-clk-driving-high: + type: boolean + description: | + Set the high driving of the DMIC clock out. + + clocks: + items: + - description: phandle and clock specifier for codec MCLK. + + clock-names: + items: + - const: mclk + + "#clock-cells": + const: 1 + + clock-output-names: + items: + - description: Name given for DAI word clock output. + - description: Name given for DAI bit clock output. + +additionalProperties: false + +required: + - compatible + - reg + +examples: + - | + #include <dt-bindings/gpio/tegra-gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "realtek,rt5682s"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <TEGRA_GPIO(U, 6) IRQ_TYPE_LEVEL_HIGH>; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + realtek,dmic1-data-pin = <1>; + realtek,dmic1-clk-pin = <1>; + realtek,jd-src = <1>; + + #clock-cells = <1>; + clock-output-names = "rt5682-dai-wclk", "rt5682-dai-bclk"; + + clocks = <&osc>; + clock-names = "mclk"; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rockchip,pdm.txt b/Documentation/devicetree/bindings/sound/rockchip,pdm.txt deleted file mode 100644 index 98572a25122f05..00000000000000 --- a/Documentation/devicetree/bindings/sound/rockchip,pdm.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Rockchip PDM controller - -Required properties: - -- compatible: "rockchip,pdm" - - "rockchip,px30-pdm" - - "rockchip,rk1808-pdm" - - "rockchip,rk3308-pdm" -- reg: physical base address of the controller and length of memory mapped - region. -- dmas: DMA specifiers for rx dma. See the DMA client binding, - Documentation/devicetree/bindings/dma/dma.txt -- dma-names: should include "rx". -- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. -- clock-names: should contain following: - - "pdm_hclk": clock for PDM BUS - - "pdm_clk" : clock for PDM controller -- resets: a list of phandle + reset-specifer paris, one for each entry in reset-names. -- reset-names: reset names, should include "pdm-m". -- pinctrl-names: Must contain a "default" entry. -- pinctrl-N: One property must exist for each entry in - pinctrl-names. See ../pinctrl/pinctrl-bindings.txt - for details of the property values. - -Example for rk3328 PDM controller: - -pdm: pdm@ff040000 { - compatible = "rockchip,pdm"; - reg = <0x0 0xff040000 0x0 0x1000>; - clocks = <&clk_pdm>, <&clk_gates28 0>; - clock-names = "pdm_clk", "pdm_hclk"; - dmas = <&pdma 16>; - #dma-cells = <1>; - dma-names = "rx"; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&pdmm0_clk - &pdmm0_sdi0 - &pdmm0_sdi1 - &pdmm0_sdi2 - &pdmm0_sdi3>; - pinctrl-1 = <&pdmm0_clk_sleep - &pdmm0_sdi0_sleep - &pdmm0_sdi1_sleep - &pdmm0_sdi2_sleep - &pdmm0_sdi3_sleep>; -}; diff --git a/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml b/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml new file mode 100644 index 00000000000000..22e1cf6c05928f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,pdm.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/rockchip,pdm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip PDM controller + +description: + The Pulse Density Modulation Interface Controller (PDMC) is + a PDM interface controller and decoder that support PDM format. + It integrates a clock generator driving the PDM microphone + and embeds filters which decimate the incoming bit stream to + obtain most common audio rates. + +maintainers: + - Heiko Stuebner <heiko@sntech.de> + +properties: + compatible: + enum: + - rockchip,pdm + - rockchip,px30-pdm + - rockchip,rk1808-pdm + - rockchip,rk3308-pdm + - rockchip,rk3568-pdm + - rockchip,rv1126-pdm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: clock for PDM controller + - description: clock for PDM BUS + + clock-names: + items: + - const: pdm_clk + - const: pdm_hclk + + dmas: + maxItems: 1 + + dma-names: + items: + - const: rx + + power-domains: + maxItems: 1 + + resets: + items: + - description: reset for PDM controller + + reset-names: + items: + - const: pdm-m + + rockchip,path-map: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Defines the mapping of PDM SDIx to PDM PATHx. + By default, they are mapped one-to-one. + maxItems: 4 + uniqueItems: true + items: + enum: [ 0, 1, 2, 3 ] + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - dmas + - dma-names + - "#sound-dai-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/rk3328-cru.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/pinctrl/rockchip.h> + + bus { + #address-cells = <2>; + #size-cells = <2>; + + pdm@ff040000 { + compatible = "rockchip,pdm"; + reg = <0x0 0xff040000 0x0 0x1000>; + interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_PDM>, <&cru HCLK_PDM>; + clock-names = "pdm_clk", "pdm_hclk"; + dmas = <&dmac 16>; + dma-names = "rx"; + #sound-dai-cells = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pdmm0_clk + &pdmm0_sdi0 + &pdmm0_sdi1 + &pdmm0_sdi2 + &pdmm0_sdi3>; + pinctrl-1 = <&pdmm0_clk_sleep + &pdmm0_sdi0_sleep + &pdmm0_sdi1_sleep + &pdmm0_sdi2_sleep + &pdmm0_sdi3_sleep>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt index c473df5c878c67..013f534fa05907 100644 --- a/Documentation/devicetree/bindings/sound/rt5659.txt +++ b/Documentation/devicetree/bindings/sound/rt5659.txt @@ -42,7 +42,7 @@ Optional properties: - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. - realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. -- sound-name-prefix: Please refer to name-prefix.txt +- sound-name-prefix: Please refer to name-prefix.yaml - ports: A Codec may have a single or multiple I2S interfaces. These interfaces on Codec side can be described under 'ports' or 'port'. diff --git a/Documentation/devicetree/bindings/sound/simple-amplifier.txt b/Documentation/devicetree/bindings/sound/simple-amplifier.txt deleted file mode 100644 index b1b097cc9b68fc..00000000000000 --- a/Documentation/devicetree/bindings/sound/simple-amplifier.txt +++ /dev/null @@ -1,17 +0,0 @@ -Simple Amplifier Audio Driver - -Required properties: -- compatible : "dioo,dio2125" or "simple-audio-amplifier" - -Optional properties: -- enable-gpios : the gpio connected to the enable pin of the simple amplifier -- VCC-supply : power supply for the device, as covered - in Documentation/devicetree/bindings/regulator/regulator.txt - -Example: - -amp: analog-amplifier { - compatible = "simple-audio-amplifier"; - VCC-supply = <®ulator>; - enable-gpios = <&gpio GPIOH_3 0>; -}; diff --git a/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml new file mode 100644 index 00000000000000..26379377a7ac3a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-audio-amplifier.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/simple-audio-amplifier.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Simple Audio Amplifier Device Tree Bindings + +maintainers: + - Jerome Brunet <jbrunet@baylibre.com> + +properties: + compatible: + enum: + - dioo,dio2125 + - simple-audio-amplifier + + enable-gpios: + maxItems: 1 + + VCC-supply: + description: > + power supply for the device + + sound-name-prefix: + $ref: /schemas/types.yaml#/definitions/string + description: > + See ./name-prefix.txt + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/meson8-gpio.h> + + analog-amplifier { + compatible = "simple-audio-amplifier"; + VCC-supply = <®ulator>; + enable-gpios = <&gpio GPIOH_3 0>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml index 5986d1fcbb54e2..b5fc35ee9b6572 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml @@ -13,6 +13,9 @@ description: | Simple audio multiplexers are driven using gpios, allowing to select which of their input line is connected to the output line. +allOf: + - $ref: name-prefix.yaml# + properties: compatible: const: simple-audio-mux @@ -21,11 +24,7 @@ properties: description: | GPIOs used to select the input line. - sound-name-prefix: - $ref: /schemas/types.yaml#/definitions/string - description: - Used as prefix for sink/source names of the component. Must be a - unique string among multiple instances of the same component. + sound-name-prefix: true required: - compatible diff --git a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt deleted file mode 100644 index 55a85841dd8546..00000000000000 --- a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt +++ /dev/null @@ -1,10 +0,0 @@ -Device-Tree bindings for dummy spdif transmitter - -Required properties: - - compatible: should be "linux,spdif-dit". - -Example node: - - codec: spdif-transmitter { - compatible = "linux,spdif-dit"; - }; diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml new file mode 100644 index 00000000000000..96cf9fc9c8b009 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8978.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8978.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wolfson WM8978 Codec Device Tree Bindings + +maintainers: + - patches@opensource.cirrus.com + +properties: + '#sound-dai-cells': + const: 0 + + compatible: + const: wlf,wm8978 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 526000 + +required: + - '#sound-dai-cells' + - compatible + - reg + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + codec@0 { + #sound-dai-cells = <0>; + compatible = "wlf,wm8978"; + reg = <0>; + spi-max-frequency = <500000>; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + #sound-dai-cells = <0>; + compatible = "wlf,wm8978"; + reg = <0x1a>; + }; + }; + +... diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index 65f61695f5618b..34888d4fc4a835 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -100,6 +100,15 @@ amidi_map MIDI device number maps assigned to the 2st OSS device; Default: 1 +Module snd-soc-core +------------------- + +The soc core module. It is used by all ALSA card drivers. +It takes the following options which have global effects. + +prealloc_buffer_size_kbytes + Specify prealloc buffer size in kbytes (default: 512). + Common parameters for top sound card modules -------------------------------------------- diff --git a/include/dt-bindings/sound/qcom,lpass.h b/include/dt-bindings/sound/qcom,lpass.h index 7b0b80b38699e4..187af4591cd852 100644 --- a/include/dt-bindings/sound/qcom,lpass.h +++ b/include/dt-bindings/sound/qcom,lpass.h @@ -10,6 +10,11 @@ #define LPASS_DP_RX 5 +#define LPASS_CDC_DMA_RX0 6 +#define LPASS_CDC_DMA_TX3 7 +#define LPASS_CDC_DMA_VA0 8 +#define LPASS_MAX_PORTS 9 + #define LPASS_MCLK0 0 #endif /* __DT_QCOM_LPASS_H */ diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h new file mode 100644 index 00000000000000..1f1e3c6c9be1c9 --- /dev/null +++ b/include/sound/cs35l41.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * linux/sound/cs35l41.h -- Platform data for CS35L41 + * + * Copyright (c) 2017-2021 Cirrus Logic Inc. + * + * Author: David Rhodes <david.rhodes@cirrus.com> + */ + +#ifndef __CS35L41_H +#define __CS35L41_H + +enum cs35l41_clk_ids { + CS35L41_CLKID_SCLK = 0, + CS35L41_CLKID_LRCLK = 1, + CS35L41_CLKID_MCLK = 4, +}; + +struct cs35l41_irq_cfg { + bool irq_pol_inv; + bool irq_out_en; + int irq_src_sel; +}; + +struct cs35l41_platform_data { + int bst_ind; + int bst_ipk; + int bst_cap; + int dout_hiz; + struct cs35l41_irq_cfg irq_config1; + struct cs35l41_irq_cfg irq_config2; +}; + +#endif /* __CS35L41_H */ diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h new file mode 100644 index 00000000000000..accfbc2dcdd2ca --- /dev/null +++ b/include/sound/rt5682s.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/sound/rt5682s.h -- Platform data for RT5682I-VS + * + * Copyright 2021 Realtek Microelectronics + */ + +#ifndef __LINUX_SND_RT5682S_H +#define __LINUX_SND_RT5682S_H + +enum rt5682s_dmic1_data_pin { + RT5682S_DMIC1_DATA_NULL, + RT5682S_DMIC1_DATA_GPIO2, + RT5682S_DMIC1_DATA_GPIO5, +}; + +enum rt5682s_dmic1_clk_pin { + RT5682S_DMIC1_CLK_NULL, + RT5682S_DMIC1_CLK_GPIO1, + RT5682S_DMIC1_CLK_GPIO3, +}; + +enum rt5682s_jd_src { + RT5682S_JD_NULL, + RT5682S_JD1, +}; + +enum rt5682s_dai_clks { + RT5682S_DAI_WCLK_IDX, + RT5682S_DAI_BCLK_IDX, + RT5682S_DAI_NUM_CLKS, +}; + +struct rt5682s_platform_data { + + int ldo1_en; /* GPIO for LDO1_EN */ + + enum rt5682s_dmic1_data_pin dmic1_data_pin; + enum rt5682s_dmic1_clk_pin dmic1_clk_pin; + enum rt5682s_jd_src jd_src; + unsigned int dmic_clk_rate; + unsigned int dmic_delay; + bool dmic_clk_driving_high; + + const char *dai_clk_names[RT5682S_DAI_NUM_CLKS]; +}; + +#endif diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 51b3b485a92ec4..6b780346eaa727 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -115,7 +115,7 @@ struct asoc_simple_priv { ((codec) = simple_props_to_dai_codec(props, i)); \ (i)++) -#define SNDRV_MAX_LINKS 128 +#define SNDRV_MAX_LINKS 512 struct link_info { int link; /* number of link */ diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 8c4d6830597fff..e09a2d108e8c42 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -220,7 +220,7 @@ struct snd_soc_component { int (*init)(struct snd_soc_component *component); /* function mark */ - struct snd_pcm_substream *mark_module; + void *mark_module; struct snd_pcm_substream *mark_open; struct snd_pcm_substream *mark_hw_params; struct snd_pcm_substream *mark_trigger; @@ -391,15 +391,13 @@ void snd_soc_component_exit_regmap(struct snd_soc_component *component); #define snd_soc_component_module_get_when_open(component, substream) \ snd_soc_component_module_get(component, substream, 1) int snd_soc_component_module_get(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open); + void *mark, int upon_open); #define snd_soc_component_module_put_when_remove(component) \ snd_soc_component_module_put(component, NULL, 0, 0) #define snd_soc_component_module_put_when_close(component, substream, rollback) \ snd_soc_component_module_put(component, substream, 1, rollback) void snd_soc_component_module_put(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open, int rollback); + void *mark, int upon_open, int rollback); static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, void *data) @@ -455,8 +453,10 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, const char **dai_name); -int snd_soc_component_compr_open(struct snd_compr_stream *cstream); -void snd_soc_component_compr_free(struct snd_compr_stream *cstream, +int snd_soc_component_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream); +void snd_soc_component_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int rollback); int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, diff --git a/include/sound/sof.h b/include/sound/sof.h index 6a1cd8e783d8f4..23b374311d1616 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -74,11 +74,6 @@ struct sof_dev_desc { int resindex_pcicfg_base; int resindex_imr_base; int irqindex_host_ipc; - int resindex_dma_base; - - /* DMA only valid when resindex_dma_base != -1*/ - int dma_engine; - int dma_size; /* IPC timeouts in ms */ int ipc_timeout; diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index b3df98a9f9f3d2..b2065f3fe42c31 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -33,7 +33,7 @@ static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; static struct clk *rt5682_dai_wclk; static struct clk *rt5682_dai_bclk; -extern bool bt_uart_enable; + void *acp_soc_is_rltk_max(struct device *dev); static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) @@ -760,8 +760,8 @@ static int cz_probe(struct platform_device *pdev) "devm_snd_soc_register_card(%s) failed\n", card->name); } - bt_uart_enable = !device_property_read_bool(&pdev->dev, - "bt-pad-enable"); + acp_bt_uart_enable = !device_property_read_bool(&pdev->dev, + "bt-pad-enable"); return 0; } diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 11b3c4f39ebaa6..1f322accd9ead3 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -36,8 +36,8 @@ #define ST_MIN_BUFFER ST_MAX_BUFFER #define DRV_NAME "acp_audio_dma" -bool bt_uart_enable = true; -EXPORT_SYMBOL(bt_uart_enable); +bool acp_bt_uart_enable = true; +EXPORT_SYMBOL(acp_bt_uart_enable); static const struct snd_pcm_hardware acp_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | @@ -596,7 +596,7 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type) acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); /* For BT instance change pins from UART to BT */ - if (!bt_uart_enable) { + if (!acp_bt_uart_enable) { val = acp_reg_read(acp_mmio, mmACP_BT_UART_PAD_SEL); val |= ACP_BT_UART_PAD_SELECT_MASK; acp_reg_write(val, acp_mmio, mmACP_BT_UART_PAD_SEL); diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index e5ab6c6040a6a8..85529ed7e5f504 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -204,4 +204,6 @@ typedef struct acp_dma_dscr_transfer { u32 reserved; } acp_dma_dscr_transfer_t; +extern bool acp_bt_uart_enable; + #endif /*__ACP_HW_H */ diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 6b3d9c05eaf276..1934767690b511 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -342,8 +342,8 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* codec is slave, so cpu is master */ mr |= ATMEL_I2SC_MR_MODE_MASTER; ret = atmel_i2s_get_gck_param(dev, params_rate(params)); @@ -351,7 +351,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, return ret; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: /* codec is master, so cpu is slave */ mr |= ATMEL_I2SC_MR_MODE_SLAVE; dev->gck_param = NULL; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 6a63e8797a0b6b..26e2bc690d86eb 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -209,8 +209,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, if (frame_size < 0) return frame_size; - switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFS: + switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFC: if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) && ssc->clk_from_rk_pin) /* Receiver Frame Synchro (i.e. capture) @@ -220,7 +220,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, mck_div = 3; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) && !ssc->clk_from_rk_pin) /* Transmit Frame Synchro (i.e. playback) @@ -232,8 +232,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, break; } - switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: r.num = ssc_p->mck_rate / mck_div / frame_size; ret = snd_interval_ratnum(i, 1, &r, &num, &den); @@ -243,8 +243,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, } break; - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_CBP_CFP: t.min = 8000; t.max = ssc_p->mck_rate / mck_div / frame_size; t.openmin = t.openmax = 0; @@ -429,9 +429,9 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, /* Is the cpu-dai master of the frame clock? */ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) { - switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFS: + switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_CBC_CFC: return 1; } return 0; @@ -440,9 +440,9 @@ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) /* Is the cpu-dai master of the bit clock? */ static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) { - switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_CBC_CFC: return 1; } return 0; diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 9e237580afa9fc..9c974c4e187d2a 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -66,7 +66,7 @@ static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { .stream_name = "WM8904 PCM", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ops = &atmel_asoc_wm8904_ops, SND_SOC_DAILINK_REG(pcm), }; diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 8988f024a73220..6d1227a1d67b51 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -350,7 +350,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; /* We can't generate only FSYNC */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS) + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC) return -EINVAL; /* We can only reconfigure the IP when it's stopped */ @@ -546,20 +546,20 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* cpu is BCLK and LRC master */ mra |= MCHP_I2SMCC_MRA_MODE_MASTER; if (dev->sysclk) mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN; set_divs = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: /* cpu is BCLK master */ mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT; set_divs = 1; fallthrough; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: /* cpu is slave */ mra |= MCHP_I2SMCC_MRA_MODE_SLAVE; if (dev->sysclk) diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index 0be7b4221c1469..f9331f7e80fe43 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -129,9 +129,9 @@ static int snd_proto_probe(struct platform_device *pdev) } if (bitclkmaster) { if (codec_np == bitclkmaster) - dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; else - dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; } else { dai_fmt |= snd_soc_daifmt_parse_clock_provider_as_flag(np, NULL); } diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index ed1f69b570244f..915da92e1ec829 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -126,7 +126,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { .stream_name = "WM8731 PCM", .init = at91sam9g20ek_wm8731_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(pcm), }; diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index 7745250fd74387..7c45dc4f8c1bbd 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -115,7 +115,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) dai->codecs->dai_name = "wm8731-hifi"; dai->init = sam9x5_wm8731_init; dai->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM; + | SND_SOC_DAIFMT_CBP_CFP; ret = snd_soc_of_parse_card_name(card, "atmel,model"); if (ret) { diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 50c3dc6936f907..1b3a31296c9b46 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -304,7 +304,7 @@ static struct snd_soc_dai_link tse850_dailink = { .stream_name = "TSE-850-PCM", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFS, + | SND_SOC_DAIFMT_CBP_CFC, SND_SOC_DAILINK_REG(pcm), }; diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index 5f8baad37a4016..400eaf9f8b1407 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -117,7 +117,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &db1200_i2s_wm8731_ops, SND_SOC_DAILINK_REG(db1200_i2s), }; @@ -138,7 +138,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &db1200_i2s_wm8731_ops, SND_SOC_DAILINK_REG(db1300_i2s), }; @@ -159,7 +159,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = { .name = "WM8731", .stream_name = "WM8731 PCM", .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &db1200_i2s_wm8731_ops, SND_SOC_DAILINK_REG(db1550_i2s), }; diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 65bd39f5032dfe..740d4e052e4df9 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -119,9 +119,9 @@ static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) goto out; } - /* I2S controller only supports master */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ + /* I2S controller only supports provider */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ break; default: goto out; diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 767ce950d0da8a..b2b8896bb593c2 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -90,12 +90,12 @@ static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, goto out; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: /* CODEC master */ - ct |= PSC_I2SCFG_MS; /* PSC I2S slave mode */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: /* CODEC provider */ + ct |= PSC_I2SCFG_MS; /* PSC I2S consumer mode */ break; - case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ - ct &= ~PSC_I2SCFG_MS; /* PSC I2S Master mode */ + case SND_SOC_DAIFMT_CBC_CFC: /* CODEC consumer */ + ct &= ~PSC_I2SCFG_MS; /* PSC I2S provider mode */ break; default: goto out; diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 3d668f449bc1cf..e3fc4bee8cfdcb 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -127,14 +127,14 @@ struct bcm2835_i2s_dev { static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) { - unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; + unsigned int provider = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; if (dev->clk_prepared) return; - switch (master) { - case SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_CBS_CFM: + switch (provider) { + case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_CBC_CFP: clk_prepare_enable(dev->clk); dev->clk_prepared = true; break; @@ -337,8 +337,8 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, unsigned int rx_mask, tx_mask; unsigned int rx_ch1_pos, rx_ch2_pos, tx_ch1_pos, tx_ch2_pos; unsigned int mode, format; - bool bit_clock_master = false; - bool frame_sync_master = false; + bool bit_clock_provider = false; + bool frame_sync_provider = false; bool frame_start_falling_edge = false; uint32_t csreg; int ret = 0; @@ -383,36 +383,36 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, if (data_length > slot_width) return -EINVAL; - /* Check if CPU is bit clock master */ - switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_CBS_CFM: - bit_clock_master = true; + /* Check if CPU is bit clock provider */ + switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_CBC_CFP: + bit_clock_provider = true; break; - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBM_CFM: - bit_clock_master = false; + case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_CBP_CFP: + bit_clock_provider = false; break; default: return -EINVAL; } - /* Check if CPU is frame sync master */ - switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - case SND_SOC_DAIFMT_CBM_CFS: - frame_sync_master = true; + /* Check if CPU is frame sync provider */ + switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_CBP_CFC: + frame_sync_provider = true; break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFM: - frame_sync_master = false; + case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_CBP_CFP: + frame_sync_provider = false; break; default: return -EINVAL; } /* Clock should only be set up here if CPU is clock master */ - if (bit_clock_master && + if (bit_clock_provider && (!dev->clk_prepared || dev->clk_rate != bclk_rate)) { if (dev->clk_prepared) bcm2835_i2s_stop_clock(dev); @@ -501,11 +501,11 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* * Transmitting data immediately after frame start, eg * in left-justified or DSP mode A, only works stable - * if bcm2835 is the frame clock master. + * if bcm2835 is the frame clock provider. */ - if ((!rx_ch1_pos || !tx_ch1_pos) && !frame_sync_master) + if ((!rx_ch1_pos || !tx_ch1_pos) && !frame_sync_provider) dev_warn(dev->dev, - "Unstable slave config detected, L/R may be swapped"); + "Unstable consumer config detected, L/R may be swapped"); /* * Set format for both streams. @@ -538,11 +538,11 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, mode |= BCM2835_I2S_FSLEN(framesync_length); /* CLKM selects bcm2835 clock slave mode */ - if (!bit_clock_master) + if (!bit_clock_provider) mode |= BCM2835_I2S_CLKM; /* FSM selects bcm2835 frame sync slave mode */ - if (!frame_sync_master) + if (!frame_sync_provider) mode |= BCM2835_I2S_FSM; /* CLKI selects normal clocking mode, sampling on rising edge */ diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index fca5a3f2eec5e8..9698f4531c90ff 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -848,12 +848,12 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ssp_newcfg = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE); aio->is_slave = 0; break; diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 7b6cdc9c8a2382..3852902029120a 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -60,7 +60,7 @@ static struct snd_soc_dai_link edb93xx_dai = { .name = "CS4271", .stream_name = "CS4271 HiFi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &edb93xx_ops, SND_SOC_DAILINK_REG(hifi), }; diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 0d26550d0df8d2..06c315a4d20af2 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -245,14 +245,14 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* CPU is master */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + /* CPU is provider */ clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFM: - /* Codec is master */ + case SND_SOC_DAIFMT_CBP_CFP: + /* Codec is provider */ clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; break; diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c index c4b11292166163..a286f5beeaebeb 100644 --- a/sound/soc/cirrus/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c @@ -70,7 +70,7 @@ static struct snd_soc_dai_link snappercl15_dai = { .name = "tlv320aic23", .stream_name = "AIC23", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &snappercl15_ops, SND_SOC_DAILINK_REG(aic23), }; diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index cac7e557edc800..c6043fa58c740d 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -968,16 +968,16 @@ static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + /* set audio interface clocking */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBP_CFC: if (pm860x->dir == PM860X_CLK_DIR_OUT) { inf |= PCM_INF2_MASTER; ret = 0; } break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: if (pm860x->dir == PM860X_CLK_DIR_IN) { inf &= ~PCM_INF2_MASTER; ret = 0; @@ -1072,15 +1072,15 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* set audio interface clocking */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: if (pm860x->dir == PM860X_CLK_DIR_OUT) inf |= PCM_INF2_MASTER; else return -EINVAL; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: if (pm860x->dir == PM860X_CLK_DIR_IN) inf &= ~PCM_INF2_MASTER; else diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 82ee233a269d07..ab7ac5e0bd680f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -61,6 +61,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS35L34 imply SND_SOC_CS35L35 imply SND_SOC_CS35L36 + imply SND_SOC_CS35L41_SPI + imply SND_SOC_CS35L41_I2C imply SND_SOC_CS42L42 imply SND_SOC_CS42L51_I2C imply SND_SOC_CS42L52 @@ -180,6 +182,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT5677 imply SND_SOC_RT5682_I2C imply SND_SOC_RT5682_SDW + imply SND_SOC_RT5682S imply SND_SOC_RT700_SDW imply SND_SOC_RT711_SDW imply SND_SOC_RT711_SDCA_SDW @@ -602,6 +605,16 @@ config SND_SOC_CS35L36 tristate "Cirrus Logic CS35L36 CODEC" depends on I2C +config SND_SOC_CS35L41_SPI + tristate "Cirrus Logic CS35L41 CODEC (SPI)" + depends on SPI_MASTER + select REGMAP_SPI + +config SND_SOC_CS35L41_I2C + tristate "Cirrus Logic CS35L41 CODEC (I2C)" + depends on I2C + select REGMAP_I2C + config SND_SOC_CS42L42 tristate "Cirrus Logic CS42L42 CODEC" depends on I2C @@ -1249,6 +1262,10 @@ config SND_SOC_RT5682_SDW select SND_SOC_RT5682 select REGMAP_SOUNDWIRE +config SND_SOC_RT5682S + tristate + depends on I2C + config SND_SOC_RT700 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8dcea2c4604aa6..4cf939d0d3fbf5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -54,6 +54,8 @@ snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs35l36-objs := cs35l36.o +snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41.o cs35l41-tables.o +snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41.o cs35l41-tables.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -198,6 +200,7 @@ snd-soc-rt5677-spi-objs := rt5677-spi.o snd-soc-rt5682-objs := rt5682.o snd-soc-rt5682-sdw-objs := rt5682-sdw.o snd-soc-rt5682-i2c-objs := rt5682-i2c.o +snd-soc-rt5682s-objs := rt5682s.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o @@ -385,6 +388,8 @@ obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o +obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o +obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o @@ -526,6 +531,7 @@ obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o +obj-$(CONFIG_SND_SOC_RT5682S) += snd-soc-rt5682s.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 5525e1ccab7670..aefafb0b7b974a 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2104,26 +2104,26 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) BIT(AB8500_DIGIFCONF3_IF0MASTER); val = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: dev_dbg(dai->component->dev, - "%s: IF0 Master-mode: AB8500 master.\n", __func__); + "%s: IF0 Master-mode: AB8500 provider.\n", __func__); val |= BIT(AB8500_DIGIFCONF3_IF0MASTER); break; - case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */ + case SND_SOC_DAIFMT_CBC_CFC: dev_dbg(dai->component->dev, - "%s: IF0 Master-mode: AB8500 slave.\n", __func__); + "%s: IF0 Master-mode: AB8500 consumer.\n", __func__); break; - case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */ - case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ + case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_CBP_CFC: dev_err(dai->component->dev, - "%s: ERROR: The device is either a master or a slave.\n", + "%s: ERROR: The device is either a provider or a consumer.\n", __func__); fallthrough; default: dev_err(dai->component->dev, - "%s: ERROR: Unsupporter master mask 0x%x\n", - __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + "%s: ERROR: Unsupporter clocking mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); return -EINVAL; } diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 08a5651bed9f97..29e1689da67ff5 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -148,9 +148,9 @@ static int ad1836_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - /* ALCLK,ABCLK are both output, AD1836 can only be master */ - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + /* ALCLK,ABCLK are both output, AD1836 can only be provider */ + case SND_SOC_DAIFMT_CBP_CFP: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 278a55af158ba5..30b98b4267e131 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -243,22 +243,22 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, if (fmt & SND_SOC_DAIFMT_DSP_A) dac_fmt ^= AD193X_DAC_LEFT_HIGH; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: adc_fmt |= AD193X_ADC_LCR_MASTER; adc_fmt |= AD193X_ADC_BCLK_MASTER; dac_fmt |= AD193X_DAC_LCR_MASTER; dac_fmt |= AD193X_DAC_BCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ + case SND_SOC_DAIFMT_CBC_CFP: adc_fmt |= AD193X_ADC_LCR_MASTER; dac_fmt |= AD193X_DAC_LCR_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ + case SND_SOC_DAIFMT_CBP_CFC: adc_fmt |= AD193X_ADC_BCLK_MASTER; dac_fmt |= AD193X_DAC_BCLK_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 6811a8b3866dd9..1faa4c42636500 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -30,7 +30,7 @@ struct adau1372 { void (*switch_mode)(struct device *dev); bool use_pll; bool enabled; - bool master; + bool clock_provider; struct snd_pcm_hw_constraint_list rate_constraints; unsigned int slot_width; @@ -578,13 +578,13 @@ static int adau1372_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int sai0 = 0, sai1 = 0; bool invert_lrclk = false; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - adau1372->master = true; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + adau1372->clock_provider = true; sai1 |= ADAU1372_SAI1_MS; break; - case SND_SOC_DAIFMT_CBS_CFS: - adau1372->master = false; + case SND_SOC_DAIFMT_CBC_CFC: + adau1372->clock_provider = false; break; default: return -EINVAL; @@ -714,7 +714,7 @@ static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, break; case 4: sai0 = ADAU1372_SAI0_SAI_TDM4; - if (adau1372->master) + if (adau1372->clock_provider) adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4_MASTER; else adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4; diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 9887aa6f0be5c0..46128aaceae9a8 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -28,7 +28,7 @@ struct adau1373_dai { unsigned int clk_src; unsigned int sysclk; bool enable_src; - bool master; + bool clock_provider; }; struct adau1373 { @@ -827,7 +827,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, dai = sink->name[3] - '1'; - if (!adau1373->dais[dai].master) + if (!adau1373->dais[dai].clock_provider) return 0; if (adau1373->dais[dai].clk_src == ADAU1373_CLK_SRC_PLL1) @@ -1102,14 +1102,14 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id]; unsigned int ctrl; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: ctrl = ADAU1373_DAI_MASTER; - adau1373_dai->master = true; + adau1373_dai->clock_provider = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ctrl = 0; - adau1373_dai->master = false; + adau1373_dai->clock_provider = false; break; default: return -EINVAL; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 5ce74697564af1..c5bf461c0b7e4b 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -482,13 +482,13 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int serictl = 0x00, seroctl = 0x00; bool invert_lrclk; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: /* master, 64-bits per sample, 1 frame per sample */ seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16 | ADAU1701_SEROCTL_OLF1024; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 8aae7ab74091f2..af05463af4ac9f 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -556,12 +556,12 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, unsigned int ctrl0_mask; int lrclk_pol; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER; adau->master = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ctrl0 = 0; adau->master = false; break; diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index e347a48131d1a1..5fcbdf2ec313c6 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -124,10 +124,10 @@ struct adau1977 { struct device *dev; void (*switch_mode)(struct device *dev); - unsigned int max_master_fs; + unsigned int max_clock_provider_fs; unsigned int slot_width; bool enabled; - bool master; + bool clock_provider; }; static const struct reg_default adau1977_reg_defaults[] = { @@ -330,7 +330,7 @@ static int adau1977_hw_params(struct snd_pcm_substream *substream, ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; } - if (adau1977->master) { + if (adau1977->clock_provider) { switch (params_width(params)) { case 16: ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; @@ -504,7 +504,7 @@ static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, if (slots == 0) { /* 0 = No fixed slot width */ adau1977->slot_width = 0; - adau1977->max_master_fs = 192000; + adau1977->max_clock_provider_fs = 192000; return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, ADAU1977_SAI_CTRL0_SAI_I2S); @@ -533,7 +533,7 @@ static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, break; case 24: /* We can only generate 16 bit or 32 bit wide slots */ - if (adau1977->master) + if (adau1977->clock_provider) return -EINVAL; ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; break; @@ -593,8 +593,8 @@ static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, adau1977->slot_width = width; - /* In master mode the maximum bitclock is 24.576 MHz */ - adau1977->max_master_fs = min(192000, 24576000 / width / slots); + /* In clock provider mode the maximum bitclock is 24.576 MHz */ + adau1977->max_clock_provider_fs = min(192000, 24576000 / width / slots); return 0; } @@ -620,13 +620,13 @@ static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) bool invert_lrclk; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - adau1977->master = false; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: + adau1977->clock_provider = false; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; - adau1977->master = true; + adau1977->clock_provider = true; break; default: return -EINVAL; @@ -714,9 +714,10 @@ static int adau1977_startup(struct snd_pcm_substream *substream, snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); - if (adau1977->master) + if (adau1977->clock_provider) snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); + SNDRV_PCM_HW_PARAM_RATE, 8000, + adau1977->max_clock_provider_fs); if (formats != 0) snd_pcm_hw_constraint_mask64(substream->runtime, @@ -913,7 +914,7 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->type = type; adau1977->regmap = regmap; adau1977->switch_mode = switch_mode; - adau1977->max_master_fs = 192000; + adau1977->max_clock_provider_fs = 192000; adau1977->constraints.list = adau1977_rates; adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 75a6491081066e..90f3a5e9e31f46 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -369,12 +369,12 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int capture = 0x00; unsigned int playback = 0x00; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: capture |= ADAV80X_CAPTURE_MODE_MASTER; playback |= ADAV80X_PLAYBACK_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 979cfb165eed46..dc4747c77a7a12 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -81,8 +81,8 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - /* This device can only be slave */ - if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) + /* This device can only be consumer */ + if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) return -EINVAL; ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index 5d46ae85566c15..e0a6451851e8c4 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -151,8 +151,8 @@ static const struct snd_soc_dapm_route ak4118_dapm_routes[] = { }; -static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118, - unsigned int format) +static int ak4118_set_dai_fmt_provider(struct ak4118_priv *ak4118, + unsigned int format) { int dif; @@ -173,8 +173,8 @@ static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118, return dif; } -static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118, - unsigned int format) +static int ak4118_set_dai_fmt_consumer(struct ak4118_priv *ak4118, + unsigned int format) { int dif; @@ -201,14 +201,12 @@ static int ak4118_set_dai_fmt(struct snd_soc_dai *dai, int dif; int ret = 0; - switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - /* component is master */ - dif = ak4118_set_dai_fmt_master(ak4118, format); + switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + dif = ak4118_set_dai_fmt_provider(ak4118, format); break; - case SND_SOC_DAIFMT_CBS_CFS: - /*component is slave */ - dif = ak4118_set_dai_fmt_slave(ak4118, format); + case SND_SOC_DAIFMT_CBC_CFC: + dif = ak4118_set_dai_fmt_consumer(ak4118, format); break; default: ret = -ENOTSUPP; diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 29eb78702bf35c..baa9ff5d0ce503 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -464,14 +464,14 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* Consumer Mode */ break; - case SND_SOC_DAIFMT_CBM_CFM: /* Master Mode is not supported */ - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFP: /* Provider Mode is not supported */ + case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_CBP_CFC: default: - dev_err(component->dev, "Master mode unsupported\n"); + dev_err(component->dev, "Clock provider mode unsupported\n"); return -EINVAL; } diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index c49c58eeb47631..c284dcc5af7604 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -392,13 +392,13 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) data = MCKO | PMPLL; /* use MCKO */ bcko = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* set clocking for audio interface */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: data |= MS; bcko = BCKO_64; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index eb435235b5a31a..e9d1251c426520 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -520,11 +520,11 @@ static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* set master/slave audio interface */ mode = snd_soc_component_read(component, AK4671_PLL_MODE_SELECT1); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: mode |= AK4671_M_S; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: mode &= ~(AK4671_M_S); break; default: diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 37d4600b6f2c27..c94cfde3e4a866 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -198,13 +198,13 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; u8 format; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: break; - case SND_SOC_DAIFMT_CBS_CFM: - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_CBP_CFC: default: dev_err(dai->dev, "Clock mode unsupported"); return -EINVAL; diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 54f4898371625f..b10357a6d65590 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -641,12 +641,12 @@ static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; u16 iface = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* set audio interface clocking */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface = ALC5623_DAI_SDP_MASTER_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface = ALC5623_DAI_SDP_SLAVE_MODE; break; default: diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 79813882a95522..6d7af3736a91b4 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -815,12 +815,12 @@ static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; u16 iface = 0; - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + /* set audio interface clocking */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: iface = ALC5632_DAI_SDP_MASTER_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface = ALC5632_DAI_SDP_SLAVE_MODE; break; default: diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 05bbacd0d174df..598e09024e2390 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -1168,15 +1168,15 @@ static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai, /* * "HiFi Playback" should always be configured as - * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master + * SND_SOC_DAIFMT_CBP_CFP - codec clk & frm provider * SND_SOC_DAIFMT_I2S - I2S mode */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: val &= ~BIT(CPCAP_BIT_SMB_ST_DAC); break; default: - dev_err(dev, "HiFi dai fmt failed: CPCAP should be master"); + dev_err(dev, "HiFi dai fmt failed: CPCAP should be provider"); return -EINVAL; } @@ -1318,15 +1318,15 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, /* * "Voice Playback" and "Voice Capture" should always be - * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm - * master + * configured as SND_SOC_DAIFMT_CBP_CFP - codec clk & frm + * provider */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: val &= ~BIT(CPCAP_BIT_SMB_CDC); break; default: - dev_err(component->dev, "Voice dai fmt failed: CPCAP should be the master"); + dev_err(component->dev, "Voice dai fmt failed: CPCAP should be the provider"); val &= ~BIT(CPCAP_BIT_SMB_CDC); break; } diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index a201d652aca2bb..9b92e1a0d1a3a7 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -283,8 +283,8 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct ec_param_ec_codec_i2s_rx p; enum ec_codec_i2s_rx_daifmt daifmt; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c new file mode 100644 index 00000000000000..2f3d1bd8e04637 --- /dev/null +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-i2c.c -- CS35l41 I2C driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <david.rhodes@cirrus.com> + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/cs35l41.h> +#include "cs35l41.h" + +static struct regmap_config cs35l41_regmap_i2c = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct i2c_device_id cs35l41_id_i2c[] = { + { "cs35l40", 0 }, + { "cs35l41", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c); + +static int cs35l41_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs35l41_private *cs35l41; + struct device *dev = &client->dev; + struct cs35l41_platform_data *pdata = dev_get_platdata(dev); + const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; + int ret; + + cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL); + + if (!cs35l41) + return -ENOMEM; + + cs35l41->dev = dev; + cs35l41->irq = client->irq; + + i2c_set_clientdata(client, cs35l41); + cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(cs35l41->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_i2c_remove(struct i2c_client *client) +{ + struct cs35l41_private *cs35l41 = i2c_get_clientdata(client); + + return cs35l41_remove(cs35l41); +} + +#ifdef CONFIG_OF +static const struct of_device_id cs35l41_of_match[] = { + { .compatible = "cirrus,cs35l40" }, + { .compatible = "cirrus,cs35l41" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l41_acpi_match[] = { + { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); +#endif + +static struct i2c_driver cs35l41_i2c_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = of_match_ptr(cs35l41_of_match), + .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), + }, + .id_table = cs35l41_id_i2c, + .probe = cs35l41_i2c_probe, + .remove = cs35l41_i2c_remove, +}; + +module_i2c_driver(cs35l41_i2c_driver); + +MODULE_DESCRIPTION("I2C CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c new file mode 100644 index 00000000000000..eac64779eea89d --- /dev/null +++ b/sound/soc/codecs/cs35l41-spi.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-spi.c -- CS35l41 SPI driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <david.rhodes@cirrus.com> + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#include <sound/cs35l41.h> +#include "cs35l41.h" + +static struct regmap_config cs35l41_regmap_spi = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = CS35L41_REGSTRIDE, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct spi_device_id cs35l41_id_spi[] = { + { "cs35l40", 0 }, + { "cs35l41", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(spi, cs35l41_id_spi); + +static void cs35l41_spi_otp_setup(struct cs35l41_private *cs35l41, + bool is_pre_setup, unsigned int *freq) +{ + struct spi_device *spi; + u32 orig_spi_freq; + + spi = to_spi_device(cs35l41->dev); + + if (!spi) { + dev_err(cs35l41->dev, "%s: No SPI device\n", __func__); + return; + } + + if (is_pre_setup) { + orig_spi_freq = spi->max_speed_hz; + if (orig_spi_freq > CS35L41_SPI_MAX_FREQ_OTP) { + spi->max_speed_hz = CS35L41_SPI_MAX_FREQ_OTP; + spi_setup(spi); + } + *freq = orig_spi_freq; + } else { + if (spi->max_speed_hz != *freq) { + spi->max_speed_hz = *freq; + spi_setup(spi); + } + } +} + +static int cs35l41_spi_probe(struct spi_device *spi) +{ + const struct regmap_config *regmap_config = &cs35l41_regmap_spi; + struct cs35l41_platform_data *pdata = dev_get_platdata(&spi->dev); + struct cs35l41_private *cs35l41; + int ret; + + cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL); + if (!cs35l41) + return -ENOMEM; + + spi_set_drvdata(spi, cs35l41); + cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + cs35l41->dev = &spi->dev; + cs35l41->irq = spi->irq; + cs35l41->otp_setup = cs35l41_spi_otp_setup; + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_spi_remove(struct spi_device *spi) +{ + struct cs35l41_private *cs35l41 = spi_get_drvdata(spi); + + return cs35l41_remove(cs35l41); +} + +#ifdef CONFIG_OF +static const struct of_device_id cs35l41_of_match[] = { + { .compatible = "cirrus,cs35l40" }, + { .compatible = "cirrus,cs35l41" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l41_acpi_match[] = { + { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match); +#endif + +static struct spi_driver cs35l41_spi_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = of_match_ptr(cs35l41_of_match), + .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), + }, + .id_table = cs35l41_id_spi, + .probe = cs35l41_spi_probe, + .remove = cs35l41_spi_remove, +}; + +module_spi_driver(cs35l41_spi_driver); + +MODULE_DESCRIPTION("SPI CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c new file mode 100644 index 00000000000000..964e530afa2779 --- /dev/null +++ b/sound/soc/codecs/cs35l41-tables.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41-tables.c -- CS35L41 ALSA SoC audio driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <david.rhodes@cirrus.com> + +#include "cs35l41.h" + +const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { + { CS35L41_PWR_CTRL1, 0x00000000 }, + { CS35L41_PWR_CTRL3, 0x01000010 }, + { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, + { CS35L41_SP_ENABLES, 0x00000000 }, + { CS35L41_SP_RATE_CTRL, 0x00000028 }, + { CS35L41_SP_FORMAT, 0x18180200 }, + { CS35L41_SP_HIZ_CTRL, 0x00000002 }, + { CS35L41_SP_FRAME_TX_SLOT, 0x03020100 }, + { CS35L41_SP_FRAME_RX_SLOT, 0x00000100 }, + { CS35L41_SP_TX_WL, 0x00000018 }, + { CS35L41_SP_RX_WL, 0x00000018 }, + { CS35L41_DAC_PCM1_SRC, 0x00000008 }, + { CS35L41_ASP_TX1_SRC, 0x00000018 }, + { CS35L41_ASP_TX2_SRC, 0x00000019 }, + { CS35L41_ASP_TX3_SRC, 0x00000020 }, + { CS35L41_ASP_TX4_SRC, 0x00000021 }, + { CS35L41_DSP1_RX1_SRC, 0x00000008 }, + { CS35L41_DSP1_RX2_SRC, 0x00000009 }, + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, + { CS35L41_DSP1_RX5_SRC, 0x00000020 }, + { CS35L41_DSP1_RX6_SRC, 0x00000021 }, + { CS35L41_DSP1_RX7_SRC, 0x0000003A }, + { CS35L41_DSP1_RX8_SRC, 0x00000001 }, + { CS35L41_NGATE1_SRC, 0x00000008 }, + { CS35L41_NGATE2_SRC, 0x00000009 }, + { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, + { CS35L41_CLASSH_CFG, 0x000B0405 }, + { CS35L41_WKFET_CFG, 0x00000111 }, + { CS35L41_NG_CFG, 0x00000033 }, + { CS35L41_AMP_GAIN_CTRL, 0x00000273 }, + { CS35L41_GPIO1_CTRL1, 0xE1000001 }, + { CS35L41_GPIO2_CTRL1, 0xE1000001 }, + { CS35L41_MIXER_NGATE_CFG, 0x00000000 }, + { CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 }, + { CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 }, +}; + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_REVID: + case CS35L41_FABID: + case CS35L41_RELID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_OTP_CTRL0: + case CS35L41_OTP_CTRL3: + case CS35L41_OTP_CTRL4: + case CS35L41_OTP_CTRL5: + case CS35L41_OTP_CTRL6: + case CS35L41_OTP_CTRL7: + case CS35L41_OTP_CTRL8: + case CS35L41_PWR_CTRL1: + case CS35L41_PWR_CTRL2: + case CS35L41_PWR_CTRL3: + case CS35L41_CTRL_OVRRIDE: + case CS35L41_AMP_OUT_MUTE: + case CS35L41_PROTECT_REL_ERR_IGN: + case CS35L41_GPIO_PAD_CONTROL: + case CS35L41_JTAG_CONTROL: + case CS35L41_PLL_CLK_CTRL: + case CS35L41_DSP_CLK_CTRL: + case CS35L41_GLOBAL_CLK_CTRL: + case CS35L41_DATA_FS_SEL: + case CS35L41_MDSYNC_EN: + case CS35L41_MDSYNC_TX_ID: + case CS35L41_MDSYNC_PWR_CTRL: + case CS35L41_MDSYNC_DATA_TX: + case CS35L41_MDSYNC_TX_STATUS: + case CS35L41_MDSYNC_DATA_RX: + case CS35L41_MDSYNC_RX_STATUS: + case CS35L41_MDSYNC_ERR_STATUS: + case CS35L41_MDSYNC_SYNC_PTE2: + case CS35L41_MDSYNC_SYNC_PTE3: + case CS35L41_MDSYNC_SYNC_MSM_STATUS: + case CS35L41_BSTCVRT_VCTRL1: + case CS35L41_BSTCVRT_VCTRL2: + case CS35L41_BSTCVRT_PEAK_CUR: + case CS35L41_BSTCVRT_SFT_RAMP: + case CS35L41_BSTCVRT_COEFF: + case CS35L41_BSTCVRT_SLOPE_LBST: + case CS35L41_BSTCVRT_SW_FREQ: + case CS35L41_BSTCVRT_DCM_CTRL: + case CS35L41_BSTCVRT_DCM_MODE_FORCE: + case CS35L41_BSTCVRT_OVERVOLT_CTRL: + case CS35L41_VI_VOL_POL: + case CS35L41_DTEMP_WARN_THLD: + case CS35L41_DTEMP_CFG: + case CS35L41_DTEMP_EN: + case CS35L41_VPVBST_FS_SEL: + case CS35L41_SP_ENABLES: + case CS35L41_SP_RATE_CTRL: + case CS35L41_SP_FORMAT: + case CS35L41_SP_HIZ_CTRL: + case CS35L41_SP_FRAME_TX_SLOT: + case CS35L41_SP_FRAME_RX_SLOT: + case CS35L41_SP_TX_WL: + case CS35L41_SP_RX_WL: + case CS35L41_DAC_PCM1_SRC: + case CS35L41_ASP_TX1_SRC: + case CS35L41_ASP_TX2_SRC: + case CS35L41_ASP_TX3_SRC: + case CS35L41_ASP_TX4_SRC: + case CS35L41_DSP1_RX1_SRC: + case CS35L41_DSP1_RX2_SRC: + case CS35L41_DSP1_RX3_SRC: + case CS35L41_DSP1_RX4_SRC: + case CS35L41_DSP1_RX5_SRC: + case CS35L41_DSP1_RX6_SRC: + case CS35L41_DSP1_RX7_SRC: + case CS35L41_DSP1_RX8_SRC: + case CS35L41_NGATE1_SRC: + case CS35L41_NGATE2_SRC: + case CS35L41_AMP_DIG_VOL_CTRL: + case CS35L41_VPBR_CFG: + case CS35L41_VBBR_CFG: + case CS35L41_VPBR_STATUS: + case CS35L41_VBBR_STATUS: + case CS35L41_OVERTEMP_CFG: + case CS35L41_AMP_ERR_VOL: + case CS35L41_VOL_STATUS_TO_DSP: + case CS35L41_CLASSH_CFG: + case CS35L41_WKFET_CFG: + case CS35L41_NG_CFG: + case CS35L41_AMP_GAIN_CTRL: + case CS35L41_DAC_MSM_CFG: + case CS35L41_IRQ1_CFG: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_MASK1: + case CS35L41_IRQ1_MASK2: + case CS35L41_IRQ1_MASK3: + case CS35L41_IRQ1_MASK4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_CFG: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_MASK1: + case CS35L41_IRQ2_MASK2: + case CS35L41_IRQ2_MASK3: + case CS35L41_IRQ2_MASK4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_GPIO1_CTRL1: + case CS35L41_GPIO2_CTRL1: + case CS35L41_MIXER_NGATE_CFG: + case CS35L41_MIXER_NGATE_CH1_CFG: + case CS35L41_MIXER_NGATE_CH2_CFG: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_CLOCK_DETECT_1: + case CS35L41_DIE_STS1: + case CS35L41_DIE_STS2: + case CS35L41_TEMP_CAL1: + case CS35L41_TEMP_CAL2: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + /*test regs*/ + case CS35L41_PLL_OVR: + case CS35L41_BST_TEST_DUTY: + case CS35L41_DIGPWM_IOCTRL: + return true; + default: + return false; + } +} + +bool cs35l41_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_SFT_RESET: + case CS35L41_FABID: + case CS35L41_REVID: + case CS35L41_DTEMP_EN: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +static const struct cs35l41_otp_packed_element_t otp_map_1[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ + { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ + { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ + { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ + { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ + { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ + { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ + { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ + { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ + { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ + { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ + { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ + { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ + { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ + { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ + { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ + { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ + { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ + { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ + { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ + { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ + { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ + { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ + { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ + { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ + { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ + { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ + { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ + { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ + { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ + { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ + { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ + { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ + { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ + { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ + { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ + { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ + { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ + { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ + { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ + { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ + { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ + { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ + { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ + { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ + { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ + { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ + { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ + { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ + { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ + { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ + { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ + { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ + { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ + { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ + { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ + { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ + { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ + { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ + { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ + { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ + { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ + { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ + { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ + { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ + { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ + { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ + { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ + { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ + { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ + { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ + { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ + { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ + { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ + { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ + { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ + { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ + { 0x00007434, 17, 1 }, /*FORCE_CAL*/ + { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ + { 0x00007068, 0, 9 }, /*MODIX*/ + { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ + { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ + { 0x00000000, 0, 1 }, /*extra bit*/ + { 0x00017040, 0, 8 }, /*X_COORDINATE*/ + { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ + { 0x00017040, 16, 8 }, /*WAFER_ID*/ + { 0x00017040, 24, 8 }, /*DVS*/ + { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ +}; + +static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + { 0x00002030, 0, 4 }, /*TRIM_OSC_FREQ_TRIM*/ + { 0x00002030, 7, 1 }, /*TRIM_OSC_TRIM_DONE*/ + { 0x0000208c, 24, 6 }, /*TST_DIGREG_VREF_TRIM*/ + { 0x00002090, 14, 4 }, /*TST_REF_TRIM*/ + { 0x00002090, 10, 4 }, /*TST_REF_TEMPCO_TRIM*/ + { 0x0000300C, 11, 4 }, /*PLL_LDOA_TST_VREF_TRIM*/ + { 0x0000394C, 23, 2 }, /*BST_ATEST_CM_VOFF*/ + { 0x00003950, 0, 7 }, /*BST_ATRIM_IADC_OFFSET*/ + { 0x00003950, 8, 7 }, /*BST_ATRIM_IADC_GAIN1*/ + { 0x00003950, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + { 0x00003950, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/ + { 0x00003954, 0, 7 }, /*BST_ATRIM_IADC_OFFSET2*/ + { 0x00003954, 8, 7 }, /*BST_ATRIM_IADC_GAIN2*/ + { 0x00003954, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + { 0x00003954, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/ + { 0x00003958, 0, 7 }, /*BST_ATRIM_IADC_OFFSET3*/ + { 0x00003958, 8, 7 }, /*BST_ATRIM_IADC_GAIN3*/ + { 0x00003958, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + { 0x00003958, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/ + { 0x0000395C, 0, 7 }, /*BST_ATRIM_IADC_OFFSET4*/ + { 0x0000395C, 8, 7 }, /*BST_ATRIM_IADC_GAIN4*/ + { 0x0000395C, 16, 8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + { 0x0000395C, 24, 8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/ + { 0x0000416C, 0, 8 }, /*VMON_GAIN_OTP_VAL*/ + { 0x00004160, 0, 7 }, /*VMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 8, 8 }, /*IMON_GAIN_OTP_VAL*/ + { 0x00004160, 16, 10 }, /*IMON_OFFSET_OTP_VAL*/ + { 0x0000416C, 16, 12 }, /*VMON_CM_GAIN_OTP_VAL*/ + { 0x0000416C, 28, 1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + { 0x00004170, 0, 6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/ + { 0x00004170, 6, 1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + { 0x00004170, 8, 6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + { 0x00004170, 14, 1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + { 0x00004170, 16, 9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + { 0x00004360, 0, 5 }, /*TEMP_GAIN_OTP_VAL*/ + { 0x00004360, 6, 9 }, /*TEMP_OFFSET_OTP_VAL*/ + { 0x00004448, 0, 8 }, /*VP_SARADC_OFFSET*/ + { 0x00004448, 8, 8 }, /*VP_GAIN_INDEX*/ + { 0x00004448, 16, 8 }, /*VBST_SARADC_OFFSET*/ + { 0x00004448, 24, 8 }, /*VBST_GAIN_INDEX*/ + { 0x0000444C, 0, 3 }, /*ANA_SELINVREF*/ + { 0x00006E30, 0, 5 }, /*GAIN_ERR_COEFF_0*/ + { 0x00006E30, 8, 5 }, /*GAIN_ERR_COEFF_1*/ + { 0x00006E30, 16, 5 }, /*GAIN_ERR_COEFF_2*/ + { 0x00006E30, 24, 5 }, /*GAIN_ERR_COEFF_3*/ + { 0x00006E34, 0, 5 }, /*GAIN_ERR_COEFF_4*/ + { 0x00006E34, 8, 5 }, /*GAIN_ERR_COEFF_5*/ + { 0x00006E34, 16, 5 }, /*GAIN_ERR_COEFF_6*/ + { 0x00006E34, 24, 5 }, /*GAIN_ERR_COEFF_7*/ + { 0x00006E38, 0, 5 }, /*GAIN_ERR_COEFF_8*/ + { 0x00006E38, 8, 5 }, /*GAIN_ERR_COEFF_9*/ + { 0x00006E38, 16, 5 }, /*GAIN_ERR_COEFF_10*/ + { 0x00006E38, 24, 5 }, /*GAIN_ERR_COEFF_11*/ + { 0x00006E3C, 0, 5 }, /*GAIN_ERR_COEFF_12*/ + { 0x00006E3C, 8, 5 }, /*GAIN_ERR_COEFF_13*/ + { 0x00006E3C, 16, 5 }, /*GAIN_ERR_COEFF_14*/ + { 0x00006E3C, 24, 5 }, /*GAIN_ERR_COEFF_15*/ + { 0x00006E40, 0, 5 }, /*GAIN_ERR_COEFF_16*/ + { 0x00006E40, 8, 5 }, /*GAIN_ERR_COEFF_17*/ + { 0x00006E40, 16, 5 }, /*GAIN_ERR_COEFF_18*/ + { 0x00006E40, 24, 5 }, /*GAIN_ERR_COEFF_19*/ + { 0x00006E44, 0, 5 }, /*GAIN_ERR_COEFF_20*/ + { 0x00006E48, 0, 10 }, /*VOFF_GAIN_0*/ + { 0x00006E48, 10, 10 }, /*VOFF_GAIN_1*/ + { 0x00006E48, 20, 10 }, /*VOFF_GAIN_2*/ + { 0x00006E4C, 0, 10 }, /*VOFF_GAIN_3*/ + { 0x00006E4C, 10, 10 }, /*VOFF_GAIN_4*/ + { 0x00006E4C, 20, 10 }, /*VOFF_GAIN_5*/ + { 0x00006E50, 0, 10 }, /*VOFF_GAIN_6*/ + { 0x00006E50, 10, 10 }, /*VOFF_GAIN_7*/ + { 0x00006E50, 20, 10 }, /*VOFF_GAIN_8*/ + { 0x00006E54, 0, 10 }, /*VOFF_GAIN_9*/ + { 0x00006E54, 10, 10 }, /*VOFF_GAIN_10*/ + { 0x00006E54, 20, 10 }, /*VOFF_GAIN_11*/ + { 0x00006E58, 0, 10 }, /*VOFF_GAIN_12*/ + { 0x00006E58, 10, 10 }, /*VOFF_GAIN_13*/ + { 0x00006E58, 20, 10 }, /*VOFF_GAIN_14*/ + { 0x00006E5C, 0, 10 }, /*VOFF_GAIN_15*/ + { 0x00006E5C, 10, 10 }, /*VOFF_GAIN_16*/ + { 0x00006E5C, 20, 10 }, /*VOFF_GAIN_17*/ + { 0x00006E60, 0, 10 }, /*VOFF_GAIN_18*/ + { 0x00006E60, 10, 10 }, /*VOFF_GAIN_19*/ + { 0x00006E60, 20, 10 }, /*VOFF_GAIN_20*/ + { 0x00006E64, 0, 10 }, /*VOFF_INT1*/ + { 0x00007418, 7, 5 }, /*DS_SPK_INT1_CAP_TRIM*/ + { 0x0000741C, 0, 5 }, /*DS_SPK_INT2_CAP_TRIM*/ + { 0x0000741C, 11, 4 }, /*DS_SPK_LPF_CAP_TRIM*/ + { 0x0000741C, 19, 4 }, /*DS_SPK_QUAN_CAP_TRIM*/ + { 0x00007434, 17, 1 }, /*FORCE_CAL*/ + { 0x00007434, 18, 7 }, /*CAL_OVERRIDE*/ + { 0x00007068, 0, 9 }, /*MODIX*/ + { 0x0000410C, 7, 1 }, /*VIMON_DLY_NOT_COMB*/ + { 0x0000400C, 0, 7 }, /*VIMON_DLY*/ + { 0x00004000, 11, 1 }, /*VMON_POL*/ + { 0x00017040, 0, 8 }, /*X_COORDINATE*/ + { 0x00017040, 8, 8 }, /*Y_COORDINATE*/ + { 0x00017040, 16, 8 }, /*WAFER_ID*/ + { 0x00017040, 24, 8 }, /*DVS*/ + { 0x00017044, 0, 24 }, /*LOT_NUMBER*/ +}; + +const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = { + { + .id = 0x01, + .map = otp_map_1, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x02, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x03, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x06, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x08, + .map = otp_map_1, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, +}; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c new file mode 100644 index 00000000000000..b16eb6610c0e95 --- /dev/null +++ b/sound/soc/codecs/cs35l41.c @@ -0,0 +1,1447 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l41.c -- CS35l41 ALSA SoC audio driver +// +// Copyright 2017-2021 Cirrus Logic, Inc. +// +// Author: David Rhodes <david.rhodes@cirrus.com> + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of_device.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "cs35l41.h" + +static const char * const cs35l41_supplies[CS35L41_NUM_SUPPLIES] = { + "VA", + "VP", +}; + +struct cs35l41_pll_sysclk_config { + int freq; + int clk_cfg; +}; + +static const struct cs35l41_pll_sysclk_config cs35l41_pll_sysclk[] = { + { 32768, 0x00 }, + { 8000, 0x01 }, + { 11025, 0x02 }, + { 12000, 0x03 }, + { 16000, 0x04 }, + { 22050, 0x05 }, + { 24000, 0x06 }, + { 32000, 0x07 }, + { 44100, 0x08 }, + { 48000, 0x09 }, + { 88200, 0x0A }, + { 96000, 0x0B }, + { 128000, 0x0C }, + { 176400, 0x0D }, + { 192000, 0x0E }, + { 256000, 0x0F }, + { 352800, 0x10 }, + { 384000, 0x11 }, + { 512000, 0x12 }, + { 705600, 0x13 }, + { 750000, 0x14 }, + { 768000, 0x15 }, + { 1000000, 0x16 }, + { 1024000, 0x17 }, + { 1200000, 0x18 }, + { 1411200, 0x19 }, + { 1500000, 0x1A }, + { 1536000, 0x1B }, + { 2000000, 0x1C }, + { 2048000, 0x1D }, + { 2400000, 0x1E }, + { 2822400, 0x1F }, + { 3000000, 0x20 }, + { 3072000, 0x21 }, + { 3200000, 0x22 }, + { 4000000, 0x23 }, + { 4096000, 0x24 }, + { 4800000, 0x25 }, + { 5644800, 0x26 }, + { 6000000, 0x27 }, + { 6144000, 0x28 }, + { 6250000, 0x29 }, + { 6400000, 0x2A }, + { 6500000, 0x2B }, + { 6750000, 0x2C }, + { 7526400, 0x2D }, + { 8000000, 0x2E }, + { 8192000, 0x2F }, + { 9600000, 0x30 }, + { 11289600, 0x31 }, + { 12000000, 0x32 }, + { 12288000, 0x33 }, + { 12500000, 0x34 }, + { 12800000, 0x35 }, + { 13000000, 0x36 }, + { 13500000, 0x37 }, + { 19200000, 0x38 }, + { 22579200, 0x39 }, + { 24000000, 0x3A }, + { 24576000, 0x3B }, + { 25000000, 0x3C }, + { 25600000, 0x3D }, + { 26000000, 0x3E }, + { 27000000, 0x3F }, +}; + +struct cs35l41_fs_mon_config { + int freq; + unsigned int fs1; + unsigned int fs2; +}; + +static const struct cs35l41_fs_mon_config cs35l41_fs_mon[] = { + { 32768, 2254, 3754 }, + { 8000, 9220, 15364 }, + { 11025, 6148, 10244 }, + { 12000, 6148, 10244 }, + { 16000, 4612, 7684 }, + { 22050, 3076, 5124 }, + { 24000, 3076, 5124 }, + { 32000, 2308, 3844 }, + { 44100, 1540, 2564 }, + { 48000, 1540, 2564 }, + { 88200, 772, 1284 }, + { 96000, 772, 1284 }, + { 128000, 580, 964 }, + { 176400, 388, 644 }, + { 192000, 388, 644 }, + { 256000, 292, 484 }, + { 352800, 196, 324 }, + { 384000, 196, 324 }, + { 512000, 148, 244 }, + { 705600, 100, 164 }, + { 750000, 100, 164 }, + { 768000, 100, 164 }, + { 1000000, 76, 124 }, + { 1024000, 76, 124 }, + { 1200000, 64, 104 }, + { 1411200, 52, 84 }, + { 1500000, 52, 84 }, + { 1536000, 52, 84 }, + { 2000000, 40, 64 }, + { 2048000, 40, 64 }, + { 2400000, 34, 54 }, + { 2822400, 28, 44 }, + { 3000000, 28, 44 }, + { 3072000, 28, 44 }, + { 3200000, 27, 42 }, + { 4000000, 22, 34 }, + { 4096000, 22, 34 }, + { 4800000, 19, 29 }, + { 5644800, 16, 24 }, + { 6000000, 16, 24 }, + { 6144000, 16, 24 }, +}; + +static const unsigned char cs35l41_bst_k1_table[4][5] = { + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x24, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 }, + { 0x40, 0x32, 0x32, 0x4F, 0x57 } +}; + +static const unsigned char cs35l41_bst_k2_table[4][5] = { + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x24, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA }, + { 0x48, 0x49, 0x66, 0xA3, 0xEA } +}; + +static const unsigned char cs35l41_bst_slope_table[4] = { + 0x75, 0x6B, 0x3B, 0x28 +}; + +static int cs35l41_get_fs_mon_config_index(int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_mon); i++) { + if (cs35l41_fs_mon[i].freq == freq) + return i; + } + + return -EINVAL; +} + +static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 1, 913, TLV_DB_MINMAX_ITEM(-10200, 1200)); +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); + +static const struct snd_kcontrol_new dre_ctrl = + SOC_DAPM_SINGLE("Switch", CS35L41_PWR_CTRL3, 20, 1, 0); + +static const char * const cs35l41_pcm_sftramp_text[] = { + "Off", ".5ms", "1ms", "2ms", "4ms", "8ms", "15ms", "30ms" +}; + +static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, + CS35L41_AMP_DIG_VOL_CTRL, 0, + cs35l41_pcm_sftramp_text); + +static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"}; +static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32}; +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum, + CS35L41_DAC_PCM1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_pcm_source_texts, + cs35l41_pcm_source_values); + +static const struct snd_kcontrol_new pcm_source_mux = + SOC_DAPM_ENUM("PCM Source", cs35l41_pcm_source_enum); + +static const char * const cs35l41_tx_input_texts[] = { + "Zero", "ASPRX1", "ASPRX2", "VMON", "IMON", + "VPMON", "VBSTMON", "DSPTX1", "DSPTX2" +}; + +static const unsigned int cs35l41_tx_input_values[] = { + 0x00, CS35L41_INPUT_SRC_ASPRX1, CS35L41_INPUT_SRC_ASPRX2, + CS35L41_INPUT_SRC_VMON, CS35L41_INPUT_SRC_IMON, CS35L41_INPUT_SRC_VPMON, + CS35L41_INPUT_SRC_VBSTMON, CS35L41_INPUT_DSP_TX1, CS35L41_INPUT_DSP_TX2 +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx1_enum, + CS35L41_ASP_TX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx1_mux = + SOC_DAPM_ENUM("ASPTX1 SRC", cs35l41_asptx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx2_enum, + CS35L41_ASP_TX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx2_mux = + SOC_DAPM_ENUM("ASPTX2 SRC", cs35l41_asptx2_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx3_enum, + CS35L41_ASP_TX3_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx3_mux = + SOC_DAPM_ENUM("ASPTX3 SRC", cs35l41_asptx3_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum, + CS35L41_ASP_TX4_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx4_mux = + SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum); + +static const struct snd_kcontrol_new cs35l41_aud_controls[] = { + SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL, + 3, 0x4CF, 0x391, dig_vol_tlv), + SOC_SINGLE_TLV("Analog PCM Volume", CS35L41_AMP_GAIN_CTRL, 5, 0x14, 0, + amp_gain_tlv), + SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp), + SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0), + SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0), + SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0), + SOC_SINGLE("Aux Noise Gate CH1 Enable", + CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0), + SOC_SINGLE("Aux Noise Gate CH1 Entry Delay", + CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0), + SOC_SINGLE("Aux Noise Gate CH1 Threshold", + CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0), + SOC_SINGLE("Aux Noise Gate CH2 Entry Delay", + CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0), + SOC_SINGLE("Aux Noise Gate CH2 Enable", + CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0), + SOC_SINGLE("Aux Noise Gate CH2 Threshold", + CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0), + SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0), + SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL, + CS35L41_AMP_INV_PCM_SHIFT, 1, 0), + SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL, + CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0), +}; + +static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { + if (cs35l41_otp_map_map[i].id == otp_id) + return &cs35l41_otp_map_map[i]; + } + + return NULL; +} + +static int cs35l41_otp_unpack(void *data) +{ + const struct cs35l41_otp_map_element_t *otp_map_match; + const struct cs35l41_otp_packed_element_t *otp_map; + struct cs35l41_private *cs35l41 = data; + int bit_offset, word_offset, ret, i; + unsigned int orig_spi_freq; + unsigned int bit_sum = 8; + u32 otp_val, otp_id_reg; + u32 *otp_mem; + + otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL); + if (!otp_mem) + return -ENOMEM; + + ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP ID failed: %d\n", ret); + goto err_otp_unpack; + } + + otp_map_match = cs35l41_find_otp_map(otp_id_reg); + + if (!otp_map_match) { + dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", + otp_id_reg); + ret = -EINVAL; + goto err_otp_unpack; + } + + if (cs35l41->otp_setup) + cs35l41->otp_setup(cs35l41, true, &orig_spi_freq); + + ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem, + CS35L41_OTP_SIZE_WORDS); + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP Mem failed: %d\n", ret); + goto err_otp_unpack; + } + + if (cs35l41->otp_setup) + cs35l41->otp_setup(cs35l41, false, &orig_spi_freq); + + otp_map = otp_map_match->map; + + bit_offset = otp_map_match->bit_offset; + word_offset = otp_map_match->word_offset; + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 1/2: %d\n", ret); + goto err_otp_unpack; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 2/2: %d\n", ret); + goto err_otp_unpack; + } + + for (i = 0; i < otp_map_match->num_elements; i++) { + dev_dbg(cs35l41->dev, + "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", + bit_offset, word_offset, bit_sum % 32); + if (bit_offset + otp_map[i].size - 1 >= 32) { + otp_val = (otp_mem[word_offset] & + GENMASK(31, bit_offset)) >> + bit_offset; + otp_val |= (otp_mem[++word_offset] & + GENMASK(bit_offset + + otp_map[i].size - 33, 0)) << + (32 - bit_offset); + bit_offset += otp_map[i].size - 32; + } else { + otp_val = (otp_mem[word_offset] & + GENMASK(bit_offset + otp_map[i].size - 1, + bit_offset)) >> bit_offset; + bit_offset += otp_map[i].size; + } + bit_sum += otp_map[i].size; + + if (bit_offset == 32) { + bit_offset = 0; + word_offset++; + } + + if (otp_map[i].reg != 0) { + ret = regmap_update_bits(cs35l41->regmap, + otp_map[i].reg, + GENMASK(otp_map[i].shift + + otp_map[i].size - 1, + otp_map[i].shift), + otp_val << otp_map[i].shift); + if (ret < 0) { + dev_err(cs35l41->dev, "Write OTP val failed: %d\n", + ret); + goto err_otp_unpack; + } + } + } + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 1/2: %d\n", ret); + goto err_otp_unpack; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 2/2: %d\n", ret); + goto err_otp_unpack; + } + ret = 0; + +err_otp_unpack: + kfree(otp_mem); + return ret; +} + +static irqreturn_t cs35l41_irq(int irq, void *data) +{ + struct cs35l41_private *cs35l41 = data; + unsigned int status[4] = { 0, 0, 0, 0 }; + unsigned int masks[4] = { 0, 0, 0, 0 }; + int ret = IRQ_NONE; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(status); i++) { + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE), + &status[i]); + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_MASK1 + (i * CS35L41_REGSTRIDE), + &masks[i]); + } + + /* Check to see if unmasked bits are active */ + if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) && + !(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) + return IRQ_NONE; + + if (status[3] & CS35L41_OTP_BOOT_DONE) { + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK4, + CS35L41_OTP_BOOT_DONE, CS35L41_OTP_BOOT_DONE); + } + + /* + * The following interrupts require a + * protection release cycle to get the + * speaker out of Safe-Mode. + */ + if (status[0] & CS35L41_AMP_SHORT_ERR) { + dev_crit_ratelimited(cs35l41->dev, "Amp short error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_AMP_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, + CS35L41_AMP_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_TEMP_WARN) { + dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_WARN); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, + CS35L41_TEMP_WARN_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_TEMP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, + CS35L41_TEMP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, 0); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_OVP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_OVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, + CS35L41_BST_OVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_DCM_UVP_ERR) { + dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_DCM_UVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, + CS35L41_BST_UVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L41_BST_SHORT_ERR) { + dev_crit_ratelimited(cs35l41->dev, "LBST error: powering off!\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, + CS35L41_BST_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT); + ret = IRQ_HANDLED; + } + + return ret; +} + +static const struct reg_sequence cs35l41_pup_patch[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00002084, 0x002F1AA0 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static const struct reg_sequence cs35l41_pdn_patch[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00002084, 0x002F1AA3 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, +}; + +static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + unsigned int val; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pup_patch, + ARRAY_SIZE(cs35l41_pup_patch)); + + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, + 1 << CS35L41_GLOBAL_EN_SHIFT); + + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, 0); + + ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + val, val & CS35L41_PDN_DONE_MASK, + 1000, 100000); + if (ret) + dev_warn(cs35l41->dev, "PDN failed: %d\n", ret); + + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_PDN_DONE_MASK); + + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pdn_patch, + ARRAY_SIZE(cs35l41_pdn_patch)); + break; + default: + dev_err(cs35l41->dev, "Invalid event = 0x%x\n", event); + ret = -EINVAL; + } + + return ret; +} + +static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0), + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, CS35L41_SP_ENABLES, 17, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, CS35L41_SP_ENABLES, 0, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 0, CS35L41_SP_ENABLES, 1, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 0, CS35L41_SP_ENABLES, 2, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 0, CS35L41_SP_ENABLES, 3, 0), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0), + SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0, + cs35l41_main_amp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VBST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + SND_SOC_DAPM_INPUT("TEMP"), + + SND_SOC_DAPM_MUX("ASP TX1 Source", SND_SOC_NOPM, 0, 0, &asp_tx1_mux), + SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux), + SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux), + SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux), + SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux), + SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl), +}; + +static const struct snd_soc_dapm_route cs35l41_audio_map[] = { + {"ASP TX1 Source", "VMON", "VMON ADC"}, + {"ASP TX1 Source", "IMON", "IMON ADC"}, + {"ASP TX1 Source", "VPMON", "VPMON ADC"}, + {"ASP TX1 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX1 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX1 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX2 Source", "VMON", "VMON ADC"}, + {"ASP TX2 Source", "IMON", "IMON ADC"}, + {"ASP TX2 Source", "VPMON", "VPMON ADC"}, + {"ASP TX2 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX2 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX2 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX3 Source", "VMON", "VMON ADC"}, + {"ASP TX3 Source", "IMON", "IMON ADC"}, + {"ASP TX3 Source", "VPMON", "VPMON ADC"}, + {"ASP TX3 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX3 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX3 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX4 Source", "VMON", "VMON ADC"}, + {"ASP TX4 Source", "IMON", "IMON ADC"}, + {"ASP TX4 Source", "VPMON", "VPMON ADC"}, + {"ASP TX4 Source", "VBSTMON", "VBSTMON ADC"}, + {"ASP TX4 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX4 Source", "ASPRX2", "ASPRX2" }, + {"ASPTX1", NULL, "ASP TX1 Source"}, + {"ASPTX2", NULL, "ASP TX2 Source"}, + {"ASPTX3", NULL, "ASP TX3 Source"}, + {"ASPTX4", NULL, "ASP TX4 Source"}, + {"AMP Capture", NULL, "ASPTX1"}, + {"AMP Capture", NULL, "ASPTX2"}, + {"AMP Capture", NULL, "ASPTX3"}, + {"AMP Capture", NULL, "ASPTX4"}, + + {"VMON ADC", NULL, "VSENSE"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VPMON ADC", NULL, "VP"}, + {"TEMPMON ADC", NULL, "TEMP"}, + {"VBSTMON ADC", NULL, "VBST"}, + + {"ASPRX1", NULL, "AMP Playback"}, + {"ASPRX2", NULL, "AMP Playback"}, + {"DRE", "Switch", "CLASS H"}, + {"Main AMP", NULL, "CLASS H"}, + {"Main AMP", NULL, "DRE"}, + {"SPK", NULL, "Main AMP"}, + + {"PCM Source", "ASP", "ASPRX1"}, + {"CLASS H", NULL, "PCM Source"}, +}; + +static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, + unsigned int *tx_slot, unsigned int rx_num, + unsigned int *rx_slot) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); + unsigned int val, mask; + int i; + + if (tx_num > 4 || rx_num > 2) + return -EINVAL; + + val = 0; + mask = 0; + for (i = 0; i < rx_num; i++) { + dev_dbg(cs35l41->dev, "rx slot %d position = %d\n", i, rx_slot[i]); + val |= rx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_RX_SLOT, mask, val); + + val = 0; + mask = 0; + for (i = 0; i < tx_num; i++) { + dev_dbg(cs35l41->dev, "tx slot %d position = %d\n", i, tx_slot[i]); + val |= tx_slot[i] << (i * 8); + mask |= 0x3F << (i * 8); + } + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FRAME_TX_SLOT, mask, val); + + return 0; +} + +static int cs35l41_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); + unsigned int daifmt = 0; + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + daifmt |= CS35L41_SCLK_MSTR_MASK | CS35L41_LRCLK_MSTR_MASK; + break; + case SND_SOC_DAIFMT_CBC_CFC: + break; + default: + dev_warn(cs35l41->dev, "Mixed provider/consumer mode unsupported\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + break; + case SND_SOC_DAIFMT_I2S: + daifmt |= 2 << CS35L41_ASP_FMT_SHIFT; + break; + default: + dev_warn(cs35l41->dev, "Invalid or unsupported DAI format\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + daifmt |= CS35L41_LRCLK_INV_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + daifmt |= CS35L41_SCLK_INV_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + daifmt |= CS35L41_LRCLK_INV_MASK | CS35L41_SCLK_INV_MASK; + break; + case SND_SOC_DAIFMT_NB_NF: + break; + default: + dev_warn(cs35l41->dev, "Invalid DAI clock INV\n"); + return -EINVAL; + } + + return regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_MSTR_MASK | CS35L41_LRCLK_MSTR_MASK | + CS35L41_ASP_FMT_MASK | CS35L41_LRCLK_INV_MASK | + CS35L41_SCLK_INV_MASK, daifmt); +} + +struct cs35l41_global_fs_config { + int rate; + int fs_cfg; +}; + +static const struct cs35l41_global_fs_config cs35l41_fs_rates[] = { + { 12000, 0x01 }, + { 24000, 0x02 }, + { 48000, 0x03 }, + { 96000, 0x04 }, + { 192000, 0x05 }, + { 11025, 0x09 }, + { 22050, 0x0A }, + { 44100, 0x0B }, + { 88200, 0x0C }, + { 176400, 0x0D }, + { 8000, 0x11 }, + { 16000, 0x12 }, + { 32000, 0x13 }, +}; + +static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); + unsigned int rate = params_rate(params); + u8 asp_wl; + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { + if (rate == cs35l41_fs_rates[i].rate) + break; + } + + if (i >= ARRAY_SIZE(cs35l41_fs_rates)) { + dev_err(cs35l41->dev, "Unsupported rate: %u\n", rate); + return -EINVAL; + } + + asp_wl = params_width(params); + + if (i < ARRAY_SIZE(cs35l41_fs_rates)) + regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, + CS35L41_GLOBAL_FS_MASK, + cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_RX_MASK, + asp_wl << CS35L41_ASP_WIDTH_RX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, + CS35L41_ASP_RX_WL_MASK, + asp_wl << CS35L41_ASP_RX_WL_SHIFT); + } else { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_TX_MASK, + asp_wl << CS35L41_ASP_WIDTH_TX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, + CS35L41_ASP_TX_WL_MASK, + asp_wl << CS35L41_ASP_TX_WL_SHIFT); + } + + return 0; +} + +static int cs35l41_get_clk_config(int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_pll_sysclk); i++) { + if (cs35l41_pll_sysclk[i].freq == freq) + return cs35l41_pll_sysclk[i].clk_cfg; + } + + return -EINVAL; +} + +static const unsigned int cs35l41_src_rates[] = { + 8000, 12000, 11025, 16000, 22050, 24000, 32000, + 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l41_constraints = { + .count = ARRAY_SIZE(cs35l41_src_rates), + .list = cs35l41_src_rates, +}; + +static int cs35l41_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->runtime) + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &cs35l41_constraints); + return 0; +} + +static int cs35l41_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); + int extclk_cfg, clksrc; + + switch (clk_id) { + case CS35L41_CLKID_SCLK: + clksrc = CS35L41_PLLSRC_SCLK; + break; + case CS35L41_CLKID_LRCLK: + clksrc = CS35L41_PLLSRC_LRCLK; + break; + case CS35L41_CLKID_MCLK: + clksrc = CS35L41_PLLSRC_MCLK; + break; + default: + dev_err(cs35l41->dev, "Invalid CLK Config\n"); + return -EINVAL; + } + + extclk_cfg = cs35l41_get_clk_config(freq); + + if (extclk_cfg < 0) { + dev_err(cs35l41->dev, "Invalid CLK Config: %d, freq: %u\n", + extclk_cfg, freq); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 1 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_REFCLK_FREQ_MASK, + extclk_cfg << CS35L41_REFCLK_FREQ_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 0 << CS35L41_PLL_CLK_EN_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_SEL_MASK, clksrc); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 0 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 1 << CS35L41_PLL_CLK_EN_SHIFT); + + return 0; +} + +static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); + unsigned int fs1_val; + unsigned int fs2_val; + unsigned int val; + int fsindex; + + fsindex = cs35l41_get_fs_mon_config_index(freq); + if (fsindex < 0) { + dev_err(cs35l41->dev, "Invalid CLK Config freq: %u\n", freq); + return -EINVAL; + } + + dev_dbg(cs35l41->dev, "Set DAI sysclk %d\n", freq); + + if (freq <= 6144000) { + /* Use the lookup table */ + fs1_val = cs35l41_fs_mon[fsindex].fs1; + fs2_val = cs35l41_fs_mon[fsindex].fs2; + } else { + /* Use hard-coded values */ + fs1_val = 0x10; + fs2_val = 0x24; + } + + val = fs1_val; + val |= (fs2_val << CS35L41_FS2_WINDOW_SHIFT) & CS35L41_FS2_WINDOW_MASK; + regmap_write(cs35l41->regmap, CS35L41_TST_FS_MON0, val); + + return 0; +} + +static int cs35l41_boost_config(struct cs35l41_private *cs35l41, + int boost_ind, int boost_cap, int boost_ipk) +{ + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; + struct regmap *regmap = cs35l41->regmap; + struct device *dev = cs35l41->dev; + int ret; + + switch (boost_ind) { + case 1000: /* 1.0 uH */ + bst_lbst_val = 0; + break; + case 1200: /* 1.2 uH */ + bst_lbst_val = 1; + break; + case 1500: /* 1.5 uH */ + bst_lbst_val = 2; + break; + case 2200: /* 2.2 uH */ + bst_lbst_val = 3; + break; + default: + dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind); + return -EINVAL; + } + + switch (boost_cap) { + case 0 ... 19: + bst_cbst_range = 0; + break; + case 20 ... 50: + bst_cbst_range = 1; + break; + case 51 ... 100: + bst_cbst_range = 2; + break; + case 101 ... 200: + bst_cbst_range = 3; + break; + default: /* 201 uF and greater */ + bst_cbst_range = 4; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK, + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K1_SHIFT | + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K2_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost coefficients: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK, + cs35l41_bst_slope_table[bst_lbst_val] + << CS35L41_BST_SLOPE_SHIFT | + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret); + return ret; + } + + if (boost_ipk < 1600 || boost_ipk > 4500) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", + boost_ipk); + return -EINVAL; + } + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, + CS35L41_BST_IPK_MASK, + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret); + return ret; + } + + return 0; +} + +static int cs35l41_set_pdata(struct cs35l41_private *cs35l41) +{ + int ret; + + /* Set Platform Data */ + /* Required */ + if (cs35l41->pdata.bst_ipk && + cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { + ret = cs35l41_boost_config(cs35l41, cs35l41->pdata.bst_ind, + cs35l41->pdata.bst_cap, + cs35l41->pdata.bst_ipk); + if (ret) { + dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret); + return ret; + } + } else { + dev_err(cs35l41->dev, "Incomplete Boost component DT config\n"); + return -EINVAL; + } + + /* Optional */ + if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && + cs35l41->pdata.dout_hiz >= 0) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, + CS35L41_ASP_DOUT_HIZ_MASK, + cs35l41->pdata.dout_hiz); + + return 0; +} + +static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) +{ + struct cs35l41_irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1; + struct cs35l41_irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2; + int irq_pol = IRQF_TRIGGER_NONE; + + regmap_update_bits(cs35l41->regmap, CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | + !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); + + regmap_update_bits(cs35l41->regmap, CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK, + irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT | + !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT); + + regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL, + CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK, + irq_gpio_cfg1->irq_src_sel << CS35L41_GPIO1_CTRL_SHIFT | + irq_gpio_cfg2->irq_src_sel << CS35L41_GPIO2_CTRL_SHIFT); + + if ((irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) || + (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_OPEN_INT | CS35L41_VALID_PDATA))) + irq_pol = IRQF_TRIGGER_LOW; + else if (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA)) + irq_pol = IRQF_TRIGGER_HIGH; + + return irq_pol; +} + +static const struct snd_soc_dai_ops cs35l41_ops = { + .startup = cs35l41_pcm_startup, + .set_fmt = cs35l41_set_dai_fmt, + .hw_params = cs35l41_pcm_hw_params, + .set_sysclk = cs35l41_dai_set_sysclk, + .set_channel_map = cs35l41_set_channel_map, +}; + +static struct snd_soc_dai_driver cs35l41_dai[] = { + { + .name = "cs35l41-pcm", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_RX_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_TX_FORMATS, + }, + .ops = &cs35l41_ops, + .symmetric_rate = 1, + }, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs35l41 = { + .name = "cs35l41-codec", + + .dapm_widgets = cs35l41_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets), + .dapm_routes = cs35l41_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l41_audio_map), + + .controls = cs35l41_aud_controls, + .num_controls = ARRAY_SIZE(cs35l41_aud_controls), + .set_sysclk = cs35l41_component_set_sysclk, +}; + +static int cs35l41_handle_pdata(struct device *dev, + struct cs35l41_platform_data *pdata, + struct cs35l41_private *cs35l41) +{ + struct cs35l41_irq_cfg *irq_gpio1_config = &pdata->irq_config1; + struct cs35l41_irq_cfg *irq_gpio2_config = &pdata->irq_config2; + unsigned int val; + int ret; + + ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val); + if (ret >= 0) + pdata->bst_ipk = val; + + ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val); + if (ret >= 0) + pdata->bst_ind = val; + + ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val); + if (ret >= 0) + pdata->bst_cap = val; + + ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val); + if (ret >= 0) + pdata->dout_hiz = val; + else + pdata->dout_hiz = -1; + + /* GPIO1 Pin Config */ + irq_gpio1_config->irq_pol_inv = device_property_read_bool(dev, + "cirrus,gpio1-polarity-invert"); + irq_gpio1_config->irq_out_en = device_property_read_bool(dev, + "cirrus,gpio1-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", + &val); + if (ret >= 0) + irq_gpio1_config->irq_src_sel = val | CS35L41_VALID_PDATA; + + /* GPIO2 Pin Config */ + irq_gpio2_config->irq_pol_inv = device_property_read_bool(dev, + "cirrus,gpio2-polarity-invert"); + irq_gpio2_config->irq_out_en = device_property_read_bool(dev, + "cirrus,gpio2-output-enable"); + ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", + &val); + if (ret >= 0) + irq_gpio2_config->irq_src_sel = val | CS35L41_VALID_PDATA; + + return 0; +} + +static const struct reg_sequence cs35l41_reva0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { 0x00003854, 0x05180240 }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_OTP_TRIM_30, 0x9091A1C8 }, + { 0x00003014, 0x0200EE0E }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { 0x00000054, 0x00000004 }, + { CS35L41_IRQ1_DB3, 0x00000000 }, + { CS35L41_IRQ2_DB3, 0x00000000 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +static const struct reg_sequence cs35l41_revb0_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +static const struct reg_sequence cs35l41_revb2_errata_patch[] = { + { 0x00000040, 0x00005555 }, + { 0x00000040, 0x0000AAAA }, + { CS35L41_VIMON_SPKMON_RESYNC, 0x00000000 }, + { 0x00004310, 0x00000000 }, + { CS35L41_VPVBST_FS_SEL, 0x00000000 }, + { CS35L41_BSTCVRT_DCM_CTRL, 0x00000051 }, + { CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 }, + { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 }, + { 0x00000040, 0x0000CCCC }, + { 0x00000040, 0x00003333 }, +}; + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata) +{ + u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; + int irq_pol = 0; + int ret; + + if (pdata) { + cs35l41->pdata = *pdata; + } else { + ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata, cs35l41); + if (ret != 0) + return ret; + } + + for (i = 0; i < CS35L41_NUM_SUPPLIES; i++) + cs35l41->supplies[i].supply = cs35l41_supplies[i]; + + ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES, + cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, "Failed to request core supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, "Failed to enable core supplies: %d\n", ret); + return ret; + } + + /* returning NULL can be an option if in stereo mode */ + cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(cs35l41->reset_gpio)) { + ret = PTR_ERR(cs35l41->reset_gpio); + cs35l41->reset_gpio = NULL; + if (ret == -EBUSY) { + dev_info(cs35l41->dev, + "Reset line busy, assuming shared reset\n"); + } else { + dev_err(cs35l41->dev, + "Failed to get reset GPIO: %d\n", ret); + goto err; + } + } + if (cs35l41->reset_gpio) { + /* satisfy minimum reset pulse width spec */ + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 1); + } + + usleep_range(2000, 2100); + + ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, + int_status, int_status & CS35L41_OTP_BOOT_DONE, + 1000, 100000); + if (ret) { + dev_err(cs35l41->dev, + "Failed waiting for OTP_BOOT_DONE: %d\n", ret); + goto err; + } + + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status); + if (int_status & CS35L41_OTP_BOOT_ERR) { + dev_err(cs35l41->dev, "OTP Boot error\n"); + ret = -EINVAL; + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, ®id); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret); + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_REVID, ®_revid); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret); + goto err; + } + + mtl_revid = reg_revid & CS35L41_MTLREVID_MASK; + + /* CS35L41 will have even MTLREVID + * CS35L41R will have odd MTLREVID + */ + chipid_match = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID; + if (regid != chipid_match) { + dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", + regid, chipid_match); + ret = -ENODEV; + goto err; + } + + switch (reg_revid) { + case CS35L41_REVID_A0: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_reva0_errata_patch, + ARRAY_SIZE(cs35l41_reva0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply A0 errata patch: %d\n", ret); + goto err; + } + break; + case CS35L41_REVID_B0: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_revb0_errata_patch, + ARRAY_SIZE(cs35l41_revb0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply B0 errata patch: %d\n", ret); + goto err; + } + break; + case CS35L41_REVID_B2: + ret = regmap_register_patch(cs35l41->regmap, + cs35l41_revb2_errata_patch, + ARRAY_SIZE(cs35l41_revb2_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply B2 errata patch: %d\n", ret); + goto err; + } + break; + } + + irq_pol = cs35l41_irq_gpio_config(cs35l41); + + /* Set interrupt masks for critical errors */ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, + CS35L41_INT1_MASK_DEFAULT); + + ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq, + IRQF_ONESHOT | IRQF_SHARED | irq_pol, + "cs35l41", cs35l41); + + /* CS35L41 needs INT for PDN_DONE */ + if (ret != 0) { + dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); + goto err; + } + + ret = cs35l41_otp_unpack(cs35l41); + if (ret < 0) { + dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret); + goto err; + } + + ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_CCM_CORE_CTRL, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CCM_CORE_CTRL failed: %d\n", ret); + goto err; + } + + ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_AMP_EN_MASK, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CS35L41_PWR_CTRL2 failed: %d\n", ret); + goto err; + } + + ret = regmap_update_bits(cs35l41->regmap, CS35L41_AMP_GAIN_CTRL, + CS35L41_AMP_GAIN_PCM_MASK, 0); + if (ret < 0) { + dev_err(cs35l41->dev, "Write CS35L41_AMP_GAIN_CTRL failed: %d\n", ret); + goto err; + } + + ret = cs35l41_set_pdata(cs35l41); + if (ret < 0) { + dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret); + goto err; + } + + ret = devm_snd_soc_register_component(cs35l41->dev, + &soc_component_dev_cs35l41, + cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); + if (ret < 0) { + dev_err(cs35l41->dev, "Register codec failed: %d\n", ret); + goto err; + } + + dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", + regid, reg_revid); + + return 0; + +err: + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); + + return ret; +} + +int cs35l41_remove(struct cs35l41_private *cs35l41) +{ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies); + gpiod_set_value_cansleep(cs35l41->reset_gpio, 0); + + return 0; +} + +MODULE_DESCRIPTION("ASoC CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h new file mode 100644 index 00000000000000..0e2639d6ef193d --- /dev/null +++ b/sound/soc/codecs/cs35l41.h @@ -0,0 +1,775 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * cs35l41.h -- CS35L41 ALSA SoC audio driver + * + * Copyright 2017-2021 Cirrus Logic, Inc. + * + * Author: David Rhodes <david.rhodes@cirrus.com> + */ + +#ifndef __CS35L41_H__ +#define __CS35L41_H__ + +#include <linux/gpio/consumer.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/core.h> +#include <sound/cs35l41.h> + +#define CS35L41_FIRSTREG 0x00000000 +#define CS35L41_LASTREG 0x03804FE8 +#define CS35L41_DEVID 0x00000000 +#define CS35L41_REVID 0x00000004 +#define CS35L41_FABID 0x00000008 +#define CS35L41_RELID 0x0000000C +#define CS35L41_OTPID 0x00000010 +#define CS35L41_SFT_RESET 0x00000020 +#define CS35L41_TEST_KEY_CTL 0x00000040 +#define CS35L41_USER_KEY_CTL 0x00000044 +#define CS35L41_OTP_MEM0 0x00000400 +#define CS35L41_OTP_MEM31 0x0000047C +#define CS35L41_OTP_CTRL0 0x00000500 +#define CS35L41_OTP_CTRL1 0x00000504 +#define CS35L41_OTP_CTRL3 0x00000508 +#define CS35L41_OTP_CTRL4 0x0000050C +#define CS35L41_OTP_CTRL5 0x00000510 +#define CS35L41_OTP_CTRL6 0x00000514 +#define CS35L41_OTP_CTRL7 0x00000518 +#define CS35L41_OTP_CTRL8 0x0000051C +#define CS35L41_PWR_CTRL1 0x00002014 +#define CS35L41_PWR_CTRL2 0x00002018 +#define CS35L41_PWR_CTRL3 0x0000201C +#define CS35L41_CTRL_OVRRIDE 0x00002020 +#define CS35L41_AMP_OUT_MUTE 0x00002024 +#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 +#define CS35L41_GPIO_PAD_CONTROL 0x0000242C +#define CS35L41_JTAG_CONTROL 0x00002438 +#define CS35L41_PLL_CLK_CTRL 0x00002C04 +#define CS35L41_DSP_CLK_CTRL 0x00002C08 +#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C +#define CS35L41_DATA_FS_SEL 0x00002C10 +#define CS35L41_TST_FS_MON0 0x00002D10 +#define CS35L41_MDSYNC_EN 0x00003400 +#define CS35L41_MDSYNC_TX_ID 0x00003408 +#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C +#define CS35L41_MDSYNC_DATA_TX 0x00003410 +#define CS35L41_MDSYNC_TX_STATUS 0x00003414 +#define CS35L41_MDSYNC_DATA_RX 0x0000341C +#define CS35L41_MDSYNC_RX_STATUS 0x00003420 +#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 +#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 +#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C +#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C +#define CS35L41_BSTCVRT_VCTRL1 0x00003800 +#define CS35L41_BSTCVRT_VCTRL2 0x00003804 +#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 +#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C +#define CS35L41_BSTCVRT_COEFF 0x00003810 +#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 +#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 +#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C +#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 +#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 +#define CS35L41_VI_VOL_POL 0x00004000 +#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 +#define CS35L41_DTEMP_WARN_THLD 0x00004220 +#define CS35L41_DTEMP_CFG 0x00004224 +#define CS35L41_DTEMP_EN 0x00004308 +#define CS35L41_VPVBST_FS_SEL 0x00004400 +#define CS35L41_SP_ENABLES 0x00004800 +#define CS35L41_SP_RATE_CTRL 0x00004804 +#define CS35L41_SP_FORMAT 0x00004808 +#define CS35L41_SP_HIZ_CTRL 0x0000480C +#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 +#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 +#define CS35L41_SP_TX_WL 0x00004830 +#define CS35L41_SP_RX_WL 0x00004840 +#define CS35L41_ASP_CONTROL4 0x00004854 +#define CS35L41_DAC_PCM1_SRC 0x00004C00 +#define CS35L41_ASP_TX1_SRC 0x00004C20 +#define CS35L41_ASP_TX2_SRC 0x00004C24 +#define CS35L41_ASP_TX3_SRC 0x00004C28 +#define CS35L41_ASP_TX4_SRC 0x00004C2C +#define CS35L41_DSP1_RX1_SRC 0x00004C40 +#define CS35L41_DSP1_RX2_SRC 0x00004C44 +#define CS35L41_DSP1_RX3_SRC 0x00004C48 +#define CS35L41_DSP1_RX4_SRC 0x00004C4C +#define CS35L41_DSP1_RX5_SRC 0x00004C50 +#define CS35L41_DSP1_RX6_SRC 0x00004C54 +#define CS35L41_DSP1_RX7_SRC 0x00004C58 +#define CS35L41_DSP1_RX8_SRC 0x00004C5C +#define CS35L41_NGATE1_SRC 0x00004C60 +#define CS35L41_NGATE2_SRC 0x00004C64 +#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 +#define CS35L41_VPBR_CFG 0x00006404 +#define CS35L41_VBBR_CFG 0x00006408 +#define CS35L41_VPBR_STATUS 0x0000640C +#define CS35L41_VBBR_STATUS 0x00006410 +#define CS35L41_OVERTEMP_CFG 0x00006414 +#define CS35L41_AMP_ERR_VOL 0x00006418 +#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 +#define CS35L41_CLASSH_CFG 0x00006800 +#define CS35L41_WKFET_CFG 0x00006804 +#define CS35L41_NG_CFG 0x00006808 +#define CS35L41_AMP_GAIN_CTRL 0x00006C04 +#define CS35L41_DAC_MSM_CFG 0x00007400 +#define CS35L41_IRQ1_CFG 0x00010000 +#define CS35L41_IRQ1_STATUS 0x00010004 +#define CS35L41_IRQ1_STATUS1 0x00010010 +#define CS35L41_IRQ1_STATUS2 0x00010014 +#define CS35L41_IRQ1_STATUS3 0x00010018 +#define CS35L41_IRQ1_STATUS4 0x0001001C +#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 +#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 +#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 +#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C +#define CS35L41_IRQ1_MASK1 0x00010110 +#define CS35L41_IRQ1_MASK2 0x00010114 +#define CS35L41_IRQ1_MASK3 0x00010118 +#define CS35L41_IRQ1_MASK4 0x0001011C +#define CS35L41_IRQ1_FRC1 0x00010190 +#define CS35L41_IRQ1_FRC2 0x00010194 +#define CS35L41_IRQ1_FRC3 0x00010198 +#define CS35L41_IRQ1_FRC4 0x0001019C +#define CS35L41_IRQ1_EDGE1 0x00010210 +#define CS35L41_IRQ1_EDGE4 0x0001021C +#define CS35L41_IRQ1_POL1 0x00010290 +#define CS35L41_IRQ1_POL2 0x00010294 +#define CS35L41_IRQ1_POL3 0x00010298 +#define CS35L41_IRQ1_POL4 0x0001029C +#define CS35L41_IRQ1_DB3 0x00010318 +#define CS35L41_IRQ2_CFG 0x00010800 +#define CS35L41_IRQ2_STATUS 0x00010804 +#define CS35L41_IRQ2_STATUS1 0x00010810 +#define CS35L41_IRQ2_STATUS2 0x00010814 +#define CS35L41_IRQ2_STATUS3 0x00010818 +#define CS35L41_IRQ2_STATUS4 0x0001081C +#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 +#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 +#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 +#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C +#define CS35L41_IRQ2_MASK1 0x00010910 +#define CS35L41_IRQ2_MASK2 0x00010914 +#define CS35L41_IRQ2_MASK3 0x00010918 +#define CS35L41_IRQ2_MASK4 0x0001091C +#define CS35L41_IRQ2_FRC1 0x00010990 +#define CS35L41_IRQ2_FRC2 0x00010994 +#define CS35L41_IRQ2_FRC3 0x00010998 +#define CS35L41_IRQ2_FRC4 0x0001099C +#define CS35L41_IRQ2_EDGE1 0x00010A10 +#define CS35L41_IRQ2_EDGE4 0x00010A1C +#define CS35L41_IRQ2_POL1 0x00010A90 +#define CS35L41_IRQ2_POL2 0x00010A94 +#define CS35L41_IRQ2_POL3 0x00010A98 +#define CS35L41_IRQ2_POL4 0x00010A9C +#define CS35L41_IRQ2_DB3 0x00010B18 +#define CS35L41_GPIO_STATUS1 0x00011000 +#define CS35L41_GPIO1_CTRL1 0x00011008 +#define CS35L41_GPIO2_CTRL1 0x0001100C +#define CS35L41_MIXER_NGATE_CFG 0x00012000 +#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 +#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 +#define CS35L41_DSP_MBOX_1 0x00013000 +#define CS35L41_DSP_MBOX_2 0x00013004 +#define CS35L41_DSP_MBOX_3 0x00013008 +#define CS35L41_DSP_MBOX_4 0x0001300C +#define CS35L41_DSP_MBOX_5 0x00013010 +#define CS35L41_DSP_MBOX_6 0x00013014 +#define CS35L41_DSP_MBOX_7 0x00013018 +#define CS35L41_DSP_MBOX_8 0x0001301C +#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 +#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 +#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 +#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C +#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 +#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 +#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 +#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C +#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 +#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 +#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 +#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C +#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 +#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 +#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 +#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C +#define CS35L41_CLOCK_DETECT_1 0x00014000 +#define CS35L41_TIMER1_CONTROL 0x00015000 +#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 +#define CS35L41_TIMER1_START_STOP 0x0001500C +#define CS35L41_TIMER1_STATUS 0x00015010 +#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 +#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 +#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C +#define CS35L41_TIMER2_CONTROL 0x00015100 +#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 +#define CS35L41_TIMER2_START_STOP 0x0001510C +#define CS35L41_TIMER2_STATUS 0x00015110 +#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 +#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 +#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C +#define CS35L41_DFT_JTAG_CONTROL 0x00016000 +#define CS35L41_DIE_STS1 0x00017040 +#define CS35L41_DIE_STS2 0x00017044 +#define CS35L41_TEMP_CAL1 0x00017048 +#define CS35L41_TEMP_CAL2 0x0001704C +#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 +#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 +#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 +#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 +#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 +#define CS35L41_DSP1_SYS_ID 0x025E0000 +#define CS35L41_DSP1_SYS_VERSION 0x025E0004 +#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 +#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C +#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 +#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 +#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 +#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 +#define CS35L41_DSP1_SYS_FEATURES 0x025E002C +#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 +#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 +#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 +#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C +#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 +#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 +#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 +#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 +#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C +#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 +#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 +#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 +#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C +#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 +#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 +#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 +#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C +#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 +#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 +#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 +#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 +#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 +#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 +#define CS35L41_DSP1_CTRL_BASE 0x02B80000 +#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 +#define CS35L41_DSP1_DEBUG 0x02B80040 +#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 +#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 +#define CS35L41_DSP1_RX1_RATE 0x02B80080 +#define CS35L41_DSP1_RX2_RATE 0x02B80088 +#define CS35L41_DSP1_RX3_RATE 0x02B80090 +#define CS35L41_DSP1_RX4_RATE 0x02B80098 +#define CS35L41_DSP1_RX5_RATE 0x02B800A0 +#define CS35L41_DSP1_RX6_RATE 0x02B800A8 +#define CS35L41_DSP1_RX7_RATE 0x02B800B0 +#define CS35L41_DSP1_RX8_RATE 0x02B800B8 +#define CS35L41_DSP1_TX1_RATE 0x02B80280 +#define CS35L41_DSP1_TX2_RATE 0x02B80288 +#define CS35L41_DSP1_TX3_RATE 0x02B80290 +#define CS35L41_DSP1_TX4_RATE 0x02B80298 +#define CS35L41_DSP1_TX5_RATE 0x02B802A0 +#define CS35L41_DSP1_TX6_RATE 0x02B802A8 +#define CS35L41_DSP1_TX7_RATE 0x02B802B0 +#define CS35L41_DSP1_TX8_RATE 0x02B802B8 +#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 +#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 +#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 +#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 +#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 +#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 +#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 +#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 +#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 +#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 +#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 +#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 +#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 +#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 +#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 +#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 +#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 +#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 +#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 +#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 +#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 +#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 +#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 +#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 +#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 +#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 +#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 +#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 +#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 +#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 +#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 +#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 +#define CS35L41_DSP1_SCRATCH1 0x02B805C0 +#define CS35L41_DSP1_SCRATCH2 0x02B805C8 +#define CS35L41_DSP1_SCRATCH3 0x02B805D0 +#define CS35L41_DSP1_SCRATCH4 0x02B805D8 +#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 +#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 +#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 +#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 +#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 +#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 +#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 +#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 +#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 +#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 +#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 +#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 +#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 +#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 +#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 +#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 +#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C +#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 +#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 +#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 +#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C +#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 +#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 +#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 +#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC +#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 +#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 +#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 +#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC +#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 +#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 +#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 +#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC +#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 +#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 +#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 +#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC +#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 +#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 +#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 +#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC +#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 +#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 +#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 +#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC +#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 +#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 +#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 +#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 +#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 +#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C +#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 +#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 +#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C +#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 +#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 +#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C +#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 +#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 +#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 +#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C +#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 +#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 +#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C +#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 +#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 +#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C +#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 +#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 +#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 +#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C +#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 +#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 +#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 +#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 +#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 +#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 +#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 +#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C +#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 +#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 +#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 +#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C +#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 +#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 +#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 +#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C +#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 +#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 +#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 +#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C +#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 +#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 +#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 +#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C +#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 +#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 +#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 +#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C +#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 +#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 +#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 +#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C +#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 +#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 +#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 +#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C +#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 +#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 +#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 +#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 +#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 +#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 +#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 +#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 +#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 +#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C +#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 +#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C +#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 +#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 +#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 +#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 +#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 +#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 +#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 +#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 +#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 +#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 +#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 +#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 +#define CS35L41_DSP1_PMEM_0 0x03800000 +#define CS35L41_DSP1_PMEM_5114 0x03804FE8 + +/*test regs for emulation bringup*/ +#define CS35L41_PLL_OVR 0x00003018 +#define CS35L41_BST_TEST_DUTY 0x00003900 +#define CS35L41_DIGPWM_IOCTRL 0x0000706C + +/*registers populated by OTP*/ +#define CS35L41_OTP_TRIM_1 0x0000208c +#define CS35L41_OTP_TRIM_2 0x00002090 +#define CS35L41_OTP_TRIM_3 0x00003010 +#define CS35L41_OTP_TRIM_4 0x0000300C +#define CS35L41_OTP_TRIM_5 0x0000394C +#define CS35L41_OTP_TRIM_6 0x00003950 +#define CS35L41_OTP_TRIM_7 0x00003954 +#define CS35L41_OTP_TRIM_8 0x00003958 +#define CS35L41_OTP_TRIM_9 0x0000395C +#define CS35L41_OTP_TRIM_10 0x0000416C +#define CS35L41_OTP_TRIM_11 0x00004160 +#define CS35L41_OTP_TRIM_12 0x00004170 +#define CS35L41_OTP_TRIM_13 0x00004360 +#define CS35L41_OTP_TRIM_14 0x00004448 +#define CS35L41_OTP_TRIM_15 0x0000444C +#define CS35L41_OTP_TRIM_16 0x00006E30 +#define CS35L41_OTP_TRIM_17 0x00006E34 +#define CS35L41_OTP_TRIM_18 0x00006E38 +#define CS35L41_OTP_TRIM_19 0x00006E3C +#define CS35L41_OTP_TRIM_20 0x00006E40 +#define CS35L41_OTP_TRIM_21 0x00006E44 +#define CS35L41_OTP_TRIM_22 0x00006E48 +#define CS35L41_OTP_TRIM_23 0x00006E4C +#define CS35L41_OTP_TRIM_24 0x00006E50 +#define CS35L41_OTP_TRIM_25 0x00006E54 +#define CS35L41_OTP_TRIM_26 0x00006E58 +#define CS35L41_OTP_TRIM_27 0x00006E5C +#define CS35L41_OTP_TRIM_28 0x00006E60 +#define CS35L41_OTP_TRIM_29 0x00006E64 +#define CS35L41_OTP_TRIM_30 0x00007418 +#define CS35L41_OTP_TRIM_31 0x0000741C +#define CS35L41_OTP_TRIM_32 0x00007434 +#define CS35L41_OTP_TRIM_33 0x00007068 +#define CS35L41_OTP_TRIM_34 0x0000410C +#define CS35L41_OTP_TRIM_35 0x0000400C +#define CS35L41_OTP_TRIM_36 0x00002030 + +#define CS35L41_MAX_CACHE_REG 36 +#define CS35L41_OTP_SIZE_WORDS 32 +#define CS35L41_NUM_OTP_ELEM 100 +#define CS35L41_NUM_OTP_MAPS 5 + +#define CS35L41_VALID_PDATA 0x80000000 +#define CS35L41_NUM_SUPPLIES 2 + +#define CS35L41_SCLK_MSTR_MASK 0x10 +#define CS35L41_SCLK_MSTR_SHIFT 4 +#define CS35L41_LRCLK_MSTR_MASK 0x01 +#define CS35L41_LRCLK_MSTR_SHIFT 0 +#define CS35L41_SCLK_INV_MASK 0x40 +#define CS35L41_SCLK_INV_SHIFT 6 +#define CS35L41_LRCLK_INV_MASK 0x04 +#define CS35L41_LRCLK_INV_SHIFT 2 +#define CS35L41_SCLK_FRC_MASK 0x20 +#define CS35L41_SCLK_FRC_SHIFT 5 +#define CS35L41_LRCLK_FRC_MASK 0x02 +#define CS35L41_LRCLK_FRC_SHIFT 1 + +#define CS35L41_AMP_GAIN_PCM_MASK 0x3E0 +#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 +#define CS35L41_AMP_GAIN_ZC_SHIFT 10 + +#define CS35L41_BST_CTL_MASK 0xFF +#define CS35L41_BST_CTL_SEL_MASK 0x03 +#define CS35L41_BST_CTL_SEL_REG 0x00 +#define CS35L41_BST_CTL_SEL_CLASSH 0x01 +#define CS35L41_BST_IPK_MASK 0x7F +#define CS35L41_BST_IPK_SHIFT 0 +#define CS35L41_BST_LIM_MASK 0x4 +#define CS35L41_BST_LIM_SHIFT 2 +#define CS35L41_BST_K1_MASK 0x000000FF +#define CS35L41_BST_K1_SHIFT 0 +#define CS35L41_BST_K2_MASK 0x0000FF00 +#define CS35L41_BST_K2_SHIFT 8 +#define CS35L41_BST_SLOPE_MASK 0x0000FF00 +#define CS35L41_BST_SLOPE_SHIFT 8 +#define CS35L41_BST_LBST_VAL_MASK 0x00000003 +#define CS35L41_BST_LBST_VAL_SHIFT 0 + +#define CS35L41_TEMP_THLD_MASK 0x03 +#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF +#define CS35L41_PDM_MODE_MASK 0x01 +#define CS35L41_PDM_MODE_SHIFT 0 + +#define CS35L41_CH_MEM_DEPTH_MASK 0x07 +#define CS35L41_CH_MEM_DEPTH_SHIFT 0 +#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 +#define CS35L41_CH_HDRM_CTL_SHIFT 16 +#define CS35L41_CH_REL_RATE_MASK 0xFF00 +#define CS35L41_CH_REL_RATE_SHIFT 8 +#define CS35L41_CH_WKFET_DLY_MASK 0x001C +#define CS35L41_CH_WKFET_DLY_SHIFT 2 +#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 +#define CS35L41_CH_WKFET_THLD_SHIFT 8 + +#define CS35L41_HW_NG_SEL_MASK 0x3F00 +#define CS35L41_HW_NG_SEL_SHIFT 8 +#define CS35L41_HW_NG_DLY_MASK 0x0070 +#define CS35L41_HW_NG_DLY_SHIFT 4 +#define CS35L41_HW_NG_THLD_MASK 0x0007 +#define CS35L41_HW_NG_THLD_SHIFT 0 + +#define CS35L41_DSP_NG_ENABLE_MASK 0x00010000 +#define CS35L41_DSP_NG_ENABLE_SHIFT 16 +#define CS35L41_DSP_NG_THLD_MASK 0x7 +#define CS35L41_DSP_NG_THLD_SHIFT 0 +#define CS35L41_DSP_NG_DELAY_MASK 0x0F00 +#define CS35L41_DSP_NG_DELAY_SHIFT 8 + +#define CS35L41_ASP_FMT_MASK 0x0700 +#define CS35L41_ASP_FMT_SHIFT 8 +#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 +#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 +#define CS35L41_ASP_WIDTH_16 0x10 +#define CS35L41_ASP_WIDTH_24 0x18 +#define CS35L41_ASP_WIDTH_32 0x20 +#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 +#define CS35L41_ASP_WIDTH_TX_SHIFT 16 +#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 +#define CS35L41_ASP_WIDTH_RX_SHIFT 24 +#define CS35L41_ASP_RX1_SLOT_MASK 0x3F +#define CS35L41_ASP_RX1_SLOT_SHIFT 0 +#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 +#define CS35L41_ASP_RX2_SLOT_SHIFT 8 +#define CS35L41_ASP_RX_WL_MASK 0x3F +#define CS35L41_ASP_TX_WL_MASK 0x3F +#define CS35L41_ASP_RX_WL_SHIFT 0 +#define CS35L41_ASP_TX_WL_SHIFT 0 +#define CS35L41_ASP_SOURCE_MASK 0x7F + +#define CS35L41_INPUT_SRC_ASPRX1 0x08 +#define CS35L41_INPUT_SRC_ASPRX2 0x09 +#define CS35L41_INPUT_SRC_VMON 0x18 +#define CS35L41_INPUT_SRC_IMON 0x19 +#define CS35L41_INPUT_SRC_CLASSH 0x21 +#define CS35L41_INPUT_SRC_VPMON 0x28 +#define CS35L41_INPUT_SRC_VBSTMON 0x29 +#define CS35L41_INPUT_SRC_TEMPMON 0x3A +#define CS35L41_INPUT_SRC_RSVD 0x3B +#define CS35L41_INPUT_DSP_TX1 0x32 +#define CS35L41_INPUT_DSP_TX2 0x33 + +#define CS35L41_PLL_CLK_SEL_MASK 0x07 +#define CS35L41_PLL_CLK_SEL_SHIFT 0 +#define CS35L41_PLL_CLK_EN_MASK 0x10 +#define CS35L41_PLL_CLK_EN_SHIFT 4 +#define CS35L41_PLL_OPENLOOP_MASK 0x0800 +#define CS35L41_PLL_OPENLOOP_SHIFT 11 +#define CS35L41_PLLSRC_SCLK 0 +#define CS35L41_PLLSRC_LRCLK 1 +#define CS35L41_PLLSRC_SELF 3 +#define CS35L41_PLLSRC_PDMCLK 4 +#define CS35L41_PLLSRC_MCLK 5 +#define CS35L41_PLLSRC_SWIRE 7 +#define CS35L41_REFCLK_FREQ_MASK 0x7E0 +#define CS35L41_REFCLK_FREQ_SHIFT 5 + +#define CS35L41_GLOBAL_FS_MASK 0x1F +#define CS35L41_GLOBAL_FS_SHIFT 0 + +#define CS35L41_GLOBAL_EN_MASK 0x01 +#define CS35L41_GLOBAL_EN_SHIFT 0 +#define CS35L41_BST_EN_MASK 0x0030 +#define CS35L41_BST_EN_SHIFT 4 +#define CS35L41_BST_EN_DEFAULT 0x2 +#define CS35L41_AMP_EN_SHIFT 0 +#define CS35L41_AMP_EN_MASK 1 + +#define CS35L41_PDN_DONE_MASK 0x00800000 +#define CS35L41_PDN_DONE_SHIFT 23 +#define CS35L41_PUP_DONE_MASK 0x01000000 +#define CS35L41_PUP_DONE_SHIFT 24 + +#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F +#define CS35L36_PUP_DONE_IRQ_MASK 0xBF + +#define CS35L41_AMP_SHORT_ERR 0x80000000 +#define CS35L41_BST_SHORT_ERR 0x0100 +#define CS35L41_TEMP_WARN 0x8000 +#define CS35L41_TEMP_ERR 0x00020000 +#define CS35L41_BST_OVP_ERR 0x40 +#define CS35L41_BST_DCM_UVP_ERR 0x80 +#define CS35L41_OTP_BOOT_DONE 0x02 +#define CS35L41_PLL_UNLOCK 0x10 +#define CS35L41_OTP_BOOT_ERR 0x80000000 + +#define CS35L41_AMP_SHORT_ERR_RLS 0x02 +#define CS35L41_BST_SHORT_ERR_RLS 0x04 +#define CS35L41_BST_OVP_ERR_RLS 0x08 +#define CS35L41_BST_UVP_ERR_RLS 0x10 +#define CS35L41_TEMP_WARN_ERR_RLS 0x20 +#define CS35L41_TEMP_ERR_RLS 0x40 + +#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F +#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF +#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF + +#define CS35L41_GPIO_DIR_MASK 0x80000000 +#define CS35L41_GPIO_DIR_SHIFT 31 +#define CS35L41_GPIO1_CTRL_MASK 0x00030000 +#define CS35L41_GPIO1_CTRL_SHIFT 16 +#define CS35L41_GPIO2_CTRL_MASK 0x07000000 +#define CS35L41_GPIO2_CTRL_SHIFT 24 +#define CS35L41_GPIO_CTRL_OPEN_INT 2 +#define CS35L41_GPIO_CTRL_ACTV_LO 4 +#define CS35L41_GPIO_CTRL_ACTV_HI 5 +#define CS35L41_GPIO_POL_MASK 0x1000 +#define CS35L41_GPIO_POL_SHIFT 12 + +#define CS35L41_AMP_INV_PCM_SHIFT 14 +#define CS35L41_AMP_INV_PCM_MASK BIT(CS35L41_AMP_INV_PCM_SHIFT) +#define CS35L41_AMP_PCM_VOL_SHIFT 3 +#define CS35L41_AMP_PCM_VOL_MASK (0x7FF << 3) +#define CS35L41_AMP_PCM_VOL_MUTE 0x4CF + +#define CS35L41_CHIP_ID 0x35a40 +#define CS35L41R_CHIP_ID 0x35b40 +#define CS35L41_MTLREVID_MASK 0x0F +#define CS35L41_REVID_A0 0xA0 +#define CS35L41_REVID_B0 0xB0 +#define CS35L41_REVID_B2 0xB2 + +#define CS35L41_HALO_CORE_RESET 0x00000200 + +#define CS35L41_FS1_WINDOW_MASK 0x000007FF +#define CS35L41_FS2_WINDOW_MASK 0x00FFF800 +#define CS35L41_FS2_WINDOW_SHIFT 12 + +#define CS35L41_SPI_MAX_FREQ_OTP 4000000 + +#define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) +#define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg); +bool cs35l41_precious_reg(struct device *dev, unsigned int reg); +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg); + +struct cs35l41_otp_packed_element_t { + u32 reg; + u8 shift; + u8 size; +}; + +struct cs35l41_otp_map_element_t { + u32 id; + u32 num_elements; + const struct cs35l41_otp_packed_element_t *map; + u32 bit_offset; + u32 word_offset; +}; + +extern const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG]; +extern const struct cs35l41_otp_map_element_t + cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; + +#define CS35L41_REGSTRIDE 4 + +struct cs35l41_private { + struct snd_soc_codec *codec; + struct cs35l41_platform_data pdata; + struct device *dev; + struct regmap *regmap; + struct regulator_bulk_data supplies[CS35L41_NUM_SUPPLIES]; + int irq; + /* GPIO for /RST */ + struct gpio_desc *reset_gpio; + void (*otp_setup)(struct cs35l41_private *cs35l41, bool is_pre_setup, + unsigned int *freq); +}; + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata); +int cs35l41_remove(struct cs35l41_private *cs35l41); + +#endif /*__CS35L41_H__*/ diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index fb1e4c33e27d34..d484ec09eb2ebb 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -851,7 +851,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, if (params_width(params) == 24) cs42l42->bclk = (cs42l42->bclk / 3) * 4; - switch(substream->stream) { + switch (substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: if (channels == 2) { val |= CS42L42_ASP_TX_CH2_AP_MASK; @@ -935,7 +935,7 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) CS42L42_HP_ANA_BMUTE_MASK); cs42l42->stream_use &= ~(1 << stream); - if(!cs42l42->stream_use) { + if (!cs42l42->stream_use) { /* * Switch to the internal oscillator. * SCLK must remain running until after this clock switch. @@ -1015,7 +1015,7 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) #define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S32_LE ) + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops cs42l42_ops = { .startup = cs42l42_dai_startup, @@ -1046,11 +1046,121 @@ static struct snd_soc_dai_driver cs42l42_dai = { .ops = &cs42l42_ops, }; +static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) +{ + unsigned int hs_det_status; + unsigned int hs_det_comp1; + unsigned int hs_det_comp2; + unsigned int hs_det_sw; + + /* Set hs detect to manual, active mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (1 << CS42L42_HSDET_CTRL_SHIFT) | + (0 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (0 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + /* Configure HS DET comparator reference levels. */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL1, + CS42L42_HSDET_COMP1_LVL_MASK | + CS42L42_HSDET_COMP2_LVL_MASK, + (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT) | + (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT)); + + /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */ + regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP1); + + msleep(100); + + regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + + hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >> + CS42L42_HSDET_COMP1_OUT_SHIFT; + hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >> + CS42L42_HSDET_COMP2_OUT_SHIFT; + + /* Close the SW_HSB_HS3 switch for a Type 2 headset. */ + regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP2); + + msleep(100); + + regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + + hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >> + CS42L42_HSDET_COMP1_OUT_SHIFT) << 1; + hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >> + CS42L42_HSDET_COMP2_OUT_SHIFT) << 1; + + /* Use Comparator 1 with 1.25V Threshold. */ + switch (hs_det_comp1) { + case CS42L42_HSDET_COMP_TYPE1: + cs42l42->hs_type = CS42L42_PLUG_CTIA; + hs_det_sw = CS42L42_HSDET_SW_TYPE1; + break; + case CS42L42_HSDET_COMP_TYPE2: + cs42l42->hs_type = CS42L42_PLUG_OMTP; + hs_det_sw = CS42L42_HSDET_SW_TYPE2; + break; + default: + /* Fallback to Comparator 2 with 1.75V Threshold. */ + switch (hs_det_comp2) { + case CS42L42_HSDET_COMP_TYPE1: + cs42l42->hs_type = CS42L42_PLUG_CTIA; + hs_det_sw = CS42L42_HSDET_SW_TYPE1; + break; + case CS42L42_HSDET_COMP_TYPE2: + cs42l42->hs_type = CS42L42_PLUG_OMTP; + hs_det_sw = CS42L42_HSDET_SW_TYPE2; + break; + case CS42L42_HSDET_COMP_TYPE3: + cs42l42->hs_type = CS42L42_PLUG_HEADPHONE; + hs_det_sw = CS42L42_HSDET_SW_TYPE3; + break; + default: + cs42l42->hs_type = CS42L42_PLUG_INVALID; + hs_det_sw = CS42L42_HSDET_SW_TYPE4; + break; + } + } + + /* Set Switches */ + regmap_write(cs42l42->regmap, CS42L42_HS_SWITCH_CTL, hs_det_sw); + + /* Set HSDET mode to Manual—Disabled */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (0 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (0 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + /* Configure HS DET comparator reference levels. */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL1, + CS42L42_HSDET_COMP1_LVL_MASK | + CS42L42_HSDET_COMP2_LVL_MASK, + (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT) | + (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT)); +} + static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) { unsigned int hs_det_status; unsigned int int_status; + /* Read and save the hs detection result */ + regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + /* Mask the auto detect interrupt */ regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, @@ -1059,6 +1169,10 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) (1 << CS42L42_PDN_DONE_SHIFT) | (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> + CS42L42_HSDET_TYPE_SHIFT; + /* Set hs detect to automatic, disabled mode */ regmap_update_bits(cs42l42->regmap, CS42L42_HSDET_CTL2, @@ -1071,11 +1185,15 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) (0 << CS42L42_HSBIAS_REF_SHIFT) | (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); - /* Read and save the hs detection result */ - regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); - - cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> - CS42L42_HSDET_TYPE_SHIFT; + /* Run Manual detection if auto detect has not found a headset. + * We Re-Run with Manual Detection if the original detection was invalid or headphones, + * to ensure that a headset mic is detected in all cases. + */ + if (cs42l42->hs_type == CS42L42_PLUG_INVALID || + cs42l42->hs_type == CS42L42_PLUG_HEADPHONE) { + dev_dbg(cs42l42->component->dev, "Running Manual Detection Fallback\n"); + cs42l42_manual_hs_type_detect(cs42l42); + } /* Set up button detection */ if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) || @@ -1492,7 +1610,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); - switch(cs42l42->hs_type){ + switch (cs42l42->hs_type) { case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADSET, @@ -1524,7 +1642,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) cs42l42->plug_state = CS42L42_TS_UNPLUG; cs42l42_cancel_hs_type_detect(cs42l42); - switch(cs42l42->hs_type){ + switch (cs42l42->hs_type) { case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADSET); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 8734f6828f3ede..0704c902475fb0 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -188,6 +188,11 @@ #define CS42L42_HSDET_COMP2_LVL_SHIFT 4 #define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT) +#define CS42L42_HSDET_COMP1_LVL_VAL 12 /* 1.25V Comparator */ +#define CS42L42_HSDET_COMP2_LVL_VAL 2 /* 1.75V Comparator */ +#define CS42L42_HSDET_COMP1_LVL_DEFAULT 7 /* 1V Comparator */ +#define CS42L42_HSDET_COMP2_LVL_DEFAULT 7 /* 2V Comparator */ + #define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20) #define CS42L42_HSDET_AUTO_TIME_SHIFT 0 #define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT) @@ -228,6 +233,60 @@ #define CS42L42_PLUG_HEADPHONE 2 #define CS42L42_PLUG_INVALID 3 +#define CS42L42_HSDET_SW_COMP1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (0 << CS42L42_SW_REF_HS4_SHIFT) | \ + (1 << CS42L42_SW_REF_HS3_SHIFT)) +#define CS42L42_HSDET_SW_COMP2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (1 << CS42L42_SW_REF_HS4_SHIFT) | \ + (0 << CS42L42_SW_REF_HS3_SHIFT)) +#define CS42L42_HSDET_SW_TYPE1 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (0 << CS42L42_SW_REF_HS4_SHIFT) | \ + (1 << CS42L42_SW_REF_HS3_SHIFT)) +#define CS42L42_HSDET_SW_TYPE2 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (0 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (1 << CS42L42_SW_REF_HS4_SHIFT) | \ + (0 << CS42L42_SW_REF_HS3_SHIFT)) +#define CS42L42_HSDET_SW_TYPE3 ((1 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (1 << CS42L42_SW_REF_HS4_SHIFT) | \ + (1 << CS42L42_SW_REF_HS3_SHIFT)) +#define CS42L42_HSDET_SW_TYPE4 ((0 << CS42L42_SW_GNDHS_HS4_SHIFT) | \ + (1 << CS42L42_SW_GNDHS_HS3_SHIFT) | \ + (1 << CS42L42_SW_HSB_HS4_SHIFT) | \ + (0 << CS42L42_SW_HSB_HS3_SHIFT) | \ + (0 << CS42L42_SW_HSB_FILT_HS4_SHIFT) | \ + (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) | \ + (0 << CS42L42_SW_REF_HS4_SHIFT) | \ + (1 << CS42L42_SW_REF_HS3_SHIFT)) + +#define CS42L42_HSDET_COMP_TYPE1 1 +#define CS42L42_HSDET_COMP_TYPE2 2 +#define CS42L42_HSDET_COMP_TYPE3 0 +#define CS42L42_HSDET_COMP_TYPE4 3 + #define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29) #define CS42L42_HS_CLAMP_DISABLE_SHIFT 0 #define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index 1ee83160b83fb7..391fd7da331fd2 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -45,7 +45,7 @@ struct cs47l15 { bool in1_lp_mode; }; -static const struct wm_adsp_region cs47l15_dsp1_regions[] = { +static const struct cs_dsp_region cs47l15_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x080000 }, { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, @@ -1402,18 +1402,18 @@ static int cs47l15_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); cs47l15->core.adsp[0].part = "cs47l15"; - cs47l15->core.adsp[0].num = 1; - cs47l15->core.adsp[0].type = WMFW_ADSP2; - cs47l15->core.adsp[0].rev = 2; - cs47l15->core.adsp[0].dev = madera->dev; - cs47l15->core.adsp[0].regmap = madera->regmap_32bit; - - cs47l15->core.adsp[0].base = MADERA_DSP1_CONFIG_1; - cs47l15->core.adsp[0].mem = cs47l15_dsp1_regions; - cs47l15->core.adsp[0].num_mems = ARRAY_SIZE(cs47l15_dsp1_regions); - - cs47l15->core.adsp[0].lock_regions = - WM_ADSP2_REGION_1 | WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3; + cs47l15->core.adsp[0].cs_dsp.num = 1; + cs47l15->core.adsp[0].cs_dsp.type = WMFW_ADSP2; + cs47l15->core.adsp[0].cs_dsp.rev = 2; + cs47l15->core.adsp[0].cs_dsp.dev = madera->dev; + cs47l15->core.adsp[0].cs_dsp.regmap = madera->regmap_32bit; + + cs47l15->core.adsp[0].cs_dsp.base = MADERA_DSP1_CONFIG_1; + cs47l15->core.adsp[0].cs_dsp.mem = cs47l15_dsp1_regions; + cs47l15->core.adsp[0].cs_dsp.num_mems = ARRAY_SIZE(cs47l15_dsp1_regions); + + cs47l15->core.adsp[0].cs_dsp.lock_regions = + CS_ADSP2_REGION_1 | CS_ADSP2_REGION_2 | CS_ADSP2_REGION_3; ret = wm_adsp2_init(&cs47l15->core.adsp[0]); if (ret != 0) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 6b6d088160241d..6356f81aafc563 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -37,21 +37,21 @@ struct cs47l24_priv { struct arizona_fll fll[2]; }; -static const struct wm_adsp_region cs47l24_dsp2_regions[] = { +static const struct cs_dsp_region cs47l24_dsp2_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x200000 }, { .type = WMFW_ADSP2_ZM, .base = 0x280000 }, { .type = WMFW_ADSP2_XM, .base = 0x290000 }, { .type = WMFW_ADSP2_YM, .base = 0x2a8000 }, }; -static const struct wm_adsp_region cs47l24_dsp3_regions[] = { +static const struct cs_dsp_region cs47l24_dsp3_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x300000 }, { .type = WMFW_ADSP2_ZM, .base = 0x380000 }, { .type = WMFW_ADSP2_XM, .base = 0x390000 }, { .type = WMFW_ADSP2_YM, .base = 0x3a8000 }, }; -static const struct wm_adsp_region *cs47l24_dsp_regions[] = { +static const struct cs_dsp_region *cs47l24_dsp_regions[] = { cs47l24_dsp2_regions, cs47l24_dsp3_regions, }; @@ -1234,15 +1234,15 @@ static int cs47l24_probe(struct platform_device *pdev) for (i = 1; i <= 2; i++) { cs47l24->core.adsp[i].part = "cs47l24"; - cs47l24->core.adsp[i].num = i + 1; - cs47l24->core.adsp[i].type = WMFW_ADSP2; - cs47l24->core.adsp[i].dev = arizona->dev; - cs47l24->core.adsp[i].regmap = arizona->regmap; + cs47l24->core.adsp[i].cs_dsp.num = i + 1; + cs47l24->core.adsp[i].cs_dsp.type = WMFW_ADSP2; + cs47l24->core.adsp[i].cs_dsp.dev = arizona->dev; + cs47l24->core.adsp[i].cs_dsp.regmap = arizona->regmap; - cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 + + cs47l24->core.adsp[i].cs_dsp.base = ARIZONA_DSP1_CONTROL_1 + (0x100 * i); - cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1]; - cs47l24->core.adsp[i].num_mems = + cs47l24->core.adsp[i].cs_dsp.mem = cs47l24_dsp_regions[i - 1]; + cs47l24->core.adsp[i].cs_dsp.num_mems = ARRAY_SIZE(cs47l24_dsp2_regions); ret = wm_adsp2_init(&cs47l24->core.adsp[i]); diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index 3f04a2a7452178..db2f844b8b17f1 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -37,28 +37,28 @@ struct cs47l35 { struct madera_fll fll; }; -static const struct wm_adsp_region cs47l35_dsp1_regions[] = { +static const struct cs_dsp_region cs47l35_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x080000 }, { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, }; -static const struct wm_adsp_region cs47l35_dsp2_regions[] = { +static const struct cs_dsp_region cs47l35_dsp2_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, { .type = WMFW_ADSP2_ZM, .base = 0x160000 }, { .type = WMFW_ADSP2_XM, .base = 0x120000 }, { .type = WMFW_ADSP2_YM, .base = 0x140000 }, }; -static const struct wm_adsp_region cs47l35_dsp3_regions[] = { +static const struct cs_dsp_region cs47l35_dsp3_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x180000 }, { .type = WMFW_ADSP2_ZM, .base = 0x1e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x1a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x1c0000 }, }; -static const struct wm_adsp_region *cs47l35_dsp_regions[] = { +static const struct cs_dsp_region *cs47l35_dsp_regions[] = { cs47l35_dsp1_regions, cs47l35_dsp2_regions, cs47l35_dsp3_regions, @@ -1686,15 +1686,15 @@ static int cs47l35_probe(struct platform_device *pdev) for (i = 0; i < CS47L35_NUM_ADSP; i++) { cs47l35->core.adsp[i].part = "cs47l35"; - cs47l35->core.adsp[i].num = i + 1; - cs47l35->core.adsp[i].type = WMFW_ADSP2; - cs47l35->core.adsp[i].rev = 1; - cs47l35->core.adsp[i].dev = madera->dev; - cs47l35->core.adsp[i].regmap = madera->regmap_32bit; - - cs47l35->core.adsp[i].base = wm_adsp2_control_bases[i]; - cs47l35->core.adsp[i].mem = cs47l35_dsp_regions[i]; - cs47l35->core.adsp[i].num_mems = + cs47l35->core.adsp[i].cs_dsp.num = i + 1; + cs47l35->core.adsp[i].cs_dsp.type = WMFW_ADSP2; + cs47l35->core.adsp[i].cs_dsp.rev = 1; + cs47l35->core.adsp[i].cs_dsp.dev = madera->dev; + cs47l35->core.adsp[i].cs_dsp.regmap = madera->regmap_32bit; + + cs47l35->core.adsp[i].cs_dsp.base = wm_adsp2_control_bases[i]; + cs47l35->core.adsp[i].cs_dsp.mem = cs47l35_dsp_regions[i]; + cs47l35->core.adsp[i].cs_dsp.num_mems = ARRAY_SIZE(cs47l35_dsp1_regions); ret = wm_adsp2_init(&cs47l35->core.adsp[i]); diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index 748a180870bc83..d4fedc5ad516eb 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -37,56 +37,56 @@ struct cs47l85 { struct madera_fll fll[3]; }; -static const struct wm_adsp_region cs47l85_dsp1_regions[] = { +static const struct cs_dsp_region cs47l85_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x080000 }, { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, }; -static const struct wm_adsp_region cs47l85_dsp2_regions[] = { +static const struct cs_dsp_region cs47l85_dsp2_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, { .type = WMFW_ADSP2_ZM, .base = 0x160000 }, { .type = WMFW_ADSP2_XM, .base = 0x120000 }, { .type = WMFW_ADSP2_YM, .base = 0x140000 }, }; -static const struct wm_adsp_region cs47l85_dsp3_regions[] = { +static const struct cs_dsp_region cs47l85_dsp3_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x180000 }, { .type = WMFW_ADSP2_ZM, .base = 0x1e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x1a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x1c0000 }, }; -static const struct wm_adsp_region cs47l85_dsp4_regions[] = { +static const struct cs_dsp_region cs47l85_dsp4_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x200000 }, { .type = WMFW_ADSP2_ZM, .base = 0x260000 }, { .type = WMFW_ADSP2_XM, .base = 0x220000 }, { .type = WMFW_ADSP2_YM, .base = 0x240000 }, }; -static const struct wm_adsp_region cs47l85_dsp5_regions[] = { +static const struct cs_dsp_region cs47l85_dsp5_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x280000 }, { .type = WMFW_ADSP2_ZM, .base = 0x2e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x2a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x2c0000 }, }; -static const struct wm_adsp_region cs47l85_dsp6_regions[] = { +static const struct cs_dsp_region cs47l85_dsp6_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x300000 }, { .type = WMFW_ADSP2_ZM, .base = 0x360000 }, { .type = WMFW_ADSP2_XM, .base = 0x320000 }, { .type = WMFW_ADSP2_YM, .base = 0x340000 }, }; -static const struct wm_adsp_region cs47l85_dsp7_regions[] = { +static const struct cs_dsp_region cs47l85_dsp7_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x380000 }, { .type = WMFW_ADSP2_ZM, .base = 0x3e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x3a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x3c0000 }, }; -static const struct wm_adsp_region *cs47l85_dsp_regions[] = { +static const struct cs_dsp_region *cs47l85_dsp_regions[] = { cs47l85_dsp1_regions, cs47l85_dsp2_regions, cs47l85_dsp3_regions, @@ -2632,15 +2632,15 @@ static int cs47l85_probe(struct platform_device *pdev) for (i = 0; i < CS47L85_NUM_ADSP; i++) { cs47l85->core.adsp[i].part = "cs47l85"; - cs47l85->core.adsp[i].num = i + 1; - cs47l85->core.adsp[i].type = WMFW_ADSP2; - cs47l85->core.adsp[i].rev = 1; - cs47l85->core.adsp[i].dev = madera->dev; - cs47l85->core.adsp[i].regmap = madera->regmap_32bit; - - cs47l85->core.adsp[i].base = wm_adsp2_control_bases[i]; - cs47l85->core.adsp[i].mem = cs47l85_dsp_regions[i]; - cs47l85->core.adsp[i].num_mems = + cs47l85->core.adsp[i].cs_dsp.num = i + 1; + cs47l85->core.adsp[i].cs_dsp.type = WMFW_ADSP2; + cs47l85->core.adsp[i].cs_dsp.rev = 1; + cs47l85->core.adsp[i].cs_dsp.dev = madera->dev; + cs47l85->core.adsp[i].cs_dsp.regmap = madera->regmap_32bit; + + cs47l85->core.adsp[i].cs_dsp.base = wm_adsp2_control_bases[i]; + cs47l85->core.adsp[i].cs_dsp.mem = cs47l85_dsp_regions[i]; + cs47l85->core.adsp[i].cs_dsp.num_mems = ARRAY_SIZE(cs47l85_dsp1_regions); ret = wm_adsp2_init(&cs47l85->core.adsp[i]); diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index d2911c014b863e..5aec937a246298 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -37,56 +37,56 @@ struct cs47l90 { struct madera_fll fll[3]; }; -static const struct wm_adsp_region cs47l90_dsp1_regions[] = { +static const struct cs_dsp_region cs47l90_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x080000 }, { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, }; -static const struct wm_adsp_region cs47l90_dsp2_regions[] = { +static const struct cs_dsp_region cs47l90_dsp2_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, { .type = WMFW_ADSP2_ZM, .base = 0x160000 }, { .type = WMFW_ADSP2_XM, .base = 0x120000 }, { .type = WMFW_ADSP2_YM, .base = 0x140000 }, }; -static const struct wm_adsp_region cs47l90_dsp3_regions[] = { +static const struct cs_dsp_region cs47l90_dsp3_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x180000 }, { .type = WMFW_ADSP2_ZM, .base = 0x1e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x1a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x1c0000 }, }; -static const struct wm_adsp_region cs47l90_dsp4_regions[] = { +static const struct cs_dsp_region cs47l90_dsp4_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x200000 }, { .type = WMFW_ADSP2_ZM, .base = 0x260000 }, { .type = WMFW_ADSP2_XM, .base = 0x220000 }, { .type = WMFW_ADSP2_YM, .base = 0x240000 }, }; -static const struct wm_adsp_region cs47l90_dsp5_regions[] = { +static const struct cs_dsp_region cs47l90_dsp5_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x280000 }, { .type = WMFW_ADSP2_ZM, .base = 0x2e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x2a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x2c0000 }, }; -static const struct wm_adsp_region cs47l90_dsp6_regions[] = { +static const struct cs_dsp_region cs47l90_dsp6_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x300000 }, { .type = WMFW_ADSP2_ZM, .base = 0x360000 }, { .type = WMFW_ADSP2_XM, .base = 0x320000 }, { .type = WMFW_ADSP2_YM, .base = 0x340000 }, }; -static const struct wm_adsp_region cs47l90_dsp7_regions[] = { +static const struct cs_dsp_region cs47l90_dsp7_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x380000 }, { .type = WMFW_ADSP2_ZM, .base = 0x3e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x3a0000 }, { .type = WMFW_ADSP2_YM, .base = 0x3c0000 }, }; -static const struct wm_adsp_region *cs47l90_dsp_regions[] = { +static const struct cs_dsp_region *cs47l90_dsp_regions[] = { cs47l90_dsp1_regions, cs47l90_dsp2_regions, cs47l90_dsp3_regions, @@ -2543,18 +2543,18 @@ static int cs47l90_probe(struct platform_device *pdev) for (i = 0; i < CS47L90_NUM_ADSP; i++) { cs47l90->core.adsp[i].part = "cs47l90"; - cs47l90->core.adsp[i].num = i + 1; - cs47l90->core.adsp[i].type = WMFW_ADSP2; - cs47l90->core.adsp[i].rev = 2; - cs47l90->core.adsp[i].dev = madera->dev; - cs47l90->core.adsp[i].regmap = madera->regmap_32bit; - - cs47l90->core.adsp[i].base = cs47l90_dsp_control_bases[i]; - cs47l90->core.adsp[i].mem = cs47l90_dsp_regions[i]; - cs47l90->core.adsp[i].num_mems = + cs47l90->core.adsp[i].cs_dsp.num = i + 1; + cs47l90->core.adsp[i].cs_dsp.type = WMFW_ADSP2; + cs47l90->core.adsp[i].cs_dsp.rev = 2; + cs47l90->core.adsp[i].cs_dsp.dev = madera->dev; + cs47l90->core.adsp[i].cs_dsp.regmap = madera->regmap_32bit; + + cs47l90->core.adsp[i].cs_dsp.base = cs47l90_dsp_control_bases[i]; + cs47l90->core.adsp[i].cs_dsp.mem = cs47l90_dsp_regions[i]; + cs47l90->core.adsp[i].cs_dsp.num_mems = ARRAY_SIZE(cs47l90_dsp1_regions); - cs47l90->core.adsp[i].lock_regions = WM_ADSP2_REGION_1_9; + cs47l90->core.adsp[i].cs_dsp.lock_regions = CS_ADSP2_REGION_1_9; ret = wm_adsp2_init(&cs47l90->core.adsp[i]); diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 1a0280416d92a7..a1b8dcdb9f7b76 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -37,7 +37,7 @@ struct cs47l92 { struct madera_fll fll[2]; }; -static const struct wm_adsp_region cs47l92_dsp1_regions[] = { +static const struct cs_dsp_region cs47l92_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x080000 }, { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, @@ -2002,17 +2002,17 @@ static int cs47l92_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); cs47l92->core.adsp[0].part = "cs47l92"; - cs47l92->core.adsp[0].num = 1; - cs47l92->core.adsp[0].type = WMFW_ADSP2; - cs47l92->core.adsp[0].rev = 2; - cs47l92->core.adsp[0].dev = madera->dev; - cs47l92->core.adsp[0].regmap = madera->regmap_32bit; + cs47l92->core.adsp[0].cs_dsp.num = 1; + cs47l92->core.adsp[0].cs_dsp.type = WMFW_ADSP2; + cs47l92->core.adsp[0].cs_dsp.rev = 2; + cs47l92->core.adsp[0].cs_dsp.dev = madera->dev; + cs47l92->core.adsp[0].cs_dsp.regmap = madera->regmap_32bit; - cs47l92->core.adsp[0].base = MADERA_DSP1_CONFIG_1; - cs47l92->core.adsp[0].mem = cs47l92_dsp1_regions; - cs47l92->core.adsp[0].num_mems = ARRAY_SIZE(cs47l92_dsp1_regions); + cs47l92->core.adsp[0].cs_dsp.base = MADERA_DSP1_CONFIG_1; + cs47l92->core.adsp[0].cs_dsp.mem = cs47l92_dsp1_regions; + cs47l92->core.adsp[0].cs_dsp.num_mems = ARRAY_SIZE(cs47l92_dsp1_regions); - cs47l92->core.adsp[0].lock_regions = WM_ADSP2_REGION_1_9; + cs47l92->core.adsp[0].cs_dsp.lock_regions = CS_ADSP2_REGION_1_9; ret = wm_adsp2_init(&cs47l92->core.adsp[0]); if (ret != 0) diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index f4ed7e04673fd3..272041c6236a99 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -905,7 +905,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, */ mutex_lock(&priv->rate_lock); - if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].base)) { + if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) { dev_warn(priv->madera->dev, "Cannot change '%s' while in use by active audio paths\n", kcontrol->id.name); @@ -964,7 +964,7 @@ static int madera_write_adsp_clk_setting(struct madera_priv *priv, unsigned int mask = MADERA_DSP_RATE_MASK; int ret; - val = priv->adsp_rate_cache[dsp->num - 1] << MADERA_DSP_RATE_SHIFT; + val = priv->adsp_rate_cache[dsp->cs_dsp.num - 1] << MADERA_DSP_RATE_SHIFT; switch (priv->madera->type) { case CS47L35: @@ -978,15 +978,15 @@ static int madera_write_adsp_clk_setting(struct madera_priv *priv, /* Configure exact dsp frequency */ dev_dbg(priv->madera->dev, "Set DSP frequency to 0x%x\n", freq); - ret = regmap_write(dsp->regmap, - dsp->base + MADERA_DSP_CONFIG_2_OFFS, freq); + ret = regmap_write(dsp->cs_dsp.regmap, + dsp->cs_dsp.base + MADERA_DSP_CONFIG_2_OFFS, freq); if (ret) goto err; break; } - ret = regmap_update_bits(dsp->regmap, - dsp->base + MADERA_DSP_CONFIG_1_OFFS, + ret = regmap_update_bits(dsp->cs_dsp.regmap, + dsp->cs_dsp.base + MADERA_DSP_CONFIG_1_OFFS, mask, val); if (ret) goto err; @@ -996,7 +996,7 @@ static int madera_write_adsp_clk_setting(struct madera_priv *priv, return 0; err: - dev_err(dsp->dev, "Failed to set DSP%d clock: %d\n", dsp->num, ret); + dev_err(dsp->cs_dsp.dev, "Failed to set DSP%d clock: %d\n", dsp->cs_dsp.num, ret); return ret; } @@ -1018,7 +1018,7 @@ int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num, * changes are locked out by the domain_group_ref reference count. */ - ret = regmap_read(dsp->regmap, dsp->base, &cur); + ret = regmap_read(dsp->cs_dsp.regmap, dsp->cs_dsp.base, &cur); if (ret) { dev_err(madera->dev, "Failed to read current DSP rate: %d\n", ret); @@ -1027,7 +1027,7 @@ int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num, cur &= MADERA_DSP_RATE_MASK; - new = priv->adsp_rate_cache[dsp->num - 1] << MADERA_DSP_RATE_SHIFT; + new = priv->adsp_rate_cache[dsp->cs_dsp.num - 1] << MADERA_DSP_RATE_SHIFT; if (new == cur) { dev_dbg(madera->dev, "DSP rate not changed\n"); diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index b392567c2b3e68..d1882cbc9381de 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -1021,7 +1021,7 @@ static int max98390_i2c_probe(struct i2c_client *i2c, int reg = 0; struct max98390_priv *max98390 = NULL; - struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent); + struct i2c_adapter *adapter = i2c->adapter; ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index 2d6a4a29b85070..f8532aa7e4aa03 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -2697,7 +2697,7 @@ static int mt6359_codec_probe(struct snd_soc_component *cmpnt) static void mt6359_codec_remove(struct snd_soc_component *cmpnt) { - snd_soc_component_exit_regmap(cmpnt); + cmpnt->regmap = NULL; } static const DECLARE_TLV_DB_SCALE(hp_playback_tlv, -2200, 100, 0); diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index b8cfc250612c81..f39f98bbc97fdc 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -17,7 +17,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = { .playback = { .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_8000_384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index faff2b558687d5..508597866dffa6 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1311,6 +1311,57 @@ static int rt1011_r0_load_info(struct snd_kcontrol *kcontrol, .put = rt1011_r0_load_mode_put \ } +static const char * const rt1011_i2s_ref[] = { + "None", "Left Channel", "Right Channel" +}; + +static SOC_ENUM_SINGLE_DECL(rt1011_i2s_ref_enum, 0, 0, + rt1011_i2s_ref); + +static int rt1011_i2s_ref_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rt1011_priv *rt1011 = + snd_soc_component_get_drvdata(component); + int i2s_ref_ch = ucontrol->value.integer.value[0]; + + switch (i2s_ref_ch) { + case RT1011_I2S_REF_LEFT_CH: + regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x1022); + regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4); + break; + case RT1011_I2S_REF_RIGHT_CH: + regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8); + regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x10a2); + regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4); + break; + default: + dev_info(component->dev, "I2S Reference: Do nothing\n"); + } + + rt1011->i2s_ref = ucontrol->value.integer.value[0]; + + return 0; +} + +static int rt1011_i2s_ref_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct rt1011_priv *rt1011 = + snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1011->i2s_ref; + + return 0; +} + static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* I2S Data In Selection */ SOC_ENUM("DIN Source", rt1011_din_source_enum), @@ -1349,6 +1400,9 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* R0 temperature */ SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP, 2, 255, 0), + /* I2S Reference */ + SOC_ENUM_EXT("I2S Reference", rt1011_i2s_ref_enum, + rt1011_i2s_ref_get, rt1011_i2s_ref_put), }; static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 68fadc15fa8c1c..afb2fad94216fd 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -654,6 +654,12 @@ enum { RT1011_AIFS }; +enum { + RT1011_I2S_REF_NONE, + RT1011_I2S_REF_LEFT_CH, + RT1011_I2S_REF_RIGHT_CH, +}; + /* BiQual & DRC related settings */ #define RT1011_BQ_DRC_NUM 128 struct rt1011_bq_drc_params { @@ -692,6 +698,7 @@ struct rt1011_priv { unsigned int r0_reg, cali_done; unsigned int r0_calib, temperature_calib; int recv_spk_mode; + unsigned int i2s_ref; }; #endif /* end of _RT1011_H_ */ diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index c0c5952cdff769..6a27dfacd81c82 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -864,7 +864,7 @@ static int rt1015_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 7561d202274cf9..9845cdddcb4c8c 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -490,7 +490,7 @@ static int rt1016_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out * 4, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 8c0b00242bb872..80b7ca0e4e1e68 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -359,7 +359,7 @@ static int rt1019_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 7a0094578e467c..a9c473537a9159 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -841,7 +841,7 @@ static int rt1305_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index b4e5546e2e2171..c555b77b3c5cd2 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -664,7 +664,7 @@ static int rt1308_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 4b1ad5054e8d15..577680df705206 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -936,7 +936,7 @@ static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index fd0d3a08e9dda7..8e6414468a87b0 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1133,7 +1133,7 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index cd1db5caabad2a..d01fe73ab9c859 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1909,7 +1909,7 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9408ee63cb2688..197c560479470f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2969,7 +2969,7 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index fc0c83b73f099e..e78ea101bc8da9 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1487,7 +1487,7 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 4a50b169fe0320..e1503c2eee81d5 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3509,7 +3509,7 @@ static int rt5659_set_component_pll(struct snd_soc_component *component, int pll ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 33ff9156358b4b..3b50fb29864e25 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1046,7 +1046,7 @@ static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index be9fc58ff68127..0389b2bb360e20 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2941,7 +2941,7 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index e59323fd5bf248..33e889802ff807 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4374,7 +4374,7 @@ static int rt5665_set_component_pll(struct snd_soc_component *component, int pll ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 6ab1a8bc373522..fb09715bf9328b 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2171,7 +2171,7 @@ static int rt5668_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index ecbaf129a6e3e8..ce7684752bb0ad 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2577,7 +2577,7 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f655228c8c4b08..4a8c267d4fbc89 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4557,7 +4557,7 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, ret = rt5677_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 4a64cab99c55be..12113c2dcae2e8 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2327,7 +2327,7 @@ static int rt5682_set_component_pll(struct snd_soc_component *component, pll2_fout1 = 3840000; ret = rl6231_pll_calc(freq_in, pll2_fout1, &pll2f_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } @@ -2339,7 +2339,7 @@ static int rt5682_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(pll2_fout1, freq_out, &pll2b_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", + dev_err(component->dev, "Unsupported input clock %d\n", pll2_fout1); return ret; } @@ -2390,7 +2390,7 @@ static int rt5682_set_component_pll(struct snd_soc_component *component, ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); if (ret < 0) { - dev_err(component->dev, "Unsupport input clock %d\n", + dev_err(component->dev, "Unsupported input clock %d\n", freq_in); return ret; } diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c new file mode 100644 index 00000000000000..d3e965b2e7072b --- /dev/null +++ b/sound/soc/codecs/rt5682s.c @@ -0,0 +1,3188 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt5682s.c -- RT5682I-VS ALSA SoC audio component driver +// +// Copyright 2021 Realtek Semiconductor Corp. +// Author: Derek Fang <derek.fang@realtek.com> +// + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/rt5682s.h> + +#include "rt5682s.h" + +#define DEVICE_ID 0x6749 + +static const struct rt5682s_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682S_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682S_DMIC1_CLK_GPIO3, + .jd_src = RT5682S_JD1, + .dai_clk_names[RT5682S_DAI_WCLK_IDX] = "rt5682-dai-wclk", + .dai_clk_names[RT5682S_DAI_BCLK_IDX] = "rt5682-dai-bclk", +}; + +const char *rt5682s_supply_names[RT5682S_NUM_SUPPLIES] = { + "AVDD", + "MICVDD", +}; + +static const struct reg_sequence patch_list[] = { + {RT5682S_I2C_CTRL, 0x0007}, + {RT5682S_DIG_IN_CTRL_1, 0x0000}, + {RT5682S_CHOP_DAC_2, 0x2020}, + {RT5682S_VREF_REC_OP_FB_CAP_CTRL_2, 0x0101}, + {RT5682S_VREF_REC_OP_FB_CAP_CTRL_1, 0x80c0}, + {RT5682S_HP_CALIB_CTRL_9, 0x0002}, + {RT5682S_DEPOP_1, 0x0000}, + {RT5682S_HP_CHARGE_PUMP_2, 0x3c15}, + {RT5682S_DAC1_DIG_VOL, 0xfefe}, + {RT5682S_SAR_IL_CMD_2, 0xac00}, + {RT5682S_SAR_IL_CMD_3, 0x024c}, + {RT5682S_CBJ_CTRL_6, 0x0804}, +}; + +static void rt5682s_apply_patch_list(struct rt5682s_priv *rt5682s, + struct device *dev) +{ + int ret; + + ret = regmap_multi_reg_write(rt5682s->regmap, patch_list, ARRAY_SIZE(patch_list)); + if (ret) + dev_warn(dev, "Failed to apply regmap patch: %d\n", ret); +} + +const struct reg_default rt5682s_reg[] = { + {0x0000, 0x0001}, + {0x0002, 0x8080}, + {0x0003, 0x0001}, + {0x0005, 0x0000}, + {0x0006, 0x0000}, + {0x0008, 0x8007}, + {0x000b, 0x0000}, + {0x000f, 0x4000}, + {0x0010, 0x4040}, + {0x0011, 0x0000}, + {0x0012, 0x0000}, + {0x0013, 0x1200}, + {0x0014, 0x200a}, + {0x0015, 0x0404}, + {0x0016, 0x0404}, + {0x0017, 0x05a4}, + {0x0019, 0xffff}, + {0x001c, 0x2f2f}, + {0x001f, 0x0000}, + {0x0022, 0x5757}, + {0x0023, 0x0039}, + {0x0024, 0x000b}, + {0x0026, 0xc0c4}, + {0x0029, 0x8080}, + {0x002a, 0xa0a0}, + {0x002b, 0x0300}, + {0x0030, 0x0000}, + {0x003c, 0x08c0}, + {0x0044, 0x1818}, + {0x004b, 0x00c0}, + {0x004c, 0x0000}, + {0x004d, 0x0000}, + {0x0061, 0x00c0}, + {0x0062, 0x008a}, + {0x0063, 0x0800}, + {0x0064, 0x0000}, + {0x0065, 0x0000}, + {0x0066, 0x0030}, + {0x0067, 0x000c}, + {0x0068, 0x0000}, + {0x0069, 0x0000}, + {0x006a, 0x0000}, + {0x006b, 0x0000}, + {0x006c, 0x0000}, + {0x006d, 0x2200}, + {0x006e, 0x0810}, + {0x006f, 0xe4de}, + {0x0070, 0x3320}, + {0x0071, 0x0000}, + {0x0073, 0x0000}, + {0x0074, 0x0000}, + {0x0075, 0x0002}, + {0x0076, 0x0001}, + {0x0079, 0x0000}, + {0x007a, 0x0000}, + {0x007b, 0x0000}, + {0x007c, 0x0100}, + {0x007e, 0x0000}, + {0x007f, 0x0000}, + {0x0080, 0x0000}, + {0x0083, 0x0000}, + {0x0084, 0x0000}, + {0x0085, 0x0000}, + {0x0086, 0x0005}, + {0x0087, 0x0000}, + {0x0088, 0x0000}, + {0x008c, 0x0003}, + {0x008e, 0x0060}, + {0x008f, 0x4da1}, + {0x0091, 0x1c15}, + {0x0092, 0x0425}, + {0x0093, 0x0000}, + {0x0094, 0x0080}, + {0x0095, 0x008f}, + {0x0096, 0x0000}, + {0x0097, 0x0000}, + {0x0098, 0x0000}, + {0x0099, 0x0000}, + {0x009a, 0x0000}, + {0x009b, 0x0000}, + {0x009c, 0x0000}, + {0x009d, 0x0000}, + {0x009e, 0x0000}, + {0x009f, 0x0009}, + {0x00a0, 0x0000}, + {0x00a3, 0x0002}, + {0x00a4, 0x0001}, + {0x00b6, 0x0000}, + {0x00b7, 0x0000}, + {0x00b8, 0x0000}, + {0x00b9, 0x0002}, + {0x00be, 0x0000}, + {0x00c0, 0x0160}, + {0x00c1, 0x82a0}, + {0x00c2, 0x0000}, + {0x00d0, 0x0000}, + {0x00d2, 0x3300}, + {0x00d3, 0x2200}, + {0x00d4, 0x0000}, + {0x00d9, 0x0000}, + {0x00da, 0x0000}, + {0x00db, 0x0000}, + {0x00dc, 0x00c0}, + {0x00dd, 0x2220}, + {0x00de, 0x3131}, + {0x00df, 0x3131}, + {0x00e0, 0x3131}, + {0x00e2, 0x0000}, + {0x00e3, 0x4000}, + {0x00e4, 0x0aa0}, + {0x00e5, 0x3131}, + {0x00e6, 0x3131}, + {0x00e7, 0x3131}, + {0x00e8, 0x3131}, + {0x00ea, 0xb320}, + {0x00eb, 0x0000}, + {0x00f0, 0x0000}, + {0x00f6, 0x0000}, + {0x00fa, 0x0000}, + {0x00fb, 0x0000}, + {0x00fc, 0x0000}, + {0x00fd, 0x0000}, + {0x00fe, 0x10ec}, + {0x00ff, 0x6749}, + {0x0100, 0xa000}, + {0x010b, 0x0066}, + {0x010c, 0x6666}, + {0x010d, 0x2202}, + {0x010e, 0x6666}, + {0x010f, 0xa800}, + {0x0110, 0x0006}, + {0x0111, 0x0460}, + {0x0112, 0x2000}, + {0x0113, 0x0200}, + {0x0117, 0x8000}, + {0x0118, 0x0303}, + {0x0125, 0x0020}, + {0x0132, 0x5026}, + {0x0136, 0x8000}, + {0x0139, 0x0005}, + {0x013a, 0x3030}, + {0x013b, 0xa000}, + {0x013c, 0x4110}, + {0x013f, 0x0000}, + {0x0145, 0x0022}, + {0x0146, 0x0000}, + {0x0147, 0x0000}, + {0x0148, 0x0000}, + {0x0156, 0x0022}, + {0x0157, 0x0303}, + {0x0158, 0x2222}, + {0x0159, 0x0000}, + {0x0160, 0x4ec0}, + {0x0161, 0x0080}, + {0x0162, 0x0200}, + {0x0163, 0x0800}, + {0x0164, 0x0000}, + {0x0165, 0x0000}, + {0x0166, 0x0000}, + {0x0167, 0x000f}, + {0x0168, 0x000f}, + {0x0169, 0x0001}, + {0x0190, 0x4131}, + {0x0194, 0x0000}, + {0x0195, 0x0000}, + {0x0197, 0x0022}, + {0x0198, 0x0000}, + {0x0199, 0x0000}, + {0x01ac, 0x0000}, + {0x01ad, 0x0000}, + {0x01ae, 0x0000}, + {0x01af, 0x2000}, + {0x01b0, 0x0000}, + {0x01b1, 0x0000}, + {0x01b2, 0x0000}, + {0x01b3, 0x0017}, + {0x01b4, 0x004b}, + {0x01b5, 0x0000}, + {0x01b6, 0x03e8}, + {0x01b7, 0x0000}, + {0x01b8, 0x0000}, + {0x01b9, 0x0400}, + {0x01ba, 0xb5b6}, + {0x01bb, 0x9124}, + {0x01bc, 0x4924}, + {0x01bd, 0x0009}, + {0x01be, 0x0018}, + {0x01bf, 0x002a}, + {0x01c0, 0x004c}, + {0x01c1, 0x0097}, + {0x01c2, 0x01c3}, + {0x01c3, 0x03e9}, + {0x01c4, 0x1389}, + {0x01c5, 0xc351}, + {0x01c6, 0x02a0}, + {0x01c7, 0x0b0f}, + {0x01c8, 0x402f}, + {0x01c9, 0x0702}, + {0x01ca, 0x0000}, + {0x01cb, 0x0000}, + {0x01cc, 0x5757}, + {0x01cd, 0x5757}, + {0x01ce, 0x5757}, + {0x01cf, 0x5757}, + {0x01d0, 0x5757}, + {0x01d1, 0x5757}, + {0x01d2, 0x5757}, + {0x01d3, 0x5757}, + {0x01d4, 0x5757}, + {0x01d5, 0x5757}, + {0x01d6, 0x0000}, + {0x01d7, 0x0000}, + {0x01d8, 0x0162}, + {0x01d9, 0x0007}, + {0x01da, 0x0000}, + {0x01db, 0x0004}, + {0x01dc, 0x0000}, + {0x01de, 0x7c00}, + {0x01df, 0x0020}, + {0x01e0, 0x04c1}, + {0x01e1, 0x0000}, + {0x01e2, 0x0000}, + {0x01e3, 0x0000}, + {0x01e4, 0x0000}, + {0x01e5, 0x0000}, + {0x01e6, 0x0001}, + {0x01e7, 0x0000}, + {0x01e8, 0x0000}, + {0x01eb, 0x0000}, + {0x01ec, 0x0000}, + {0x01ed, 0x0000}, + {0x01ee, 0x0000}, + {0x01ef, 0x0000}, + {0x01f0, 0x0000}, + {0x01f1, 0x0000}, + {0x01f2, 0x0000}, + {0x01f3, 0x0000}, + {0x01f4, 0x0000}, + {0x0210, 0x6297}, + {0x0211, 0xa004}, + {0x0212, 0x0365}, + {0x0213, 0xf7ff}, + {0x0214, 0xf24c}, + {0x0215, 0x0102}, + {0x0216, 0x00a3}, + {0x0217, 0x0048}, + {0x0218, 0xa2c0}, + {0x0219, 0x0400}, + {0x021a, 0x00c8}, + {0x021b, 0x00c0}, + {0x021c, 0x0000}, + {0x021d, 0x024c}, + {0x02fa, 0x0000}, + {0x02fb, 0x0000}, + {0x02fc, 0x0000}, + {0x03fe, 0x0000}, + {0x03ff, 0x0000}, + {0x0500, 0x0000}, + {0x0600, 0x0000}, + {0x0610, 0x6666}, + {0x0611, 0xa9aa}, + {0x0620, 0x6666}, + {0x0621, 0xa9aa}, + {0x0630, 0x6666}, + {0x0631, 0xa9aa}, + {0x0640, 0x6666}, + {0x0641, 0xa9aa}, + {0x07fa, 0x0000}, + {0x08fa, 0x0000}, + {0x08fb, 0x0000}, + {0x0d00, 0x0000}, + {0x1100, 0x0000}, + {0x1101, 0x0000}, + {0x1102, 0x0000}, + {0x1103, 0x0000}, + {0x1104, 0x0000}, + {0x1105, 0x0000}, + {0x1106, 0x0000}, + {0x1107, 0x0000}, + {0x1108, 0x0000}, + {0x1109, 0x0000}, + {0x110a, 0x0000}, + {0x110b, 0x0000}, + {0x110c, 0x0000}, + {0x1111, 0x0000}, + {0x1112, 0x0000}, + {0x1113, 0x0000}, + {0x1114, 0x0000}, + {0x1115, 0x0000}, + {0x1116, 0x0000}, + {0x1117, 0x0000}, + {0x1118, 0x0000}, + {0x1119, 0x0000}, + {0x111a, 0x0000}, + {0x111b, 0x0000}, + {0x111c, 0x0000}, + {0x1401, 0x0404}, + {0x1402, 0x0007}, + {0x1403, 0x0365}, + {0x1404, 0x0210}, + {0x1405, 0x0365}, + {0x1406, 0x0210}, + {0x1407, 0x0000}, + {0x1408, 0x0000}, + {0x1409, 0x0000}, + {0x140a, 0x0000}, + {0x140b, 0x0000}, + {0x140c, 0x0000}, + {0x140d, 0x0000}, + {0x140e, 0x0000}, + {0x140f, 0x0000}, + {0x1410, 0x0000}, + {0x1411, 0x0000}, + {0x1801, 0x0004}, + {0x1802, 0x0000}, + {0x1803, 0x0000}, + {0x1804, 0x0000}, + {0x1805, 0x00ff}, + {0x2c00, 0x0000}, + {0x3400, 0x0200}, + {0x3404, 0x0000}, + {0x3405, 0x0000}, + {0x3406, 0x0000}, + {0x3407, 0x0000}, + {0x3408, 0x0000}, + {0x3409, 0x0000}, + {0x340a, 0x0000}, + {0x340b, 0x0000}, + {0x340c, 0x0000}, + {0x340d, 0x0000}, + {0x340e, 0x0000}, + {0x340f, 0x0000}, + {0x3410, 0x0000}, + {0x3411, 0x0000}, + {0x3412, 0x0000}, + {0x3413, 0x0000}, + {0x3414, 0x0000}, + {0x3415, 0x0000}, + {0x3424, 0x0000}, + {0x3425, 0x0000}, + {0x3426, 0x0000}, + {0x3427, 0x0000}, + {0x3428, 0x0000}, + {0x3429, 0x0000}, + {0x342a, 0x0000}, + {0x342b, 0x0000}, + {0x342c, 0x0000}, + {0x342d, 0x0000}, + {0x342e, 0x0000}, + {0x342f, 0x0000}, + {0x3430, 0x0000}, + {0x3431, 0x0000}, + {0x3432, 0x0000}, + {0x3433, 0x0000}, + {0x3434, 0x0000}, + {0x3435, 0x0000}, + {0x3440, 0x6319}, + {0x3441, 0x3771}, + {0x3500, 0x0002}, + {0x3501, 0x5728}, + {0x3b00, 0x3010}, + {0x3b01, 0x3300}, + {0x3b02, 0x2200}, + {0x3b03, 0x0100}, +}; + +static bool rt5682s_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5682S_RESET: + case RT5682S_CBJ_CTRL_2: + case RT5682S_I2S1_F_DIV_CTRL_2: + case RT5682S_I2S2_F_DIV_CTRL_2: + case RT5682S_INT_ST_1: + case RT5682S_GPIO_ST: + case RT5682S_IL_CMD_1: + case RT5682S_4BTN_IL_CMD_1: + case RT5682S_AJD1_CTRL: + case RT5682S_VERSION_ID...RT5682S_DEVICE_ID: + case RT5682S_STO_NG2_CTRL_1: + case RT5682S_STO_NG2_CTRL_5...RT5682S_STO_NG2_CTRL_7: + case RT5682S_STO1_DAC_SIL_DET: + case RT5682S_HP_IMP_SENS_CTRL_1...RT5682S_HP_IMP_SENS_CTRL_4: + case RT5682S_HP_IMP_SENS_CTRL_13: + case RT5682S_HP_IMP_SENS_CTRL_14: + case RT5682S_HP_IMP_SENS_CTRL_43...RT5682S_HP_IMP_SENS_CTRL_46: + case RT5682S_HP_CALIB_CTRL_1: + case RT5682S_HP_CALIB_CTRL_10: + case RT5682S_HP_CALIB_ST_1...RT5682S_HP_CALIB_ST_11: + case RT5682S_SAR_IL_CMD_2...RT5682S_SAR_IL_CMD_5: + case RT5682S_SAR_IL_CMD_10: + case RT5682S_SAR_IL_CMD_11: + case RT5682S_VERSION_ID_HIDE: + case RT5682S_VERSION_ID_CUS: + case RT5682S_I2C_TRANS_CTRL: + case RT5682S_DMIC_FLOAT_DET: + case RT5682S_HA_CMP_OP_1: + case RT5682S_NEW_CBJ_DET_CTL_10...RT5682S_NEW_CBJ_DET_CTL_16: + case RT5682S_CLK_SW_TEST_1: + case RT5682S_CLK_SW_TEST_2: + case RT5682S_EFUSE_READ_1...RT5682S_EFUSE_READ_18: + case RT5682S_PILOT_DIG_CTL_1: + return true; + default: + return false; + } +} + +static bool rt5682s_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5682S_RESET: + case RT5682S_VERSION_ID: + case RT5682S_VENDOR_ID: + case RT5682S_DEVICE_ID: + case RT5682S_HP_CTRL_1: + case RT5682S_HP_CTRL_2: + case RT5682S_HPL_GAIN: + case RT5682S_HPR_GAIN: + case RT5682S_I2C_CTRL: + case RT5682S_CBJ_BST_CTRL: + case RT5682S_CBJ_DET_CTRL: + case RT5682S_CBJ_CTRL_1...RT5682S_CBJ_CTRL_8: + case RT5682S_DAC1_DIG_VOL: + case RT5682S_STO1_ADC_DIG_VOL: + case RT5682S_STO1_ADC_BOOST: + case RT5682S_HP_IMP_GAIN_1: + case RT5682S_HP_IMP_GAIN_2: + case RT5682S_SIDETONE_CTRL: + case RT5682S_STO1_ADC_MIXER: + case RT5682S_AD_DA_MIXER: + case RT5682S_STO1_DAC_MIXER: + case RT5682S_A_DAC1_MUX: + case RT5682S_DIG_INF2_DATA: + case RT5682S_REC_MIXER: + case RT5682S_CAL_REC: + case RT5682S_HP_ANA_OST_CTRL_1...RT5682S_HP_ANA_OST_CTRL_3: + case RT5682S_PWR_DIG_1...RT5682S_PWR_MIXER: + case RT5682S_MB_CTRL: + case RT5682S_CLK_GATE_TCON_1...RT5682S_CLK_GATE_TCON_3: + case RT5682S_CLK_DET...RT5682S_LPF_AD_DMIC: + case RT5682S_I2S1_SDP: + case RT5682S_I2S2_SDP: + case RT5682S_ADDA_CLK_1: + case RT5682S_ADDA_CLK_2: + case RT5682S_I2S1_F_DIV_CTRL_1: + case RT5682S_I2S1_F_DIV_CTRL_2: + case RT5682S_TDM_CTRL: + case RT5682S_TDM_ADDA_CTRL_1: + case RT5682S_TDM_ADDA_CTRL_2: + case RT5682S_DATA_SEL_CTRL_1: + case RT5682S_TDM_TCON_CTRL_1: + case RT5682S_TDM_TCON_CTRL_2: + case RT5682S_GLB_CLK: + case RT5682S_PLL_TRACK_1...RT5682S_PLL_TRACK_6: + case RT5682S_PLL_TRACK_11: + case RT5682S_DEPOP_1: + case RT5682S_HP_CHARGE_PUMP_1: + case RT5682S_HP_CHARGE_PUMP_2: + case RT5682S_HP_CHARGE_PUMP_3: + case RT5682S_MICBIAS_1...RT5682S_MICBIAS_3: + case RT5682S_PLL_TRACK_12...RT5682S_PLL_CTRL_7: + case RT5682S_RC_CLK_CTRL: + case RT5682S_I2S2_M_CLK_CTRL_1: + case RT5682S_I2S2_F_DIV_CTRL_1: + case RT5682S_I2S2_F_DIV_CTRL_2: + case RT5682S_IRQ_CTRL_1...RT5682S_IRQ_CTRL_4: + case RT5682S_INT_ST_1: + case RT5682S_GPIO_CTRL_1: + case RT5682S_GPIO_CTRL_2: + case RT5682S_GPIO_ST: + case RT5682S_HP_AMP_DET_CTRL_1: + case RT5682S_MID_HP_AMP_DET: + case RT5682S_LOW_HP_AMP_DET: + case RT5682S_DELAY_BUF_CTRL: + case RT5682S_SV_ZCD_1: + case RT5682S_SV_ZCD_2: + case RT5682S_IL_CMD_1...RT5682S_IL_CMD_6: + case RT5682S_4BTN_IL_CMD_1...RT5682S_4BTN_IL_CMD_7: + case RT5682S_ADC_STO1_HP_CTRL_1: + case RT5682S_ADC_STO1_HP_CTRL_2: + case RT5682S_AJD1_CTRL: + case RT5682S_JD_CTRL_1: + case RT5682S_DUMMY_1...RT5682S_DUMMY_3: + case RT5682S_DAC_ADC_DIG_VOL1: + case RT5682S_BIAS_CUR_CTRL_2...RT5682S_BIAS_CUR_CTRL_10: + case RT5682S_VREF_REC_OP_FB_CAP_CTRL_1: + case RT5682S_VREF_REC_OP_FB_CAP_CTRL_2: + case RT5682S_CHARGE_PUMP_1: + case RT5682S_DIG_IN_CTRL_1: + case RT5682S_PAD_DRIVING_CTRL: + case RT5682S_CHOP_DAC_1: + case RT5682S_CHOP_DAC_2: + case RT5682S_CHOP_ADC: + case RT5682S_CALIB_ADC_CTRL: + case RT5682S_VOL_TEST: + case RT5682S_SPKVDD_DET_ST: + case RT5682S_TEST_MODE_CTRL_1...RT5682S_TEST_MODE_CTRL_4: + case RT5682S_PLL_INTERNAL_1...RT5682S_PLL_INTERNAL_4: + case RT5682S_STO_NG2_CTRL_1...RT5682S_STO_NG2_CTRL_10: + case RT5682S_STO1_DAC_SIL_DET: + case RT5682S_SIL_PSV_CTRL1: + case RT5682S_SIL_PSV_CTRL2: + case RT5682S_SIL_PSV_CTRL3: + case RT5682S_SIL_PSV_CTRL4: + case RT5682S_SIL_PSV_CTRL5: + case RT5682S_HP_IMP_SENS_CTRL_1...RT5682S_HP_IMP_SENS_CTRL_46: + case RT5682S_HP_LOGIC_CTRL_1...RT5682S_HP_LOGIC_CTRL_3: + case RT5682S_HP_CALIB_CTRL_1...RT5682S_HP_CALIB_CTRL_11: + case RT5682S_HP_CALIB_ST_1...RT5682S_HP_CALIB_ST_11: + case RT5682S_SAR_IL_CMD_1...RT5682S_SAR_IL_CMD_14: + case RT5682S_DUMMY_4...RT5682S_DUMMY_6: + case RT5682S_VERSION_ID_HIDE: + case RT5682S_VERSION_ID_CUS: + case RT5682S_SCAN_CTL: + case RT5682S_HP_AMP_DET: + case RT5682S_BIAS_CUR_CTRL_11: + case RT5682S_BIAS_CUR_CTRL_12: + case RT5682S_BIAS_CUR_CTRL_13: + case RT5682S_BIAS_CUR_CTRL_14: + case RT5682S_BIAS_CUR_CTRL_15: + case RT5682S_BIAS_CUR_CTRL_16: + case RT5682S_BIAS_CUR_CTRL_17: + case RT5682S_BIAS_CUR_CTRL_18: + case RT5682S_I2C_TRANS_CTRL: + case RT5682S_DUMMY_7: + case RT5682S_DUMMY_8: + case RT5682S_DMIC_FLOAT_DET: + case RT5682S_HA_CMP_OP_1...RT5682S_HA_CMP_OP_13: + case RT5682S_HA_CMP_OP_14...RT5682S_HA_CMP_OP_25: + case RT5682S_NEW_CBJ_DET_CTL_1...RT5682S_NEW_CBJ_DET_CTL_16: + case RT5682S_DA_FILTER_1...RT5682S_DA_FILTER_5: + case RT5682S_CLK_SW_TEST_1: + case RT5682S_CLK_SW_TEST_2: + case RT5682S_CLK_SW_TEST_3...RT5682S_CLK_SW_TEST_14: + case RT5682S_EFUSE_MANU_WRITE_1...RT5682S_EFUSE_MANU_WRITE_6: + case RT5682S_EFUSE_READ_1...RT5682S_EFUSE_READ_18: + case RT5682S_EFUSE_TIMING_CTL_1: + case RT5682S_EFUSE_TIMING_CTL_2: + case RT5682S_PILOT_DIG_CTL_1: + case RT5682S_PILOT_DIG_CTL_2: + case RT5682S_HP_AMP_DET_CTL_1...RT5682S_HP_AMP_DET_CTL_4: + return true; + default: + return false; + } +} + +static void rt5682s_reset(struct rt5682s_priv *rt5682s) +{ + regmap_write(rt5682s->regmap, RT5682S_RESET, 0); +} + +static int rt5682s_button_detect(struct snd_soc_component *component) +{ + int btn_type, val; + + val = snd_soc_component_read(component, RT5682S_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_component_write(component, RT5682S_4BTN_IL_CMD_1, val); + dev_dbg(component->dev, "%s btn_type=%x\n", __func__, btn_type); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_2, + RT5682S_SAR_ADC_PSV_MASK, RT5682S_SAR_ADC_PSV_ENTRY); + + return btn_type; +} + +enum { + SAR_PWR_OFF, + SAR_PWR_NORMAL, + SAR_PWR_SAVING, +}; + +static void rt5682s_sar_power_mode(struct snd_soc_component *component, + int mode, int jd_step) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + mutex_lock(&rt5682s->sar_mutex); + + switch (mode) { + case SAR_PWR_SAVING: + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_DIS); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, + RT5682S_CTRL_MB1_REG | RT5682S_CTRL_MB2_REG); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | + RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK, RT5682S_SAR_BUTDET_EN); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_2, + RT5682S_SAR_ADC_PSV_MASK, RT5682S_SAR_ADC_PSV_ENTRY); + break; + case SAR_PWR_NORMAL: + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_EN); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK, + RT5682S_CTRL_MB1_FSM | RT5682S_CTRL_MB2_FSM); + if (!jd_step) { + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_SEL_MB1_2_AUTO); + usleep_range(5000, 5500); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK, + RT5682S_SAR_BUTDET_EN | RT5682S_SAR_BUTDET_POW_NORM); + } + break; + case SAR_PWR_OFF: + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK | + RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS | + RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU); + break; + default: + dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode); + break; + } + + mutex_unlock(&rt5682s->sar_mutex); +} + +static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_BTN); + snd_soc_component_write(component, RT5682S_IL_CMD_1, 0x0040); + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK | RT5682S_4BTN_IL_RST_MASK, + RT5682S_4BTN_IL_EN | RT5682S_4BTN_IL_NOR); + snd_soc_component_update_bits(component, RT5682S_IRQ_CTRL_3, + RT5682S_IL_IRQ_MASK, RT5682S_IL_IRQ_EN); +} + +static void rt5682s_disable_push_button_irq(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, RT5682S_IRQ_CTRL_3, + RT5682S_IL_IRQ_MASK, RT5682S_IL_IRQ_DIS); + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); +} + +/** + * rt5682s_headset_detect - Detect headset. + * @component: SoC audio component device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert) +{ + unsigned int val, count; + int jack_type = 0; + + if (jack_insert) { + rt5682s_disable_push_button_irq(component); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF1 | RT5682S_PWR_VREF2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF1 | RT5682S_PWR_VREF2 | RT5682S_PWR_MB); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2, 0); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2, + RT5682S_PWR_FV1 | RT5682S_PWR_FV2); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_CBJ, RT5682S_PWR_CBJ); + snd_soc_component_write(component, RT5682S_SAR_IL_CMD_3, 0x0365); + snd_soc_component_update_bits(component, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_OSW_L_MASK | RT5682S_OSW_R_MASK, + RT5682S_OSW_L_DIS | RT5682S_OSW_R_DIS); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_13, + RT5682S_SAR_SOUR_MASK, RT5682S_SAR_SOUR_TYPE); + rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 1); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); + usleep_range(45000, 50000); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_HIGH); + + count = 0; + do { + usleep_range(10000, 15000); + val = snd_soc_component_read(component, RT5682S_CBJ_CTRL_2) + & RT5682S_JACK_TYPE_MASK; + count++; + } while (val == 0 && count < 50); + + pr_debug("%s, val=%d, count=%d\n", __func__, val, count); + + switch (val) { + case 0x1: + case 0x2: + jack_type = SND_JACK_HEADSET; + snd_soc_component_write(component, RT5682S_SAR_IL_CMD_3, 0x024c); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_EN); + snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_SEL_MB1_2_MASK, val << RT5682S_SAR_SEL_MB1_2_SFT); + rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 1); + rt5682s_enable_push_button_irq(component); + break; + default: + jack_type = SND_JACK_HEADPHONE; + break; + } + snd_soc_component_update_bits(component, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_OSW_L_MASK | RT5682S_OSW_R_MASK, + RT5682S_OSW_L_EN | RT5682S_OSW_R_EN); + } else { + rt5682s_sar_power_mode(component, SAR_PWR_OFF, 1); + rt5682s_disable_push_button_irq(component); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW); + + if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); + if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3, + RT5682S_PWR_CBJ, 0); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1, + RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_DIS); + snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3, + RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_DIS); + jack_type = 0; + } + + dev_dbg(component->dev, "jack_type = %d\n", jack_type); + + return jack_type; +} + +static void rt5682s_jack_detect_handler(struct work_struct *work) +{ + struct rt5682s_priv *rt5682s = + container_of(work, struct rt5682s_priv, jack_detect_work.work); + int val, btn_type; + + while (!rt5682s->component) + usleep_range(10000, 15000); + + while (!rt5682s->component->card->instantiated) + usleep_range(10000, 15000); + + mutex_lock(&rt5682s->calibrate_mutex); + + val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) + & RT5682S_JDH_RS_MASK; + if (!val) { + /* jack in */ + if (rt5682s->jack_type == 0) { + /* jack was out, report jack type */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 1); + rt5682s->irq_work_delay_time = 0; + } else if ((rt5682s->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + rt5682s->jack_type = SND_JACK_HEADSET; + btn_type = rt5682s_button_detect(rt5682s->component); + /** + * rt5682s can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + rt5682s->jack_type |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + rt5682s->jack_type |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + rt5682s->jack_type |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + rt5682s->jack_type |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + dev_err(rt5682s->component->dev, + "Unexpected button code 0x%04x\n", btn_type); + break; + } + } + } else { + /* jack out */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 0); + rt5682s->irq_work_delay_time = 50; + } + + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (rt5682s->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + schedule_delayed_work(&rt5682s->jd_check_work, 0); + else + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + mutex_unlock(&rt5682s->calibrate_mutex); +} + +static void rt5682s_jd_check_handler(struct work_struct *work) +{ + struct rt5682s_priv *rt5682s = + container_of(work, struct rt5682s_priv, jd_check_work.work); + + if (snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL) + & RT5682S_JDH_RS_MASK) { + /* jack out */ + rt5682s->jack_type = rt5682s_headset_detect(rt5682s->component, 0); + + snd_soc_jack_report(rt5682s->hs_jack, rt5682s->jack_type, + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + } else { + schedule_delayed_work(&rt5682s->jd_check_work, 500); + } +} + +static irqreturn_t rt5682s_irq(int irq, void *data) +{ + struct rt5682s_priv *rt5682s = data; + + mod_delayed_work(system_power_efficient_wq, &rt5682s->jack_detect_work, + msecs_to_jiffies(rt5682s->irq_work_delay_time)); + + return IRQ_HANDLED; +} + +static int rt5682s_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int btndet_delay = 16; + + rt5682s->hs_jack = hs_jack; + + if (!hs_jack) { + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK, RT5682S_JD1_DIS); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_JDH, 0); + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + + return 0; + } + + switch (rt5682s->pdata.jd_src) { + case RT5682S_JD1: + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_5, + RT5682S_JD_FAST_OFF_SRC_MASK, RT5682S_JD_FAST_OFF_SRC_JDH); + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_2, + RT5682S_EXT_JD_SRC, RT5682S_EXT_JD_SRC_MANUAL); + regmap_update_bits(rt5682s->regmap, RT5682S_CBJ_CTRL_1, + RT5682S_EMB_JD_MASK | RT5682S_DET_TYPE | + RT5682S_POL_FAST_OFF_MASK | RT5682S_MIC_CAP_MASK, + RT5682S_EMB_JD_EN | RT5682S_DET_TYPE | + RT5682S_POL_FAST_OFF_HIGH | RT5682S_MIC_CAP_HS); + regmap_update_bits(rt5682s->regmap, RT5682S_SAR_IL_CMD_1, + RT5682S_SAR_POW_MASK, RT5682S_SAR_POW_EN); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP1_PIN_MASK, RT5682S_GP1_PIN_IRQ); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BGLDO, RT5682S_PWR_BGLDO); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_2, + RT5682S_PWR_JD_MASK, RT5682S_PWR_JD_ENABLE); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_IRQ | RT5682S_POW_JDH, RT5682S_POW_IRQ | RT5682S_POW_JDH); + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK | RT5682S_JD1_POL_MASK, + RT5682S_JD1_EN | RT5682S_JD1_POL_NOR); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_4, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_5, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_6, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + regmap_update_bits(rt5682s->regmap, RT5682S_4BTN_IL_CMD_7, + RT5682S_4BTN_IL_HOLD_WIN_MASK | RT5682S_4BTN_IL_CLICK_WIN_MASK, + (btndet_delay << RT5682S_4BTN_IL_HOLD_WIN_SFT | btndet_delay)); + + mod_delayed_work(system_power_efficient_wq, + &rt5682s->jack_detect_work, msecs_to_jiffies(250)); + break; + + case RT5682S_JD_NULL: + regmap_update_bits(rt5682s->regmap, RT5682S_IRQ_CTRL_2, + RT5682S_JD1_EN_MASK, RT5682S_JD1_DIS); + regmap_update_bits(rt5682s->regmap, RT5682S_RC_CLK_CTRL, + RT5682S_POW_JDH, 0); + break; + + default: + dev_warn(component->dev, "Wrong JD source\n"); + break; + } + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(cbj_bst_tlv, -1200, 150, 0); + +static const struct snd_kcontrol_new rt5682s_snd_controls[] = { + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682S_DAC1_DIG_VOL, + RT5682S_L_VOL_SFT + 2, RT5682S_R_VOL_SFT + 2, 63, 0, dac_vol_tlv), + + /* CBJ Boost Volume */ + SOC_SINGLE_TLV("CBJ Boost Volume", RT5682S_REC_MIXER, + RT5682S_BST_CBJ_SFT, 35, 0, cbj_bst_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE_SFT, RT5682S_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_VOL_SFT + 1, RT5682S_R_VOL_SFT + 1, 63, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5682S_STO1_ADC_BOOST, + RT5682S_STO1_ADC_L_BST_SFT, RT5682S_STO1_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), +}; + +/** + * rt5682s_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @component: SoC audio component device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5682S can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the component driver will turn on + * ASRC for these filters if ASRC is selected as their clock source. + */ +int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, + unsigned int filter_mask, unsigned int clk_src) +{ + switch (clk_src) { + case RT5682S_CLK_SEL_SYS: + case RT5682S_CLK_SEL_I2S1_ASRC: + case RT5682S_CLK_SEL_I2S2_ASRC: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5682S_DA_STEREO1_FILTER) { + snd_soc_component_update_bits(component, RT5682S_PLL_TRACK_2, + RT5682S_FILTER_CLK_SEL_MASK, clk_src << RT5682S_FILTER_CLK_SEL_SFT); + } + + if (filter_mask & RT5682S_AD_STEREO1_FILTER) { + snd_soc_component_update_bits(component, RT5682S_PLL_TRACK_3, + RT5682S_FILTER_CLK_SEL_MASK, clk_src << RT5682S_FILTER_CLK_SEL_SFT); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5682s_sel_asrc_clk_src); + +static int rt5682s_div_sel(struct rt5682s_priv *rt5682s, + int target, const int div[], int size) +{ + int i; + + if (rt5682s->sysclk < target) { + dev_err(rt5682s->component->dev, + "sysclk rate %d is too low\n", rt5682s->sysclk); + return 0; + } + + for (i = 0; i < size - 1; i++) { + dev_dbg(rt5682s->component->dev, "div[%d]=%d\n", i, div[i]); + if (target * div[i] == rt5682s->sysclk) + return i; + if (target * div[i + 1] > rt5682s->sysclk) { + dev_dbg(rt5682s->component->dev, + "can't find div for sysclk %d\n", rt5682s->sysclk); + return i; + } + } + + if (target * div[i] < rt5682s->sysclk) + dev_err(rt5682s->component->dev, + "sysclk rate %d is too high\n", rt5682s->sysclk); + + return size - 1; +} + +static int get_clk_info(int sclk, int rate) +{ + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + + if (sclk <= 0 || rate <= 0) + return -EINVAL; + + rate = rate << 8; + for (i = 0; i < ARRAY_SIZE(pd); i++) + if (sclk == rate * pd[i]) + return i; + + return -EINVAL; +} + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int idx, dmic_clk_rate = 3072000; + static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128}; + + if (rt5682s->pdata.dmic_clk_rate) + dmic_clk_rate = rt5682s->pdata.dmic_clk_rate; + + idx = rt5682s_div_sel(rt5682s, dmic_clk_rate, div, ARRAY_SIZE(div)); + + snd_soc_component_update_bits(component, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_CLK_MASK, idx << RT5682S_DMIC_CLK_SFT); + + return 0; +} + +static int set_filter_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int ref, val, reg, idx; + static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; + static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + + val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1) + & RT5682S_GP4_PIN_MASK; + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2) + ref = 256 * rt5682s->lrck[RT5682S_AIF2]; + else + ref = 256 * rt5682s->lrck[RT5682S_AIF1]; + + idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f)); + + if (w->shift == RT5682S_PWR_ADC_S1F_BIT) + reg = RT5682S_PLL_TRACK_3; + else + reg = RT5682S_PLL_TRACK_2; + + snd_soc_component_update_bits(component, reg, + RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT); + + /* select over sample rate */ + for (idx = 0; idx < ARRAY_SIZE(div_o); idx++) { + if (rt5682s->sysclk <= 12288000 * div_o[idx]) + break; + } + + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, + RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK, + (idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT)); + + return 0; +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int delay = 50, val; + + if (rt5682s->pdata.dmic_delay) + delay = rt5682s->pdata.dmic_delay; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = (snd_soc_component_read(component, RT5682S_GLB_CLK) + & RT5682S_SCLK_SRC_MASK) >> RT5682S_SCLK_SRC_SFT; + if (val == RT5682S_CLK_SRC_PLL1 || val == RT5682S_CLK_SRC_PLL2) + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB, + RT5682S_PWR_VREF2 | RT5682S_PWR_MB); + + /*Add delay to avoid pop noise*/ + msleep(delay); + break; + + case SND_SOC_DAPM_POST_PMD: + if (!rt5682s->jack_type) { + if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0); + if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2")) + snd_soc_component_update_bits(component, + RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0); + } + break; + } + + return 0; +} + +static int set_i2s_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int pre_div, id; + unsigned int reg, mask, sft; + + if (event != SND_SOC_DAPM_PRE_PMU) + return 0; + + if (w->shift == RT5682S_PWR_I2S2_BIT) { + id = RT5682S_AIF2; + reg = RT5682S_I2S2_M_CLK_CTRL_1; + mask = RT5682S_I2S2_M_D_MASK; + sft = RT5682S_I2S2_M_D_SFT; + } else { + id = RT5682S_AIF1; + reg = RT5682S_ADDA_CLK_1; + mask = RT5682S_I2S_M_D_MASK; + sft = RT5682S_I2S_M_D_SFT; + } + + if (!rt5682s->master[id]) + return 0; + + pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]); + if (pre_div < 0) { + dev_err(component->dev, "get pre_div failed\n"); + return -EINVAL; + } + + dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n", + rt5682s->lrck[id], pre_div, id); + snd_soc_component_update_bits(component, reg, mask, pre_div << sft); + + return 0; +} + +static int is_sys_clk_from_plla(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if ((rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL1) || + (rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL2 && rt5682s->pll_comb == USE_PLLAB)) + return 1; + + return 0; +} + +static int is_sys_clk_from_pllb(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if (rt5682s->sysclk_src == RT5682S_CLK_SRC_PLL2) + return 1; + + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, sft, val; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (w->shift) { + case RT5682S_ADC_STO1_ASRC_SFT: + reg = RT5682S_PLL_TRACK_3; + sft = RT5682S_FILTER_CLK_SEL_SFT; + break; + case RT5682S_DAC_STO1_ASRC_SFT: + reg = RT5682S_PLL_TRACK_2; + sft = RT5682S_FILTER_CLK_SEL_SFT; + break; + default: + return 0; + } + + val = (snd_soc_component_read(component, reg) >> sft) & 0xf; + switch (val) { + case RT5682S_CLK_SEL_I2S1_ASRC: + case RT5682S_CLK_SEL_I2S2_ASRC: + return 1; + default: + return 0; + } +} + +static int is_headset_type(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + if ((rt5682s->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) + return 1; + + return 0; +} + +static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN); + break; + + case SND_SOC_DAPM_POST_PMU: + usleep_range(30000, 35000); + snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_11, 0x6666); + snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_12, 0xa82a); + snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, + RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | + RT5682S_HPO_SEL_IP_EN_SW, RT5682S_HPO_L_PATH_EN | + RT5682S_HPO_R_PATH_EN | RT5682S_HPO_IP_EN_GATING); + snd_soc_component_write(component, RT5682S_HP_AMP_DET_CTL_1, 0x3050); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2, + RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK | + RT5682S_HPO_SEL_IP_EN_SW, 0); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN | + RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN, 0); + snd_soc_component_update_bits(component, RT5682S_DEPOP_1, + RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN, 0); + break; + } + + return 0; +} + +static int sar_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + rt5682s_sar_power_mode(component, SAR_PWR_NORMAL, 0); + break; + case SND_SOC_DAPM_POST_PMD: + rt5682s_sar_power_mode(component, SAR_PWR_SAVING, 0); + break; + } + + return 0; +} + +/* Interface data select */ +static const char * const rt5682s_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_if2_adc_enum, RT5682S_DIG_INF2_DATA, + RT5682S_IF2_ADC_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_01_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC1_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_23_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC2_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_45_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC3_SEL_SFT, rt5682s_data_select); + +static SOC_ENUM_SINGLE_DECL(rt5682s_if1_67_adc_enum, RT5682S_TDM_ADDA_CTRL_1, + RT5682S_IF1_ADC4_SEL_SFT, rt5682s_data_select); + +static const struct snd_kcontrol_new rt5682s_if2_adc_swap_mux = + SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5682s_if2_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5682s_if1_01_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5682s_if1_23_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5682s_if1_45_adc_enum); + +static const struct snd_kcontrol_new rt5682s_if1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682s_if1_67_adc_enum); + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5682s_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5682S_STO1_ADC_MIXER, + RT5682S_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5682S_AD_DA_MIXER, + RT5682S_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5682S_STO1_DAC_MIXER, + RT5682S_M_DAC_R1_STO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5682s_rec1_l_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5682S_REC_MIXER, + RT5682S_M_CBJ_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5682s_rec1_r_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5682S_REC_MIXER, + RT5682S_M_CBJ_RM1_R_SFT, 1, 1), +}; + +/* STO1 ADC1 Source */ +/* MX-26 [13] [5] */ +static const char * const rt5682s_sto1_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc1l_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC1L_SRC_SFT, rt5682s_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc1l_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682s_sto1_adc1l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc1r_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC1R_SRC_SFT, rt5682s_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc1r_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682s_sto1_adc1r_enum); + +/* STO1 ADC Source */ +/* MX-26 [11:10] [3:2] */ +static const char * const rt5682s_sto1_adc_src[] = { + "ADC1 L", "ADC1 R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adcl_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADCL_SRC_SFT, rt5682s_sto1_adc_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adcl_mux = + SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5682s_sto1_adcl_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adcr_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADCR_SRC_SFT, rt5682s_sto1_adc_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adcr_mux = + SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5682s_sto1_adcr_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [12] [4] */ +static const char * const rt5682s_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc2l_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC2L_SRC_SFT, rt5682s_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc2l_mux = + SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5682s_sto1_adc2l_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_sto1_adc2r_enum, RT5682S_STO1_ADC_MIXER, + RT5682S_STO1_ADC2R_SRC_SFT, rt5682s_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5682s_sto1_adc2r_mux = + SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5682s_sto1_adc2r_enum); + +/* MX-79 [6:4] I2S1 ADC data location */ +static const unsigned int rt5682s_if1_adc_slot_values[] = { + 0, 2, 4, 6, +}; + +static const char * const rt5682s_if1_adc_slot_src[] = { + "Slot 0", "Slot 2", "Slot 4", "Slot 6" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rt5682s_if1_adc_slot_enum, + RT5682S_TDM_CTRL, RT5682S_TDM_ADC_LCA_SFT, RT5682S_TDM_ADC_LCA_MASK, + rt5682s_if1_adc_slot_src, rt5682s_if1_adc_slot_values); + +static const struct snd_kcontrol_new rt5682s_if1_adc_slot_mux = + SOC_DAPM_ENUM("IF1 ADC Slot location", rt5682s_if1_adc_slot_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2B [4], MX-2B [0]*/ +static const char * const rt5682s_alg_dac1_src[] = { + "Stereo1 DAC Mixer", "DAC1" +}; + +static SOC_ENUM_SINGLE_DECL(rt5682s_alg_dac_l1_enum, RT5682S_A_DAC1_MUX, + RT5682S_A_DACL1_SFT, rt5682s_alg_dac1_src); + +static const struct snd_kcontrol_new rt5682s_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DAC L1 Source", rt5682s_alg_dac_l1_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682s_alg_dac_r1_enum, RT5682S_A_DAC1_MUX, + RT5682S_A_DACR1_SFT, rt5682s_alg_dac1_src); + +static const struct snd_kcontrol_new rt5682s_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DAC R1 Source", rt5682s_alg_dac_r1_enum); + +static const unsigned int rt5682s_adcdat_pin_values[] = { + 1, 3, +}; + +static const char * const rt5682s_adcdat_pin_select[] = { + "ADCDAT1", "ADCDAT2", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rt5682s_adcdat_pin_enum, + RT5682S_GPIO_CTRL_1, RT5682S_GP4_PIN_SFT, RT5682S_GP4_PIN_MASK, + rt5682s_adcdat_pin_select, rt5682s_adcdat_pin_values); + +static const struct snd_kcontrol_new rt5682s_adcdat_pin_ctrl = + SOC_DAPM_ENUM("ADCDAT", rt5682s_adcdat_pin_enum); + +static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO MB1", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO MB2", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* PLL Powers */ + SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3, + RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3, + RT5682S_RSTB_PLLB_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DAC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_AD_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DA_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5682S_PLL_TRACK_1, + RT5682S_DMIC_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MB2_BIT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + + SND_SOC_DAPM_INPUT("IN1P"), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5682S_DMIC_CTRL_1, RT5682S_DMIC_1_EN_SFT, 0, + set_dmic_power, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682s_rec1_l_mix, + ARRAY_SIZE(rt5682s_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5682s_rec1_r_mix, + ARRAY_SIZE(rt5682s_rec1_r_mix)), + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5682S_CAL_REC, + RT5682S_PWR_RM1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5682S_CAL_REC, + RT5682S_PWR_RM1_R_BIT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5682S_PWR_DIG_1, + RT5682S_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5682S_PWR_DIG_1, + RT5682S_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5682S_CHOP_ADC, + RT5682S_CKGEN_ADC1_SFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adcl_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_sto1_adcr_mux), + SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_adc_slot_mux), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682S_PWR_DIG_2, + RT5682S_PWR_ADC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_L_MUTE_SFT, 1, rt5682s_sto1_adc_l_mix, + ARRAY_SIZE(rt5682s_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682S_STO1_ADC_DIG_VOL, + RT5682S_R_MUTE_SFT, 1, rt5682s_sto1_adc_r_mix, + ARRAY_SIZE(rt5682s_sto1_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT, + 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT, + 0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5682s_if2_adc_swap_mux), + + SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0, &rt5682s_adcdat_pin_ctrl), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, RT5682S_I2S1_SDP, + RT5682S_SEL_ADCDAT_SFT, 1), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, RT5682S_I2S2_SDP, + RT5682S_I2S2_PIN_CFG_SFT, 1), + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_dac_l_mix, ARRAY_SIZE(rt5682s_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5682s_dac_r_mix, ARRAY_SIZE(rt5682s_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, &rt5682s_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, &rt5682s_alg_dac_r1_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5682S_PWR_DIG_2, + RT5682S_PWR_DAC_S1F_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_dac_l_mix, ARRAY_SIZE(rt5682s_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5682s_sto1_dac_r_mix, ARRAY_SIZE(rt5682s_sto1_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5682S_PWR_DIG_1, RT5682S_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5682S_PWR_DIG_1, RT5682S_PWR_DAC_R1_BIT, 0), + + /* HPO */ + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682s_hp_amp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + /* CLK DET */ + SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682S_CLK_DET, + RT5682S_SYS_CLK_DET_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5682S_CLK_DET, + RT5682S_PLL1_CLK_DET_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MCLK0 DET PWR", RT5682S_PWR_ANLG_2, + RT5682S_PWR_MCLK0_WD_BIT, 0, NULL, 0), + + /* SAR */ + SND_SOC_DAPM_SUPPLY("SAR", SND_SOC_NOPM, 0, 0, sar_power_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = { + /*PLL*/ + {"ADC Stereo1 Filter", NULL, "PLLA", is_sys_clk_from_plla}, + {"ADC Stereo1 Filter", NULL, "PLLB", is_sys_clk_from_pllb}, + {"DAC Stereo1 Filter", NULL, "PLLA", is_sys_clk_from_plla}, + {"DAC Stereo1 Filter", NULL, "PLLB", is_sys_clk_from_pllb}, + {"PLLA", NULL, "PLLA_LDO"}, + {"PLLA", NULL, "PLLA_BIAS"}, + {"PLLA", NULL, "PLLA_RST"}, + {"PLLB", NULL, "PLLB_LDO"}, + {"PLLB", NULL, "PLLB_BIAS"}, + {"PLLB", NULL, "PLLB_RST"}, + + /*ASRC*/ + {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, + {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, + {"ADC STO1 ASRC", NULL, "AD ASRC"}, + {"ADC STO1 ASRC", NULL, "DA ASRC"}, + {"DAC STO1 ASRC", NULL, "AD ASRC"}, + {"DAC STO1 ASRC", NULL, "DA ASRC"}, + + {"CLKDET SYS", NULL, "MCLK0 DET PWR"}, + + {"BST1 CBJ", NULL, "IN1P"}, + {"BST1 CBJ", NULL, "SAR", is_headset_type}, + + {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1L", NULL, "RECMIX1L Power"}, + {"RECMIX1R", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1R", NULL, "RECMIX1R Power"}, + + {"ADC1 L", NULL, "RECMIX1L"}, + {"ADC1 L", NULL, "ADC1 L Power"}, + {"ADC1 L", NULL, "ADC1 clock"}, + {"ADC1 R", NULL, "RECMIX1R"}, + {"ADC1 R", NULL, "ADC1 R Power"}, + {"ADC1 R", NULL, "ADC1 clock"}, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC1 Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC1 Power"}, + {"DMIC CLK", NULL, "DMIC ASRC"}, + + {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"}, + + {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"}, + {"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"}, + {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"}, + {"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"}, + + {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"}, + {"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"}, + {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"}, + {"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, + {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, + {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, + {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, + {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"}, + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"}, + + {"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + + {"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"}, + {"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"}, + {"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"}, + {"AIF1TX", NULL, "I2S1"}, + {"AIF1TX", NULL, "ADCDAT Mux"}, + {"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"}, + {"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"}, + {"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"}, + {"AIF2TX", NULL, "ADCDAT Mux"}, + + {"IF1 DAC1 L", NULL, "AIF1RX"}, + {"IF1 DAC1 L", NULL, "I2S1"}, + {"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"}, + {"IF1 DAC1 R", NULL, "AIF1RX"}, + {"IF1 DAC1 R", NULL, "I2S1"}, + {"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"}, + + {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"}, + {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"}, + + {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + + {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + + {"DAC L1 Source", "DAC1", "DAC1 MIXL"}, + {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC R1 Source", "DAC1", "DAC1 MIXR"}, + {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + + {"DAC L1", NULL, "DAC L1 Source"}, + {"DAC R1", NULL, "DAC R1 Source"}, + + {"HP Amp", NULL, "DAC L1"}, + {"HP Amp", NULL, "DAC R1"}, + {"HP Amp", NULL, "CLKDET SYS"}, + {"HP Amp", NULL, "SAR", is_headset_type}, + + {"HPOL", NULL, "HP Amp"}, + {"HPOR", NULL, "HP Amp"}, +}; + +static int rt5682s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + unsigned int cl, val = 0; + + if (tx_mask || rx_mask) + snd_soc_component_update_bits(component, + RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, RT5682S_TDM_EN); + else + snd_soc_component_update_bits(component, + RT5682S_TDM_ADDA_CTRL_2, RT5682S_TDM_EN, 0); + + switch (slots) { + case 4: + val |= RT5682S_TDM_TX_CH_4; + val |= RT5682S_TDM_RX_CH_4; + break; + case 6: + val |= RT5682S_TDM_TX_CH_6; + val |= RT5682S_TDM_RX_CH_6; + break; + case 8: + val |= RT5682S_TDM_TX_CH_8; + val |= RT5682S_TDM_RX_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_TDM_CTRL, + RT5682S_TDM_TX_CH_MASK | RT5682S_TDM_RX_CH_MASK, val); + + switch (slot_width) { + case 8: + if (tx_mask || rx_mask) + return -EINVAL; + cl = RT5682S_I2S1_TX_CHL_8 | RT5682S_I2S1_RX_CHL_8; + break; + case 16: + val = RT5682S_TDM_CL_16; + cl = RT5682S_I2S1_TX_CHL_16 | RT5682S_I2S1_RX_CHL_16; + break; + case 20: + val = RT5682S_TDM_CL_20; + cl = RT5682S_I2S1_TX_CHL_20 | RT5682S_I2S1_RX_CHL_20; + break; + case 24: + val = RT5682S_TDM_CL_24; + cl = RT5682S_I2S1_TX_CHL_24 | RT5682S_I2S1_RX_CHL_24; + break; + case 32: + val = RT5682S_TDM_CL_32; + cl = RT5682S_I2S1_TX_CHL_32 | RT5682S_I2S1_RX_CHL_32; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_CL_MASK, val); + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_TX_CHL_MASK | RT5682S_I2S1_RX_CHL_MASK, cl); + + return 0; +} + +static int rt5682s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int len_1 = 0, len_2 = 0; + int frame_size; + + rt5682s->lrck[dai->id] = params_rate(params); + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(component->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + break; + case 20: + len_1 |= RT5682S_I2S1_DL_20; + len_2 |= RT5682S_I2S2_DL_20; + break; + case 24: + len_1 |= RT5682S_I2S1_DL_24; + len_2 |= RT5682S_I2S2_DL_24; + break; + case 32: + len_1 |= RT5682S_I2S1_DL_32; + len_2 |= RT5682S_I2S2_DL_24; + break; + case 8: + len_1 |= RT5682S_I2S2_DL_8; + len_2 |= RT5682S_I2S2_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5682S_AIF1: + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_DL_MASK, len_1); + if (params_channels(params) == 1) /* mono mode */ + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_MONO_MASK, RT5682S_I2S1_MONO_EN); + else + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S1_MONO_MASK, RT5682S_I2S1_MONO_DIS); + break; + case RT5682S_AIF2: + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_DL_MASK, len_2); + if (params_channels(params) == 1) /* mono mode */ + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MONO_MASK, RT5682S_I2S2_MONO_EN); + else + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MONO_MASK, RT5682S_I2S2_MONO_DIS); + break; + default: + dev_err(component->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int reg_val = 0, tdm_ctrl = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5682s->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + rt5682s->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5682S_I2S_BP_INV; + tdm_ctrl |= RT5682S_TDM_S_BP_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + if (dai->id == RT5682S_AIF1) + tdm_ctrl |= RT5682S_TDM_S_LP_INV | RT5682S_TDM_M_BP_INV; + else + return -EINVAL; + break; + case SND_SOC_DAIFMT_IB_IF: + if (dai->id == RT5682S_AIF1) + tdm_ctrl |= RT5682S_TDM_S_BP_INV | RT5682S_TDM_S_LP_INV | + RT5682S_TDM_M_BP_INV | RT5682S_TDM_M_LP_INV; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5682S_I2S_DF_LEFT; + tdm_ctrl |= RT5682S_TDM_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5682S_I2S_DF_PCM_A; + tdm_ctrl |= RT5682S_TDM_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5682S_I2S_DF_PCM_B; + tdm_ctrl |= RT5682S_TDM_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5682S_AIF1: + snd_soc_component_update_bits(component, RT5682S_I2S1_SDP, + RT5682S_I2S_DF_MASK, reg_val); + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_MS_MASK | RT5682S_TDM_S_BP_MASK | + RT5682S_TDM_DF_MASK | RT5682S_TDM_M_BP_MASK | + RT5682S_TDM_M_LP_MASK | RT5682S_TDM_S_LP_MASK, + tdm_ctrl | rt5682s->master[dai->id]); + break; + case RT5682S_AIF2: + if (rt5682s->master[dai->id] == 0) + reg_val |= RT5682S_I2S2_MS_S; + snd_soc_component_update_bits(component, RT5682S_I2S2_SDP, + RT5682S_I2S2_MS_MASK | RT5682S_I2S_BP_MASK | + RT5682S_I2S_DF_MASK, reg_val); + break; + default: + dev_err(component->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5682s_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + unsigned int src = 0; + + if (freq == rt5682s->sysclk && clk_id == rt5682s->sysclk_src) + return 0; + + switch (clk_id) { + case RT5682S_SCLK_S_MCLK: + src = RT5682S_CLK_SRC_MCLK; + break; + case RT5682S_SCLK_S_PLL1: + src = RT5682S_CLK_SRC_PLL1; + break; + case RT5682S_SCLK_S_PLL2: + src = RT5682S_CLK_SRC_PLL2; + break; + case RT5682S_SCLK_S_RCCLK: + src = RT5682S_CLK_SRC_RCCLK; + break; + default: + dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_SCLK_SRC_MASK, src << RT5682S_SCLK_SRC_SFT); + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1, + RT5682S_I2S_M_CLK_SRC_MASK, src << RT5682S_I2S_M_CLK_SRC_SFT); + snd_soc_component_update_bits(component, RT5682S_I2S2_M_CLK_CTRL_1, + RT5682S_I2S2_M_CLK_SRC_MASK, src << RT5682S_I2S2_M_CLK_SRC_SFT); + + rt5682s->sysclk = freq; + rt5682s->sysclk_src = clk_id; + + dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n", + freq, clk_id); + + return 0; +} + +static const struct pll_calc_map plla_table[] = { + {2048000, 24576000, 0, 46, 2, true, false, false, false}, + {256000, 24576000, 0, 382, 2, true, false, false, false}, + {512000, 24576000, 0, 190, 2, true, false, false, false}, + {4096000, 24576000, 0, 22, 2, true, false, false, false}, + {1024000, 24576000, 0, 94, 2, true, false, false, false}, + {11289600, 22579200, 1, 22, 2, false, false, false, false}, + {1411200, 22579200, 0, 62, 2, true, false, false, false}, + {2822400, 22579200, 0, 30, 2, true, false, false, false}, + {12288000, 24576000, 1, 22, 2, false, false, false, false}, + {1536000, 24576000, 0, 62, 2, true, false, false, false}, + {3072000, 24576000, 0, 30, 2, true, false, false, false}, + {24576000, 49152000, 4, 22, 0, false, false, false, false}, + {3072000, 49152000, 0, 30, 0, true, false, false, false}, + {6144000, 49152000, 0, 30, 0, false, false, false, false}, + {49152000, 98304000, 10, 22, 0, false, true, false, false}, + {6144000, 98304000, 0, 30, 0, false, true, false, false}, + {12288000, 98304000, 1, 22, 0, false, true, false, false}, + {48000000, 3840000, 10, 22, 23, false, false, false, false}, + {24000000, 3840000, 4, 22, 23, false, false, false, false}, + {19200000, 3840000, 3, 23, 23, false, false, false, false}, + {38400000, 3840000, 8, 23, 23, false, false, false, false}, +}; + +static const struct pll_calc_map pllb_table[] = { + {48000000, 24576000, 8, 6, 3, false, false, false, false}, + {48000000, 22579200, 23, 12, 3, false, false, false, true}, + {24000000, 24576000, 3, 6, 3, false, false, false, false}, + {24000000, 22579200, 23, 26, 3, false, false, false, true}, + {19200000, 24576000, 2, 6, 3, false, false, false, false}, + {19200000, 22579200, 3, 5, 3, false, false, false, true}, + {38400000, 24576000, 6, 6, 3, false, false, false, false}, + {38400000, 22579200, 8, 5, 3, false, false, false, true}, + {3840000, 49152000, 0, 6, 0, true, false, false, false}, +}; + +static int find_pll_inter_combination(unsigned int f_in, unsigned int f_out, + struct pll_calc_map *a, struct pll_calc_map *b) +{ + int i, j; + + /* Look at PLLA table */ + for (i = 0; i < ARRAY_SIZE(plla_table); i++) { + if (plla_table[i].freq_in == f_in && plla_table[i].freq_out == f_out) { + memcpy(a, plla_table + i, sizeof(*a)); + return USE_PLLA; + } + } + + /* Look at PLLB table */ + for (i = 0; i < ARRAY_SIZE(pllb_table); i++) { + if (pllb_table[i].freq_in == f_in && pllb_table[i].freq_out == f_out) { + memcpy(b, pllb_table + i, sizeof(*b)); + return USE_PLLB; + } + } + + /* Find a combination of PLLA & PLLB */ + for (i = ARRAY_SIZE(plla_table) - 1; i >= 0; i--) { + if (plla_table[i].freq_in == f_in && plla_table[i].freq_out == 3840000) { + for (j = ARRAY_SIZE(pllb_table) - 1; j >= 0; j--) { + if (pllb_table[j].freq_in == 3840000 && + pllb_table[j].freq_out == f_out) { + memcpy(a, plla_table + i, sizeof(*a)); + memcpy(b, pllb_table + j, sizeof(*b)); + return USE_PLLAB; + } + } + } + } + + return -EINVAL; +} + +static int rt5682s_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, unsigned int freq_in, + unsigned int freq_out) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct pll_calc_map a_map, b_map; + + if (source == rt5682s->pll_src[pll_id] && freq_in == rt5682s->pll_in[pll_id] && + freq_out == rt5682s->pll_out[pll_id]) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(component->dev, "PLL disabled\n"); + rt5682s->pll_in[pll_id] = 0; + rt5682s->pll_out[pll_id] = 0; + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_SCLK_SRC_MASK, RT5682S_CLK_SRC_MCLK << RT5682S_SCLK_SRC_SFT); + return 0; + } + + switch (source) { + case RT5682S_PLL_S_MCLK: + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_PLL_SRC_MASK, RT5682S_PLL_SRC_MCLK); + break; + case RT5682S_PLL_S_BCLK1: + snd_soc_component_update_bits(component, RT5682S_GLB_CLK, + RT5682S_PLL_SRC_MASK, RT5682S_PLL_SRC_BCLK1); + break; + default: + dev_err(component->dev, "Unknown PLL Source %d\n", source); + return -EINVAL; + } + + rt5682s->pll_comb = find_pll_inter_combination(freq_in, freq_out, + &a_map, &b_map); + + if ((pll_id == RT5682S_PLL1 && rt5682s->pll_comb == USE_PLLA) || + (pll_id == RT5682S_PLL2 && (rt5682s->pll_comb == USE_PLLB || + rt5682s->pll_comb == USE_PLLAB))) { + dev_dbg(component->dev, + "Supported freq conversion for PLL%d:(%d->%d): %d\n", + pll_id + 1, freq_in, freq_out, rt5682s->pll_comb); + } else { + dev_err(component->dev, + "Unsupported freq conversion for PLL%d:(%d->%d): %d\n", + pll_id + 1, freq_in, freq_out, rt5682s->pll_comb); + return -EINVAL; + } + + if (rt5682s->pll_comb == USE_PLLA || rt5682s->pll_comb == USE_PLLAB) { + dev_dbg(component->dev, + "PLLA: fin=%d fout=%d m_bp=%d k_bp=%d m=%d n=%d k=%d\n", + a_map.freq_in, a_map.freq_out, a_map.m_bp, a_map.k_bp, + (a_map.m_bp ? 0 : a_map.m), a_map.n, (a_map.k_bp ? 0 : a_map.k)); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_1, + RT5682S_PLLA_N_MASK, a_map.n); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_2, + RT5682S_PLLA_M_MASK | RT5682S_PLLA_K_MASK, + a_map.m << RT5682S_PLLA_M_SFT | a_map.k); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_6, + RT5682S_PLLA_M_BP_MASK | RT5682S_PLLA_K_BP_MASK, + a_map.m_bp << RT5682S_PLLA_M_BP_SFT | + a_map.k_bp << RT5682S_PLLA_K_BP_SFT); + } + + if (rt5682s->pll_comb == USE_PLLB || rt5682s->pll_comb == USE_PLLAB) { + dev_dbg(component->dev, + "PLLB: fin=%d fout=%d m_bp=%d k_bp=%d m=%d n=%d k=%d byp_ps=%d sel_ps=%d\n", + b_map.freq_in, b_map.freq_out, b_map.m_bp, b_map.k_bp, + (b_map.m_bp ? 0 : b_map.m), b_map.n, (b_map.k_bp ? 0 : b_map.k), + b_map.byp_ps, b_map.sel_ps); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_3, + RT5682S_PLLB_N_MASK, b_map.n); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_4, + RT5682S_PLLB_M_MASK | RT5682S_PLLB_K_MASK, + b_map.m << RT5682S_PLLB_M_SFT | b_map.k); + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_6, + RT5682S_PLLB_SEL_PS_MASK | RT5682S_PLLB_BYP_PS_MASK | + RT5682S_PLLB_M_BP_MASK | RT5682S_PLLB_K_BP_MASK, + b_map.sel_ps << RT5682S_PLLB_SEL_PS_SFT | + b_map.byp_ps << RT5682S_PLLB_BYP_PS_SFT | + b_map.m_bp << RT5682S_PLLB_M_BP_SFT | + b_map.k_bp << RT5682S_PLLB_K_BP_SFT); + } + + if (rt5682s->pll_comb == USE_PLLB) + snd_soc_component_update_bits(component, RT5682S_PLL_CTRL_7, + RT5682S_PLLB_SRC_MASK, RT5682S_PLLB_SRC_DFIN); + + rt5682s->pll_in[pll_id] = freq_in; + rt5682s->pll_out[pll_id] = freq_out; + rt5682s->pll_src[pll_id] = source; + + return 0; +} + +static int rt5682s_set_bclk1_ratio(struct snd_soc_dai *dai, + unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s->bclk[dai->id] = ratio; + + switch (ratio) { + case 256: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_256); + break; + case 128: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_128); + break; + case 64: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_64); + break; + case 32: + snd_soc_component_update_bits(component, RT5682S_TDM_TCON_CTRL_1, + RT5682S_TDM_BCLK_MS1_MASK, RT5682S_TDM_BCLK_MS1_32); + break; + default: + dev_err(dai->dev, "Invalid bclk1 ratio %d\n", ratio); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_bclk2_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s->bclk[dai->id] = ratio; + + switch (ratio) { + case 64: + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_2, + RT5682S_I2S2_BCLK_MS2_MASK, RT5682S_I2S2_BCLK_MS2_64); + break; + case 32: + snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_2, + RT5682S_I2S2_BCLK_MS2_MASK, RT5682S_I2S2_BCLK_MS2_32); + break; + default: + dev_err(dai->dev, "Invalid bclk2 ratio %d\n", ratio); + return -EINVAL; + } + + return 0; +} + +static int rt5682s_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_PWR_LDO, RT5682S_PWR_LDO); + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, + RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0); + break; + case SND_SOC_BIAS_ON: + break; + } + + return 0; +} + +#ifdef CONFIG_COMMON_CLK +#define CLK_PLL2_FIN 48000000 +#define CLK_48 48000 +#define CLK_44 44100 + +static bool rt5682s_clk_check(struct rt5682s_priv *rt5682s) +{ + if (!rt5682s->master[RT5682S_AIF1]) { + dev_dbg(rt5682s->component->dev, "dai clk fmt not set correctly\n"); + return false; + } + return true; +} + +static int rt5682s_wclk_prepare(struct clk_hw *hw) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_MB, RT5682S_PWR_MB); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2"); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_FV2, RT5682S_PWR_FV2); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1"); + /* Only need to power PLLB due to the rate set restriction */ + snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB"); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); + + return 0; +} + +static void rt5682s_wclk_unprepare(struct clk_hw *hw) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + if (!rt5682s_clk_check(rt5682s)) + return; + + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2"); + if (!rt5682s->jack_type) + snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, + RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0); + + snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1"); + snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB"); + snd_soc_dapm_sync_unlocked(dapm); + + snd_soc_dapm_mutex_unlock(dapm); +} + +static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682s_clk_check(rt5682s)) + return 0; + /* + * Only accept to set wclk rate to 44.1k or 48kHz. + */ + if (rt5682s->lrck[RT5682S_AIF1] != CLK_48 && + rt5682s->lrck[RT5682S_AIF1] != CLK_44) { + dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + return 0; + } + + return rt5682s->lrck[RT5682S_AIF1]; +} + +static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + /* + * Only accept to set wclk rate to 44.1k or 48kHz. + * It will force to 48kHz if not both. + */ + if (rate != CLK_48 && rate != CLK_44) { + dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + rate = CLK_48; + } + + return rate; +} + +static int rt5682s_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct clk *parent_clk; + const char * const clk_name = clk_hw_get_name(hw); + unsigned int clk_pll2_fout; + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + /* + * Whether the wclk's parent clk (mclk) exists or not, please ensure + * it is fixed or set to 48MHz before setting wclk rate. It's a + * temporary limitation. Only accept 48MHz clk as the clk provider. + * + * It will set the codec anyway by assuming mclk is 48MHz. + */ + parent_clk = clk_get_parent(hw->clk); + if (!parent_clk) + dev_warn(component->dev, + "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n", + CLK_PLL2_FIN); + + if (parent_rate != CLK_PLL2_FIN) + dev_warn(component->dev, "clk %s only support %d Hz input\n", + clk_name, CLK_PLL2_FIN); + + /* + * To achieve the rate conversion from 48MHz to 44.1k or 48kHz, + * PLL2 is needed. + */ + clk_pll2_fout = rate * 512; + rt5682s_set_component_pll(component, RT5682S_PLL2, RT5682S_PLL_S_MCLK, + CLK_PLL2_FIN, clk_pll2_fout); + + rt5682s_set_component_sysclk(component, RT5682S_SCLK_S_PLL2, 0, + clk_pll2_fout, SND_SOC_CLOCK_IN); + + rt5682s->lrck[RT5682S_AIF1] = rate; + + return 0; +} + +static unsigned long rt5682s_bclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + unsigned int bclks_per_wclk; + + bclks_per_wclk = snd_soc_component_read(component, RT5682S_TDM_TCON_CTRL_1); + + switch (bclks_per_wclk & RT5682S_TDM_BCLK_MS1_MASK) { + case RT5682S_TDM_BCLK_MS1_256: + return parent_rate * 256; + case RT5682S_TDM_BCLK_MS1_128: + return parent_rate * 128; + case RT5682S_TDM_BCLK_MS1_64: + return parent_rate * 64; + case RT5682S_TDM_BCLK_MS1_32: + return parent_rate * 32; + default: + return 0; + } +} + +static unsigned long rt5682s_bclk_get_factor(unsigned long rate, + unsigned long parent_rate) +{ + unsigned long factor; + + factor = rate / parent_rate; + if (factor < 64) + return 32; + else if (factor < 128) + return 64; + else if (factor < 256) + return 128; + else + return 256; +} + +static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + unsigned long factor; + + if (!*parent_rate || !rt5682s_clk_check(rt5682s)) + return -EINVAL; + + /* + * BCLK rates are set as a multiplier of WCLK in HW. + * We don't allow changing the parent WCLK. We just do + * some rounding down based on the parent WCLK rate + * and find the appropriate multiplier of BCLK to + * get the rounded down BCLK value. + */ + factor = rt5682s_bclk_get_factor(rate, *parent_rate); + + return *parent_rate * factor; +} + +static int rt5682s_bclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rt5682s_priv *rt5682s = + container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]); + struct snd_soc_component *component = rt5682s->component; + struct snd_soc_dai *dai; + unsigned long factor; + + if (!rt5682s_clk_check(rt5682s)) + return -EINVAL; + + factor = rt5682s_bclk_get_factor(rate, parent_rate); + + for_each_component_dais(component, dai) + if (dai->id == RT5682S_AIF1) + break; + if (!dai) { + dev_err(component->dev, "dai %d not found in component\n", + RT5682S_AIF1); + return -ENODEV; + } + + return rt5682s_set_bclk1_ratio(dai, factor); +} + +static const struct clk_ops rt5682s_dai_clk_ops[RT5682S_DAI_NUM_CLKS] = { + [RT5682S_DAI_WCLK_IDX] = { + .prepare = rt5682s_wclk_prepare, + .unprepare = rt5682s_wclk_unprepare, + .recalc_rate = rt5682s_wclk_recalc_rate, + .round_rate = rt5682s_wclk_round_rate, + .set_rate = rt5682s_wclk_set_rate, + }, + [RT5682S_DAI_BCLK_IDX] = { + .recalc_rate = rt5682s_bclk_recalc_rate, + .round_rate = rt5682s_bclk_round_rate, + .set_rate = rt5682s_bclk_set_rate, + }, +}; + +static int rt5682s_register_dai_clks(struct snd_soc_component *component) +{ + struct device *dev = component->dev; + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct rt5682s_platform_data *pdata = &rt5682s->pdata; + struct clk_hw *dai_clk_hw; + int i, ret; + + for (i = 0; i < RT5682S_DAI_NUM_CLKS; ++i) { + struct clk_init_data init = { }; + + dai_clk_hw = &rt5682s->dai_clks_hw[i]; + + switch (i) { + case RT5682S_DAI_WCLK_IDX: + /* Make MCLK the parent of WCLK */ + if (rt5682s->mclk) { + init.parent_data = &(struct clk_parent_data){ + .fw_name = "mclk", + }; + init.num_parents = 1; + } + break; + case RT5682S_DAI_BCLK_IDX: + /* Make WCLK the parent of BCLK */ + init.parent_hws = &(const struct clk_hw *){ + &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX] + }; + init.num_parents = 1; + break; + default: + dev_err(dev, "Invalid clock index\n"); + return -EINVAL; + } + + init.name = pdata->dai_clk_names[i]; + init.ops = &rt5682s_dai_clk_ops[i]; + init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; + dai_clk_hw->init = &init; + + ret = devm_clk_hw_register(dev, dai_clk_hw); + if (ret) { + dev_warn(dev, "Failed to register %s: %d\n", init.name, ret); + return ret; + } + + if (dev->of_node) { + devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + } else { + ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, + init.name, dev_name(dev)); + if (ret) + return ret; + } + } + + return 0; +} + +static int rt5682s_dai_probe_clks(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + int ret; + + /* Check if MCLK provided */ + rt5682s->mclk = devm_clk_get(component->dev, "mclk"); + if (IS_ERR(rt5682s->mclk)) { + if (PTR_ERR(rt5682s->mclk) != -ENOENT) { + ret = PTR_ERR(rt5682s->mclk); + return ret; + } + rt5682s->mclk = NULL; + } + + /* Register CCF DAI clock control */ + ret = rt5682s_register_dai_clks(component); + if (ret) + return ret; + + /* Initial setup for CCF */ + rt5682s->lrck[RT5682S_AIF1] = CLK_48; + + return 0; +} +#else +static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component) +{ + return 0; +} +#endif /* CONFIG_COMMON_CLK */ + +static int rt5682s_probe(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = &component->dapm; + int ret; + + rt5682s->component = component; + + ret = rt5682s_dai_probe_clks(component); + if (ret) + return ret; + + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin(dapm, "Vref2"); + snd_soc_dapm_sync(dapm); + return 0; +} + +static void rt5682s_remove(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + rt5682s_reset(rt5682s); +} + +#ifdef CONFIG_PM +static int rt5682s_suspend(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + if (rt5682s->hs_jack && rt5682s->jack_type == SND_JACK_HEADSET) + snd_soc_component_update_bits(component, RT5682S_4BTN_IL_CMD_2, + RT5682S_4BTN_IL_MASK, RT5682S_4BTN_IL_DIS); + + regcache_cache_only(rt5682s->regmap, true); + regcache_mark_dirty(rt5682s->regmap); + + return 0; +} + +static int rt5682s_resume(struct snd_soc_component *component) +{ + struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt5682s->regmap, false); + regcache_sync(rt5682s->regmap); + + if (rt5682s->hs_jack) { + rt5682s->jack_type = 0; + mod_delayed_work(system_power_efficient_wq, + &rt5682s->jack_detect_work, msecs_to_jiffies(250)); + } + + return 0; +} +#else +#define rt5682s_suspend NULL +#define rt5682s_resume NULL +#endif + +const struct snd_soc_dai_ops rt5682s_aif1_dai_ops = { + .hw_params = rt5682s_hw_params, + .set_fmt = rt5682s_set_dai_fmt, + .set_tdm_slot = rt5682s_set_tdm_slot, + .set_bclk_ratio = rt5682s_set_bclk1_ratio, +}; + +static const struct snd_soc_dai_ops rt5682s_aif2_dai_ops = { + .hw_params = rt5682s_hw_params, + .set_fmt = rt5682s_set_dai_fmt, + .set_bclk_ratio = rt5682s_set_bclk2_ratio, +}; + +static const struct snd_soc_component_driver rt5682s_soc_component_dev = { + .probe = rt5682s_probe, + .remove = rt5682s_remove, + .suspend = rt5682s_suspend, + .resume = rt5682s_resume, + .set_bias_level = rt5682s_set_bias_level, + .controls = rt5682s_snd_controls, + .num_controls = ARRAY_SIZE(rt5682s_snd_controls), + .dapm_widgets = rt5682s_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5682s_dapm_widgets), + .dapm_routes = rt5682s_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5682s_dapm_routes), + .set_sysclk = rt5682s_set_component_sysclk, + .set_pll = rt5682s_set_component_pll, + .set_jack = rt5682s_set_jack_detect, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) +{ + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5682s->pdata.dmic1_data_pin); + device_property_read_u32(dev, "realtek,dmic1-clk-pin", + &rt5682s->pdata.dmic1_clk_pin); + device_property_read_u32(dev, "realtek,jd-src", + &rt5682s->pdata.jd_src); + device_property_read_u32(dev, "realtek,dmic-clk-rate-hz", + &rt5682s->pdata.dmic_clk_rate); + device_property_read_u32(dev, "realtek,dmic-delay-ms", + &rt5682s->pdata.dmic_delay); + + rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, + "realtek,ldo1-en-gpios", 0); + + if (device_property_read_string_array(dev, "clock-output-names", + rt5682s->pdata.dai_clk_names, + RT5682S_DAI_NUM_CLKS) < 0) + dev_warn(dev, "Using default DAI clk names: %s, %s\n", + rt5682s->pdata.dai_clk_names[RT5682S_DAI_WCLK_IDX], + rt5682s->pdata.dai_clk_names[RT5682S_DAI_BCLK_IDX]); + + rt5682s->pdata.dmic_clk_driving_high = device_property_read_bool(dev, + "realtek,dmic-clk-driving-high"); + + return 0; +} + +static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) +{ + unsigned int count, value; + + mutex_lock(&rt5682s->calibrate_mutex); + + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80); + usleep_range(15000, 20000); + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xfa80); + regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x01c0); + regmap_write(rt5682s->regmap, RT5682S_MICBIAS_2, 0x0380); + regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x8000); + regmap_write(rt5682s->regmap, RT5682S_ADDA_CLK_1, 0x1001); + regmap_write(rt5682s->regmap, RT5682S_CHOP_DAC_2, 0x3030); + regmap_write(rt5682s->regmap, RT5682S_CHOP_ADC, 0xb000); + regmap_write(rt5682s->regmap, RT5682S_STO1_ADC_MIXER, 0x686c); + regmap_write(rt5682s->regmap, RT5682S_CAL_REC, 0x5151); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_2, 0x0321); + regmap_write(rt5682s->regmap, RT5682S_HP_LOGIC_CTRL_2, 0x0004); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_1, 0x7c00); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_1, 0xfc00); + + for (count = 0; count < 60; count++) { + regmap_read(rt5682s->regmap, RT5682S_HP_CALIB_ST_1, &value); + if (!(value & 0x8000)) + break; + + usleep_range(10000, 10005); + } + + if (count >= 60) + dev_err(rt5682s->component->dev, "HP Calibration Failure\n"); + + /* restore settings */ + regmap_write(rt5682s->regmap, RT5682S_MICBIAS_2, 0x0180); + regmap_write(rt5682s->regmap, RT5682S_CAL_REC, 0x5858); + regmap_write(rt5682s->regmap, RT5682S_STO1_ADC_MIXER, 0xc0c4); + regmap_write(rt5682s->regmap, RT5682S_HP_CALIB_CTRL_2, 0x0320); + regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0); + regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800); + regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000); + + mutex_unlock(&rt5682s->calibrate_mutex); +} + +static const struct regmap_config rt5682s_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = RT5682S_MAX_REG, + .volatile_reg = rt5682s_volatile_register, + .readable_reg = rt5682s_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5682s_reg, + .num_reg_defaults = ARRAY_SIZE(rt5682s_reg), + .use_single_read = true, + .use_single_write = true, +}; + +static struct snd_soc_dai_driver rt5682s_dai[] = { + { + .name = "rt5682s-aif1", + .id = RT5682S_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .ops = &rt5682s_aif1_dai_ops, + }, + { + .name = "rt5682s-aif2", + .id = RT5682S_AIF2, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682S_STEREO_RATES, + .formats = RT5682S_FORMATS, + }, + .ops = &rt5682s_aif2_dai_ops, + }, +}; + +static void rt5682s_i2c_disable_regulators(void *data) +{ + struct rt5682s_priv *rt5682s = data; + + regulator_bulk_disable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); +} + +static int rt5682s_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5682s_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5682s_priv *rt5682s; + int i, ret; + unsigned int val; + + rt5682s = devm_kzalloc(&i2c->dev, sizeof(struct rt5682s_priv), GFP_KERNEL); + if (!rt5682s) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5682s); + + rt5682s->pdata = i2s_default_platform_data; + + if (pdata) + rt5682s->pdata = *pdata; + else + rt5682s_parse_dt(rt5682s, &i2c->dev); + + rt5682s->regmap = devm_regmap_init_i2c(i2c, &rt5682s_regmap); + if (IS_ERR(rt5682s->regmap)) { + ret = PTR_ERR(rt5682s->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(rt5682s->supplies); i++) + rt5682s->supplies[i].supply = rt5682s_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&i2c->dev, rt5682s_i2c_disable_regulators, rt5682s); + if (ret) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5682s->supplies), rt5682s->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { + if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, + GPIOF_OUT_INIT_HIGH, "rt5682s")) + dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + } + + /* Sleep for 50 ms minimum */ + usleep_range(50000, 55000); + + regmap_read(rt5682s->regmap, RT5682S_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, "Device with ID register %x is not rt5682s\n", val); + return -ENODEV; + } + + rt5682s_reset(rt5682s); + rt5682s_apply_patch_list(rt5682s, &i2c->dev); + + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_2, + RT5682S_DLDO_I_LIMIT_MASK, RT5682S_DLDO_I_LIMIT_DIS); + usleep_range(20000, 25000); + + mutex_init(&rt5682s->calibrate_mutex); + mutex_init(&rt5682s->sar_mutex); + rt5682s_calibrate(rt5682s); + + regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2, + RT5682S_PWR_CLK25M_MASK | RT5682S_PWR_CLK1M_MASK, + RT5682S_PWR_CLK25M_PD | RT5682S_PWR_CLK1M_PU); + regmap_update_bits(rt5682s->regmap, RT5682S_PWR_ANLG_1, + RT5682S_PWR_BG, RT5682S_PWR_BG); + regmap_update_bits(rt5682s->regmap, RT5682S_HP_LOGIC_CTRL_2, + RT5682S_HP_SIG_SRC_MASK, RT5682S_HP_SIG_SRC_1BIT_CTL); + regmap_update_bits(rt5682s->regmap, RT5682S_HP_CHARGE_PUMP_2, + RT5682S_PM_HP_MASK, RT5682S_PM_HP_HV); + + /* DMIC data pin */ + switch (rt5682s->pdata.dmic1_data_pin) { + case RT5682S_DMIC1_DATA_NULL: + break; + case RT5682S_DMIC1_DATA_GPIO2: /* share with LRCK2 */ + regmap_update_bits(rt5682s->regmap, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_1_DP_MASK, RT5682S_DMIC_1_DP_GPIO2); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP2_PIN_MASK, RT5682S_GP2_PIN_DMIC_SDA); + break; + case RT5682S_DMIC1_DATA_GPIO5: /* share with DACDAT1 */ + regmap_update_bits(rt5682s->regmap, RT5682S_DMIC_CTRL_1, + RT5682S_DMIC_1_DP_MASK, RT5682S_DMIC_1_DP_GPIO5); + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP5_PIN_MASK, RT5682S_GP5_PIN_DMIC_SDA); + break; + default: + dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n"); + break; + } + + /* DMIC clk pin */ + switch (rt5682s->pdata.dmic1_clk_pin) { + case RT5682S_DMIC1_CLK_NULL: + break; + case RT5682S_DMIC1_CLK_GPIO1: /* share with IRQ */ + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP1_PIN_MASK, RT5682S_GP1_PIN_DMIC_CLK); + break; + case RT5682S_DMIC1_CLK_GPIO3: /* share with BCLK2 */ + regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1, + RT5682S_GP3_PIN_MASK, RT5682S_GP3_PIN_DMIC_CLK); + if (rt5682s->pdata.dmic_clk_driving_high) + regmap_update_bits(rt5682s->regmap, RT5682S_PAD_DRIVING_CTRL, + RT5682S_PAD_DRV_GP3_MASK, RT5682S_PAD_DRV_GP3_HIGH); + break; + default: + dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n"); + break; + } + + INIT_DELAYED_WORK(&rt5682s->jack_detect_work, rt5682s_jack_detect_handler); + INIT_DELAYED_WORK(&rt5682s->jd_check_work, rt5682s_jd_check_handler); + + if (i2c->irq) { + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rt5682s_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "rt5682s", rt5682s); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + } + + return devm_snd_soc_register_component(&i2c->dev, &rt5682s_soc_component_dev, + rt5682s_dai, ARRAY_SIZE(rt5682s_dai)); +} + +static void rt5682s_i2c_shutdown(struct i2c_client *client) +{ + struct rt5682s_priv *rt5682s = i2c_get_clientdata(client); + + disable_irq(client->irq); + cancel_delayed_work_sync(&rt5682s->jack_detect_work); + cancel_delayed_work_sync(&rt5682s->jd_check_work); + + rt5682s_reset(rt5682s); +} + +static int rt5682s_i2c_remove(struct i2c_client *client) +{ + rt5682s_i2c_shutdown(client); + + return 0; +} + +static const struct of_device_id rt5682s_of_match[] = { + {.compatible = "realtek,rt5682s"}, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5682s_of_match); + +static const struct acpi_device_id rt5682s_acpi_match[] = { + {"RTL5682", 0,}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5682s_acpi_match); + +static const struct i2c_device_id rt5682s_i2c_id[] = { + {"rt5682s", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5682s_i2c_id); + +static struct i2c_driver rt5682s_i2c_driver = { + .driver = { + .name = "rt5682s", + .of_match_table = rt5682s_of_match, + .acpi_match_table = rt5682s_acpi_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = rt5682s_i2c_probe, + .remove = rt5682s_i2c_remove, + .shutdown = rt5682s_i2c_shutdown, + .id_table = rt5682s_i2c_id, +}; +module_i2c_driver(rt5682s_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5682I-VS driver"); +MODULE_AUTHOR("Derek Fang <derek.fang@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h new file mode 100644 index 00000000000000..7c755e5efb81f2 --- /dev/null +++ b/sound/soc/codecs/rt5682s.h @@ -0,0 +1,1455 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt5682s.h -- RT5682I-VS ALSA SoC audio driver + * + * Copyright 2021 Realtek Microelectronics + * Author: Derek Fang <derek.fang@realtek.com> + */ + +#ifndef __RT5682S_H__ +#define __RT5682S_H__ + +#include <sound/rt5682s.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> + + +/* Info */ +#define RT5682S_RESET 0x0000 +#define RT5682S_VERSION_ID 0x00fd +#define RT5682S_VENDOR_ID 0x00fe +#define RT5682S_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5682S_HP_CTRL_1 0x0002 +#define RT5682S_HP_CTRL_2 0x0003 +#define RT5682S_HPL_GAIN 0x0005 +#define RT5682S_HPR_GAIN 0x0006 + +#define RT5682S_I2C_CTRL 0x0008 + +/* I/O - Input */ +#define RT5682S_CBJ_BST_CTRL 0x000b +#define RT5682S_CBJ_DET_CTRL 0x000f +#define RT5682S_CBJ_CTRL_1 0x0010 +#define RT5682S_CBJ_CTRL_2 0x0011 +#define RT5682S_CBJ_CTRL_3 0x0012 +#define RT5682S_CBJ_CTRL_4 0x0013 +#define RT5682S_CBJ_CTRL_5 0x0014 +#define RT5682S_CBJ_CTRL_6 0x0015 +#define RT5682S_CBJ_CTRL_7 0x0016 +#define RT5682S_CBJ_CTRL_8 0x0017 +/* I/O - ADC/DAC/DMIC */ +#define RT5682S_DAC1_DIG_VOL 0x0019 +#define RT5682S_STO1_ADC_DIG_VOL 0x001c +#define RT5682S_STO1_ADC_BOOST 0x001f +#define RT5682S_HP_IMP_GAIN_1 0x0022 +#define RT5682S_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5682S_SIDETONE_CTRL 0x0024 +#define RT5682S_STO1_ADC_MIXER 0x0026 +#define RT5682S_AD_DA_MIXER 0x0029 +#define RT5682S_STO1_DAC_MIXER 0x002a +#define RT5682S_A_DAC1_MUX 0x002b +#define RT5682S_DIG_INF2_DATA 0x0030 +/* Mixer - ADC */ +#define RT5682S_REC_MIXER 0x003c +#define RT5682S_CAL_REC 0x0044 +/* HP Analog Offset Control */ +#define RT5682S_HP_ANA_OST_CTRL_1 0x004b +#define RT5682S_HP_ANA_OST_CTRL_2 0x004c +#define RT5682S_HP_ANA_OST_CTRL_3 0x004d +/* Power */ +#define RT5682S_PWR_DIG_1 0x0061 +#define RT5682S_PWR_DIG_2 0x0062 +#define RT5682S_PWR_ANLG_1 0x0063 +#define RT5682S_PWR_ANLG_2 0x0064 +#define RT5682S_PWR_ANLG_3 0x0065 +#define RT5682S_PWR_MIXER 0x0066 + +#define RT5682S_MB_CTRL 0x0067 +#define RT5682S_CLK_GATE_TCON_1 0x0068 +#define RT5682S_CLK_GATE_TCON_2 0x0069 +#define RT5682S_CLK_GATE_TCON_3 0x006a +/* Clock Detect */ +#define RT5682S_CLK_DET 0x006b +/* Filter Auto Reset */ +#define RT5682S_RESET_LPF_CTRL 0x006c +#define RT5682S_RESET_HPF_CTRL 0x006d +/* DMIC */ +#define RT5682S_DMIC_CTRL_1 0x006e +#define RT5682S_LPF_AD_DMIC 0x006f +/* Format - ADC/DAC */ +#define RT5682S_I2S1_SDP 0x0070 +#define RT5682S_I2S2_SDP 0x0071 +#define RT5682S_ADDA_CLK_1 0x0073 +#define RT5682S_ADDA_CLK_2 0x0074 +#define RT5682S_I2S1_F_DIV_CTRL_1 0x0075 +#define RT5682S_I2S1_F_DIV_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5682S_TDM_CTRL 0x0079 +#define RT5682S_TDM_ADDA_CTRL_1 0x007a +#define RT5682S_TDM_ADDA_CTRL_2 0x007b +#define RT5682S_DATA_SEL_CTRL_1 0x007c +#define RT5682S_TDM_TCON_CTRL_1 0x007e +#define RT5682S_TDM_TCON_CTRL_2 0x007f +/* Function - Analog */ +#define RT5682S_GLB_CLK 0x0080 +#define RT5682S_PLL_TRACK_1 0x0083 +#define RT5682S_PLL_TRACK_2 0x0084 +#define RT5682S_PLL_TRACK_3 0x0085 +#define RT5682S_PLL_TRACK_4 0x0086 +#define RT5682S_PLL_TRACK_5 0x0087 +#define RT5682S_PLL_TRACK_6 0x0088 +#define RT5682S_PLL_TRACK_11 0x008c +#define RT5682S_DEPOP_1 0x008e +#define RT5682S_HP_CHARGE_PUMP_1 0x008f +#define RT5682S_HP_CHARGE_PUMP_2 0x0091 +#define RT5682S_HP_CHARGE_PUMP_3 0x0092 +#define RT5682S_MICBIAS_1 0x0093 +#define RT5682S_MICBIAS_2 0x0094 +#define RT5682S_MICBIAS_3 0x0095 + +#define RT5682S_PLL_TRACK_12 0x0096 +#define RT5682S_PLL_TRACK_14 0x0097 +#define RT5682S_PLL_CTRL_1 0x0098 +#define RT5682S_PLL_CTRL_2 0x0099 +#define RT5682S_PLL_CTRL_3 0x009a +#define RT5682S_PLL_CTRL_4 0x009b +#define RT5682S_PLL_CTRL_5 0x009c +#define RT5682S_PLL_CTRL_6 0x009d +#define RT5682S_PLL_CTRL_7 0x009e + +#define RT5682S_RC_CLK_CTRL 0x009f +#define RT5682S_I2S2_M_CLK_CTRL_1 0x00a0 +#define RT5682S_I2S2_F_DIV_CTRL_1 0x00a3 +#define RT5682S_I2S2_F_DIV_CTRL_2 0x00a4 + +#define RT5682S_IRQ_CTRL_1 0x00b6 +#define RT5682S_IRQ_CTRL_2 0x00b7 +#define RT5682S_IRQ_CTRL_3 0x00b8 +#define RT5682S_IRQ_CTRL_4 0x00b9 +#define RT5682S_INT_ST_1 0x00be +#define RT5682S_GPIO_CTRL_1 0x00c0 +#define RT5682S_GPIO_CTRL_2 0x00c1 +#define RT5682S_GPIO_ST 0x00c2 +#define RT5682S_HP_AMP_DET_CTRL_1 0x00d0 +#define RT5682S_MID_HP_AMP_DET 0x00d2 +#define RT5682S_LOW_HP_AMP_DET 0x00d3 +#define RT5682S_DELAY_BUF_CTRL 0x00d4 +#define RT5682S_SV_ZCD_1 0x00d9 +#define RT5682S_SV_ZCD_2 0x00da +#define RT5682S_IL_CMD_1 0x00db +#define RT5682S_IL_CMD_2 0x00dc +#define RT5682S_IL_CMD_3 0x00dd +#define RT5682S_IL_CMD_4 0x00de +#define RT5682S_IL_CMD_5 0x00df +#define RT5682S_IL_CMD_6 0x00e0 +#define RT5682S_4BTN_IL_CMD_1 0x00e2 +#define RT5682S_4BTN_IL_CMD_2 0x00e3 +#define RT5682S_4BTN_IL_CMD_3 0x00e4 +#define RT5682S_4BTN_IL_CMD_4 0x00e5 +#define RT5682S_4BTN_IL_CMD_5 0x00e6 +#define RT5682S_4BTN_IL_CMD_6 0x00e7 +#define RT5682S_4BTN_IL_CMD_7 0x00e8 + +#define RT5682S_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5682S_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5682S_AJD1_CTRL 0x00f0 +#define RT5682S_JD_CTRL_1 0x00f6 +/* General Control */ +#define RT5682S_DUMMY_1 0x00fa +#define RT5682S_DUMMY_2 0x00fb +#define RT5682S_DUMMY_3 0x00fc + +#define RT5682S_DAC_ADC_DIG_VOL1 0x0100 +#define RT5682S_BIAS_CUR_CTRL_2 0x010b +#define RT5682S_BIAS_CUR_CTRL_3 0x010c +#define RT5682S_BIAS_CUR_CTRL_4 0x010d +#define RT5682S_BIAS_CUR_CTRL_5 0x010e +#define RT5682S_BIAS_CUR_CTRL_6 0x010f +#define RT5682S_BIAS_CUR_CTRL_7 0x0110 +#define RT5682S_BIAS_CUR_CTRL_8 0x0111 +#define RT5682S_BIAS_CUR_CTRL_9 0x0112 +#define RT5682S_BIAS_CUR_CTRL_10 0x0113 +#define RT5682S_VREF_REC_OP_FB_CAP_CTRL_1 0x0117 +#define RT5682S_VREF_REC_OP_FB_CAP_CTRL_2 0x0118 +#define RT5682S_CHARGE_PUMP_1 0x0125 +#define RT5682S_DIG_IN_CTRL_1 0x0132 +#define RT5682S_PAD_DRIVING_CTRL 0x0136 +#define RT5682S_CHOP_DAC_1 0x0139 +#define RT5682S_CHOP_DAC_2 0x013a +#define RT5682S_CHOP_ADC 0x013b +#define RT5682S_CALIB_ADC_CTRL 0x013c +#define RT5682S_VOL_TEST 0x013f +#define RT5682S_SPKVDD_DET_ST 0x0142 +#define RT5682S_TEST_MODE_CTRL_1 0x0145 +#define RT5682S_TEST_MODE_CTRL_2 0x0146 +#define RT5682S_TEST_MODE_CTRL_3 0x0147 +#define RT5682S_TEST_MODE_CTRL_4 0x0148 +#define RT5682S_PLL_INTERNAL_1 0x0156 +#define RT5682S_PLL_INTERNAL_2 0x0157 +#define RT5682S_PLL_INTERNAL_3 0x0158 +#define RT5682S_PLL_INTERNAL_4 0x0159 +#define RT5682S_STO_NG2_CTRL_1 0x0160 +#define RT5682S_STO_NG2_CTRL_2 0x0161 +#define RT5682S_STO_NG2_CTRL_3 0x0162 +#define RT5682S_STO_NG2_CTRL_4 0x0163 +#define RT5682S_STO_NG2_CTRL_5 0x0164 +#define RT5682S_STO_NG2_CTRL_6 0x0165 +#define RT5682S_STO_NG2_CTRL_7 0x0166 +#define RT5682S_STO_NG2_CTRL_8 0x0167 +#define RT5682S_STO_NG2_CTRL_9 0x0168 +#define RT5682S_STO_NG2_CTRL_10 0x0169 +#define RT5682S_STO1_DAC_SIL_DET 0x0190 +#define RT5682S_SIL_PSV_CTRL1 0x0194 +#define RT5682S_SIL_PSV_CTRL2 0x0195 +#define RT5682S_SIL_PSV_CTRL3 0x0197 +#define RT5682S_SIL_PSV_CTRL4 0x0198 +#define RT5682S_SIL_PSV_CTRL5 0x0199 +#define RT5682S_HP_IMP_SENS_CTRL_1 0x01ac +#define RT5682S_HP_IMP_SENS_CTRL_2 0x01ad +#define RT5682S_HP_IMP_SENS_CTRL_3 0x01ae +#define RT5682S_HP_IMP_SENS_CTRL_4 0x01af +#define RT5682S_HP_IMP_SENS_CTRL_5 0x01b0 +#define RT5682S_HP_IMP_SENS_CTRL_6 0x01b1 +#define RT5682S_HP_IMP_SENS_CTRL_7 0x01b2 +#define RT5682S_HP_IMP_SENS_CTRL_8 0x01b3 +#define RT5682S_HP_IMP_SENS_CTRL_9 0x01b4 +#define RT5682S_HP_IMP_SENS_CTRL_10 0x01b5 +#define RT5682S_HP_IMP_SENS_CTRL_11 0x01b6 +#define RT5682S_HP_IMP_SENS_CTRL_12 0x01b7 +#define RT5682S_HP_IMP_SENS_CTRL_13 0x01b8 +#define RT5682S_HP_IMP_SENS_CTRL_14 0x01b9 +#define RT5682S_HP_IMP_SENS_CTRL_15 0x01ba +#define RT5682S_HP_IMP_SENS_CTRL_16 0x01bb +#define RT5682S_HP_IMP_SENS_CTRL_17 0x01bc +#define RT5682S_HP_IMP_SENS_CTRL_18 0x01bd +#define RT5682S_HP_IMP_SENS_CTRL_19 0x01be +#define RT5682S_HP_IMP_SENS_CTRL_20 0x01bf +#define RT5682S_HP_IMP_SENS_CTRL_21 0x01c0 +#define RT5682S_HP_IMP_SENS_CTRL_22 0x01c1 +#define RT5682S_HP_IMP_SENS_CTRL_23 0x01c2 +#define RT5682S_HP_IMP_SENS_CTRL_24 0x01c3 +#define RT5682S_HP_IMP_SENS_CTRL_25 0x01c4 +#define RT5682S_HP_IMP_SENS_CTRL_26 0x01c5 +#define RT5682S_HP_IMP_SENS_CTRL_27 0x01c6 +#define RT5682S_HP_IMP_SENS_CTRL_28 0x01c7 +#define RT5682S_HP_IMP_SENS_CTRL_29 0x01c8 +#define RT5682S_HP_IMP_SENS_CTRL_30 0x01c9 +#define RT5682S_HP_IMP_SENS_CTRL_31 0x01ca +#define RT5682S_HP_IMP_SENS_CTRL_32 0x01cb +#define RT5682S_HP_IMP_SENS_CTRL_33 0x01cc +#define RT5682S_HP_IMP_SENS_CTRL_34 0x01cd +#define RT5682S_HP_IMP_SENS_CTRL_35 0x01ce +#define RT5682S_HP_IMP_SENS_CTRL_36 0x01cf +#define RT5682S_HP_IMP_SENS_CTRL_37 0x01d0 +#define RT5682S_HP_IMP_SENS_CTRL_38 0x01d1 +#define RT5682S_HP_IMP_SENS_CTRL_39 0x01d2 +#define RT5682S_HP_IMP_SENS_CTRL_40 0x01d3 +#define RT5682S_HP_IMP_SENS_CTRL_41 0x01d4 +#define RT5682S_HP_IMP_SENS_CTRL_42 0x01d5 +#define RT5682S_HP_IMP_SENS_CTRL_43 0x01d6 +#define RT5682S_HP_IMP_SENS_CTRL_44 0x01d7 +#define RT5682S_HP_IMP_SENS_CTRL_45 0x01d8 +#define RT5682S_HP_IMP_SENS_CTRL_46 0x01d9 +#define RT5682S_HP_LOGIC_CTRL_1 0x01da +#define RT5682S_HP_LOGIC_CTRL_2 0x01db +#define RT5682S_HP_LOGIC_CTRL_3 0x01dc +#define RT5682S_HP_CALIB_CTRL_1 0x01de +#define RT5682S_HP_CALIB_CTRL_2 0x01df +#define RT5682S_HP_CALIB_CTRL_3 0x01e0 +#define RT5682S_HP_CALIB_CTRL_4 0x01e1 +#define RT5682S_HP_CALIB_CTRL_5 0x01e2 +#define RT5682S_HP_CALIB_CTRL_6 0x01e3 +#define RT5682S_HP_CALIB_CTRL_7 0x01e4 +#define RT5682S_HP_CALIB_CTRL_8 0x01e5 +#define RT5682S_HP_CALIB_CTRL_9 0x01e6 +#define RT5682S_HP_CALIB_CTRL_10 0x01e7 +#define RT5682S_HP_CALIB_CTRL_11 0x01e8 +#define RT5682S_HP_CALIB_ST_1 0x01ea +#define RT5682S_HP_CALIB_ST_2 0x01eb +#define RT5682S_HP_CALIB_ST_3 0x01ec +#define RT5682S_HP_CALIB_ST_4 0x01ed +#define RT5682S_HP_CALIB_ST_5 0x01ee +#define RT5682S_HP_CALIB_ST_6 0x01ef +#define RT5682S_HP_CALIB_ST_7 0x01f0 +#define RT5682S_HP_CALIB_ST_8 0x01f1 +#define RT5682S_HP_CALIB_ST_9 0x01f2 +#define RT5682S_HP_CALIB_ST_10 0x01f3 +#define RT5682S_HP_CALIB_ST_11 0x01f4 +#define RT5682S_SAR_IL_CMD_1 0x0210 +#define RT5682S_SAR_IL_CMD_2 0x0211 +#define RT5682S_SAR_IL_CMD_3 0x0212 +#define RT5682S_SAR_IL_CMD_4 0x0213 +#define RT5682S_SAR_IL_CMD_5 0x0214 +#define RT5682S_SAR_IL_CMD_6 0x0215 +#define RT5682S_SAR_IL_CMD_7 0x0216 +#define RT5682S_SAR_IL_CMD_8 0x0217 +#define RT5682S_SAR_IL_CMD_9 0x0218 +#define RT5682S_SAR_IL_CMD_10 0x0219 +#define RT5682S_SAR_IL_CMD_11 0x021a +#define RT5682S_SAR_IL_CMD_12 0x021b +#define RT5682S_SAR_IL_CMD_13 0x021c +#define RT5682S_SAR_IL_CMD_14 0x021d +#define RT5682S_DUMMY_4 0x02fa +#define RT5682S_DUMMY_5 0x02fb +#define RT5682S_DUMMY_6 0x02fc +#define RT5682S_VERSION_ID_HIDE 0x03fe +#define RT5682S_VERSION_ID_CUS 0x03ff +#define RT5682S_SCAN_CTL 0x0500 +#define RT5682S_HP_AMP_DET 0x0600 +#define RT5682S_BIAS_CUR_CTRL_11 0x0610 +#define RT5682S_BIAS_CUR_CTRL_12 0x0611 +#define RT5682S_BIAS_CUR_CTRL_13 0x0620 +#define RT5682S_BIAS_CUR_CTRL_14 0x0621 +#define RT5682S_BIAS_CUR_CTRL_15 0x0630 +#define RT5682S_BIAS_CUR_CTRL_16 0x0631 +#define RT5682S_BIAS_CUR_CTRL_17 0x0640 +#define RT5682S_BIAS_CUR_CTRL_18 0x0641 +#define RT5682S_I2C_TRANS_CTRL 0x07fa +#define RT5682S_DUMMY_7 0x08fa +#define RT5682S_DUMMY_8 0x08fb +#define RT5682S_DMIC_FLOAT_DET 0x0d00 +#define RT5682S_HA_CMP_OP_1 0x1100 +#define RT5682S_HA_CMP_OP_2 0x1101 +#define RT5682S_HA_CMP_OP_3 0x1102 +#define RT5682S_HA_CMP_OP_4 0x1103 +#define RT5682S_HA_CMP_OP_5 0x1104 +#define RT5682S_HA_CMP_OP_6 0x1105 +#define RT5682S_HA_CMP_OP_7 0x1106 +#define RT5682S_HA_CMP_OP_8 0x1107 +#define RT5682S_HA_CMP_OP_9 0x1108 +#define RT5682S_HA_CMP_OP_10 0x1109 +#define RT5682S_HA_CMP_OP_11 0x110a +#define RT5682S_HA_CMP_OP_12 0x110b +#define RT5682S_HA_CMP_OP_13 0x110c +#define RT5682S_HA_CMP_OP_14 0x1111 +#define RT5682S_HA_CMP_OP_15 0x1112 +#define RT5682S_HA_CMP_OP_16 0x1113 +#define RT5682S_HA_CMP_OP_17 0x1114 +#define RT5682S_HA_CMP_OP_18 0x1115 +#define RT5682S_HA_CMP_OP_19 0x1116 +#define RT5682S_HA_CMP_OP_20 0x1117 +#define RT5682S_HA_CMP_OP_21 0x1118 +#define RT5682S_HA_CMP_OP_22 0x1119 +#define RT5682S_HA_CMP_OP_23 0x111a +#define RT5682S_HA_CMP_OP_24 0x111b +#define RT5682S_HA_CMP_OP_25 0x111c +#define RT5682S_NEW_CBJ_DET_CTL_1 0x1401 +#define RT5682S_NEW_CBJ_DET_CTL_2 0x1402 +#define RT5682S_NEW_CBJ_DET_CTL_3 0x1403 +#define RT5682S_NEW_CBJ_DET_CTL_4 0x1404 +#define RT5682S_NEW_CBJ_DET_CTL_5 0x1406 +#define RT5682S_NEW_CBJ_DET_CTL_6 0x1407 +#define RT5682S_NEW_CBJ_DET_CTL_7 0x1408 +#define RT5682S_NEW_CBJ_DET_CTL_8 0x1409 +#define RT5682S_NEW_CBJ_DET_CTL_9 0x140a +#define RT5682S_NEW_CBJ_DET_CTL_10 0x140b +#define RT5682S_NEW_CBJ_DET_CTL_11 0x140c +#define RT5682S_NEW_CBJ_DET_CTL_12 0x140d +#define RT5682S_NEW_CBJ_DET_CTL_13 0x140e +#define RT5682S_NEW_CBJ_DET_CTL_14 0x140f +#define RT5682S_NEW_CBJ_DET_CTL_15 0x1410 +#define RT5682S_NEW_CBJ_DET_CTL_16 0x1411 +#define RT5682S_DA_FILTER_1 0x1801 +#define RT5682S_DA_FILTER_2 0x1802 +#define RT5682S_DA_FILTER_3 0x1803 +#define RT5682S_DA_FILTER_4 0x1804 +#define RT5682S_DA_FILTER_5 0x1805 +#define RT5682S_CLK_SW_TEST_1 0x2c00 +#define RT5682S_CLK_SW_TEST_2 0x3400 +#define RT5682S_CLK_SW_TEST_3 0x3404 +#define RT5682S_CLK_SW_TEST_4 0x3405 +#define RT5682S_CLK_SW_TEST_5 0x3406 +#define RT5682S_CLK_SW_TEST_6 0x3407 +#define RT5682S_CLK_SW_TEST_7 0x3408 +#define RT5682S_CLK_SW_TEST_8 0x3409 +#define RT5682S_CLK_SW_TEST_9 0x340a +#define RT5682S_CLK_SW_TEST_10 0x340b +#define RT5682S_CLK_SW_TEST_11 0x340c +#define RT5682S_CLK_SW_TEST_12 0x340d +#define RT5682S_CLK_SW_TEST_13 0x340e +#define RT5682S_CLK_SW_TEST_14 0x340f +#define RT5682S_EFUSE_MANU_WRITE_1 0x3410 +#define RT5682S_EFUSE_MANU_WRITE_2 0x3411 +#define RT5682S_EFUSE_MANU_WRITE_3 0x3412 +#define RT5682S_EFUSE_MANU_WRITE_4 0x3413 +#define RT5682S_EFUSE_MANU_WRITE_5 0x3414 +#define RT5682S_EFUSE_MANU_WRITE_6 0x3415 +#define RT5682S_EFUSE_READ_1 0x3424 +#define RT5682S_EFUSE_READ_2 0x3425 +#define RT5682S_EFUSE_READ_3 0x3426 +#define RT5682S_EFUSE_READ_4 0x3427 +#define RT5682S_EFUSE_READ_5 0x3428 +#define RT5682S_EFUSE_READ_6 0x3429 +#define RT5682S_EFUSE_READ_7 0x342a +#define RT5682S_EFUSE_READ_8 0x342b +#define RT5682S_EFUSE_READ_9 0x342c +#define RT5682S_EFUSE_READ_10 0x342d +#define RT5682S_EFUSE_READ_11 0x342e +#define RT5682S_EFUSE_READ_12 0x342f +#define RT5682S_EFUSE_READ_13 0x3430 +#define RT5682S_EFUSE_READ_14 0x3431 +#define RT5682S_EFUSE_READ_15 0x3432 +#define RT5682S_EFUSE_READ_16 0x3433 +#define RT5682S_EFUSE_READ_17 0x3434 +#define RT5682S_EFUSE_READ_18 0x3435 +#define RT5682S_EFUSE_TIMING_CTL_1 0x3440 +#define RT5682S_EFUSE_TIMING_CTL_2 0x3441 +#define RT5682S_PILOT_DIG_CTL_1 0x3500 +#define RT5682S_PILOT_DIG_CTL_2 0x3501 +#define RT5682S_HP_AMP_DET_CTL_1 0x3b00 +#define RT5682S_HP_AMP_DET_CTL_2 0x3b01 +#define RT5682S_HP_AMP_DET_CTL_3 0x3b02 +#define RT5682S_HP_AMP_DET_CTL_4 0x3b03 + +#define RT5682S_MAX_REG (RT5682S_HP_AMP_DET_CTL_4) + +/* global definition */ +#define RT5682S_L_MUTE (0x1 << 15) +#define RT5682S_L_MUTE_SFT 15 +#define RT5682S_R_MUTE (0x1 << 7) +#define RT5682S_R_MUTE_SFT 7 +#define RT5682S_L_VOL_SFT 8 +#define RT5682S_R_VOL_SFT 0 +#define RT5682S_CLK_SRC_MCLK (0x0) +#define RT5682S_CLK_SRC_PLL1 (0x1) +#define RT5682S_CLK_SRC_PLL2 (0x2) +#define RT5682S_CLK_SRC_RCCLK (0x4) /* 25M */ + + +/* Headphone Amp Control 2 (0x0003) */ +#define RT5682S_HPO_L_PATH_MASK (0x1 << 14) +#define RT5682S_HPO_L_PATH_EN (0x1 << 14) +#define RT5682S_HPO_L_PATH_DIS (0x0 << 14) +#define RT5682S_HPO_R_PATH_MASK (0x1 << 13) +#define RT5682S_HPO_R_PATH_EN (0x1 << 13) +#define RT5682S_HPO_R_PATH_DIS (0x0 << 13) +#define RT5682S_HPO_SEL_IP_EN_SW (0x1) +#define RT5682S_HPO_IP_EN_GATING (0x1) +#define RT5682S_HPO_IP_NO_GATING (0x0) + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5682S_G_HP (0xf << 8) +#define RT5682S_G_HP_SFT 8 +#define RT5682S_G_STO_DA_DMIX (0xf) +#define RT5682S_G_STO_DA_SFT 0 + +/* Embeeded Jack and Type Detection Control 2 (0x0010) */ +#define RT5682S_EMB_JD_MASK (0x1 << 15) +#define RT5682S_EMB_JD_EN (0x1 << 15) +#define RT5682S_EMB_JD_EN_SFT 15 +#define RT5682S_EMB_JD_RST (0x1 << 14) +#define RT5682S_JD_MODE (0x1 << 13) +#define RT5682S_JD_MODE_SFT 13 +#define RT5682S_DET_TYPE (0x1 << 12) +#define RT5682S_DET_TYPE_SFT 12 +#define RT5682S_POLA_EXT_JD_MASK (0x1 << 11) +#define RT5682S_POLA_EXT_JD_LOW (0x1 << 11) +#define RT5682S_POLA_EXT_JD_HIGH (0x0 << 11) +#define RT5682S_SEL_FAST_OFF_MASK (0x3 << 9) +#define RT5682S_SEL_FAST_OFF_SFT 9 +#define RT5682S_POL_FAST_OFF_MASK (0x1 << 8) +#define RT5682S_POL_FAST_OFF_HIGH (0x1 << 8) +#define RT5682S_POL_FAST_OFF_LOW (0x0 << 8) +#define RT5682S_FAST_OFF_MASK (0x1 << 7) +#define RT5682S_FAST_OFF_EN (0x1 << 7) +#define RT5682S_FAST_OFF_DIS (0x0 << 7) +#define RT5682S_VREF_POW_MASK (0x1 << 6) +#define RT5682S_VREF_POW_FSM (0x0 << 6) +#define RT5682S_VREF_POW_REG (0x1 << 6) +#define RT5682S_MB1_PATH_BIT 5 +#define RT5682S_MB1_PATH_MASK (0x1 << 5) +#define RT5682S_CTRL_MB1_REG (0x1 << 5) +#define RT5682S_CTRL_MB1_FSM (0x0 << 5) +#define RT5682S_MB2_PATH_BIT 4 +#define RT5682S_MB2_PATH_MASK (0x1 << 4) +#define RT5682S_CTRL_MB2_REG (0x1 << 4) +#define RT5682S_CTRL_MB2_FSM (0x0 << 4) +#define RT5682S_TRIG_JD_MASK (0x1 << 3) +#define RT5682S_TRIG_JD_HIGH (0x1 << 3) +#define RT5682S_TRIG_JD_LOW (0x0 << 3) +#define RT5682S_MIC_CAP_MASK (0x1 << 1) +#define RT5682S_MIC_CAP_HS (0x1 << 1) +#define RT5682S_MIC_CAP_HP (0x0 << 1) +#define RT5682S_MIC_CAP_SRC_MASK (0x1) +#define RT5682S_MIC_CAP_SRC_REG (0x1) +#define RT5682S_MIC_CAP_SRC_ANA (0x0) + +/* Embeeded Jack and Type Detection Control 3 (0x0011) */ +#define RT5682S_SEL_CBJ_TYPE_SLOW (0x1 << 15) +#define RT5682S_SEL_CBJ_TYPE_NORM (0x0 << 15) +#define RT5682S_SEL_CBJ_TYPE_MASK (0x1 << 15) +#define RT5682S_POW_BG_MB1_MASK (0x1 << 13) +#define RT5682S_POW_BG_MB1_REG (0x1 << 13) +#define RT5682S_POW_BG_MB1_FSM (0x0 << 13) +#define RT5682S_POW_BG_MB2_MASK (0x1 << 12) +#define RT5682S_POW_BG_MB2_REG (0x1 << 12) +#define RT5682S_POW_BG_MB2_FSM (0x0 << 12) +#define RT5682S_EXT_JD_SRC (0x7 << 4) +#define RT5682S_EXT_JD_SRC_SFT 4 +#define RT5682S_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5682S_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5682S_EXT_JD_SRC_JDH (0x2 << 4) +#define RT5682S_EXT_JD_SRC_JDL (0x3 << 4) +#define RT5682S_EXT_JD_SRC_MANUAL (0x4 << 4) +#define RT5682S_JACK_TYPE_MASK (0x3) + +/* Combo Jack and Type Detection Control 4 (0x0012) */ +#define RT5682S_CBJ_IN_BUF_MASK (0x1 << 7) +#define RT5682S_CBJ_IN_BUF_EN (0x1 << 7) +#define RT5682S_CBJ_IN_BUF_DIS (0x0 << 7) +#define RT5682S_CBJ_IN_BUF_BIT 7 + +/* Combo Jack and Type Detection Control 5 (0x0013) */ +#define RT5682S_SEL_SHT_MID_TON_MASK (0x3 << 12) +#define RT5682S_SEL_SHT_MID_TON_2 (0x0 << 12) +#define RT5682S_SEL_SHT_MID_TON_3 (0x1 << 12) +#define RT5682S_CBJ_JD_TEST_MASK (0x1 << 6) +#define RT5682S_CBJ_JD_TEST_NORM (0x0 << 6) +#define RT5682S_CBJ_JD_TEST_MODE (0x1 << 6) + +/* Combo Jack and Type Detection Control 6 (0x0014) */ +#define RT5682S_JD_FAST_OFF_SRC_MASK (0x7 << 8) +#define RT5682S_JD_FAST_OFF_SRC_JDH (0x6 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO6 (0x5 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO5 (0x4 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO4 (0x3 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO3 (0x2 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO2 (0x1 << 8) +#define RT5682S_JD_FAST_OFF_SRC_GPIO1 (0x0 << 8) + +/* DAC1 Digital Volume (0x0019) */ +#define RT5682S_DAC_L1_VOL_MASK (0xff << 8) +#define RT5682S_DAC_L1_VOL_SFT 8 +#define RT5682S_DAC_R1_VOL_MASK (0xff) +#define RT5682S_DAC_R1_VOL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5682S_ADC_L_VOL_MASK (0x7f << 8) +#define RT5682S_ADC_L_VOL_SFT 8 +#define RT5682S_ADC_R_VOL_MASK (0x7f) +#define RT5682S_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5682S_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5682S_STO1_ADC_L_BST_SFT 14 +#define RT5682S_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5682S_STO1_ADC_R_BST_SFT 12 + +/* Sidetone Control (0x0024) */ +#define RT5682S_ST_SRC_SEL (0x1 << 8) +#define RT5682S_ST_SRC_SFT 8 +#define RT5682S_ST_EN_MASK (0x1 << 6) +#define RT5682S_ST_DIS (0x0 << 6) +#define RT5682S_ST_EN (0x1 << 6) +#define RT5682S_ST_EN_SFT 6 + +/* Stereo1 ADC Mixer Control (0x0026) */ +#define RT5682S_M_STO1_ADC_L1 (0x1 << 15) +#define RT5682S_M_STO1_ADC_L1_SFT 15 +#define RT5682S_M_STO1_ADC_L2 (0x1 << 14) +#define RT5682S_M_STO1_ADC_L2_SFT 14 +#define RT5682S_STO1_ADC1L_SRC_MASK (0x1 << 13) +#define RT5682S_STO1_ADC1L_SRC_SFT 13 +#define RT5682S_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5682S_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5682S_STO1_ADC2L_SRC_MASK (0x1 << 12) +#define RT5682S_STO1_ADC2L_SRC_SFT 12 +#define RT5682S_STO1_ADCL_SRC_MASK (0x3 << 10) +#define RT5682S_STO1_ADCL_SRC_SFT 10 +#define RT5682S_M_STO1_ADC_R1 (0x1 << 7) +#define RT5682S_M_STO1_ADC_R1_SFT 7 +#define RT5682S_M_STO1_ADC_R2 (0x1 << 6) +#define RT5682S_M_STO1_ADC_R2_SFT 6 +#define RT5682S_STO1_ADC1R_SRC_MASK (0x1 << 5) +#define RT5682S_STO1_ADC1R_SRC_SFT 5 +#define RT5682S_STO1_ADC2R_SRC_MASK (0x1 << 4) +#define RT5682S_STO1_ADC2R_SRC_SFT 4 +#define RT5682S_STO1_ADCR_SRC_MASK (0x3 << 2) +#define RT5682S_STO1_ADCR_SRC_SFT 2 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5682S_M_ADCMIX_L (0x1 << 15) +#define RT5682S_M_ADCMIX_L_SFT 15 +#define RT5682S_M_DAC1_L (0x1 << 14) +#define RT5682S_M_DAC1_L_SFT 14 +#define RT5682S_M_ADCMIX_R (0x1 << 7) +#define RT5682S_M_ADCMIX_R_SFT 7 +#define RT5682S_M_DAC1_R (0x1 << 6) +#define RT5682S_M_DAC1_R_SFT 6 + +/* Stereo1 DAC Mixer Control (0x002a) */ +#define RT5682S_M_DAC_L1_STO_L (0x1 << 15) +#define RT5682S_M_DAC_L1_STO_L_SFT 15 +#define RT5682S_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5682S_G_DAC_L1_STO_L_SFT 14 +#define RT5682S_M_DAC_R1_STO_L (0x1 << 13) +#define RT5682S_M_DAC_R1_STO_L_SFT 13 +#define RT5682S_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5682S_G_DAC_R1_STO_L_SFT 12 +#define RT5682S_M_DAC_L1_STO_R (0x1 << 7) +#define RT5682S_M_DAC_L1_STO_R_SFT 7 +#define RT5682S_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5682S_G_DAC_L1_STO_R_SFT 6 +#define RT5682S_M_DAC_R1_STO_R (0x1 << 5) +#define RT5682S_M_DAC_R1_STO_R_SFT 5 +#define RT5682S_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5682S_G_DAC_R1_STO_R_SFT 4 + +/* Analog DAC1 Input Source Control (0x002b) */ +#define RT5682S_M_ST_STO_L (0x1 << 9) +#define RT5682S_M_ST_STO_L_SFT 9 +#define RT5682S_M_ST_STO_R (0x1 << 8) +#define RT5682S_M_ST_STO_R_SFT 8 +#define RT5682S_DAC_L1_SRC_MASK (0x1 << 4) +#define RT5682S_A_DACL1_SFT 4 +#define RT5682S_DAC_R1_SRC_MASK (0x1) +#define RT5682S_A_DACR1_SFT 0 + +/* Digital Interface Data Control (0x0030) */ +#define RT5682S_IF2_DAC_SEL_MASK (0x3 << 2) +#define RT5682S_IF2_DAC_SEL_SFT 2 +#define RT5682S_IF2_ADC_SEL_MASK (0x3 << 0) +#define RT5682S_IF2_ADC_SEL_SFT 0 + +/* REC Left/Right Mixer Control 2 (0x003c) */ +#define RT5682S_BST_CBJ_MASK (0x3f << 8) +#define RT5682S_BST_CBJ_SFT 8 +#define RT5682S_M_CBJ_RM1_L (0x1 << 7) +#define RT5682S_M_CBJ_RM1_L_SFT 7 +#define RT5682S_M_CBJ_RM1_R (0x1 << 6) +#define RT5682S_M_CBJ_RM1_R_SFT 6 + +/* REC Left/Right Mixer Calibration Control(0x0044) */ +#define RT5682S_PWR_RM1_R_BIT 8 +#define RT5682S_PWR_RM1_L_BIT 0 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5682S_PWR_I2S1 (0x1 << 15) +#define RT5682S_PWR_I2S1_BIT 15 +#define RT5682S_PWR_I2S2 (0x1 << 14) +#define RT5682S_PWR_I2S2_BIT 14 +#define RT5682S_PRE_CHR_DAC_L1 (0x1 << 13) +#define RT5682S_PRE_CHR_DAC_L1_BIT 13 +#define RT5682S_PRE_CHR_DAC_R1 (0x1 << 12) +#define RT5682S_PRE_CHR_DAC_R1_BIT 12 +#define RT5682S_PWR_DAC_L1 (0x1 << 11) +#define RT5682S_PWR_DAC_L1_BIT 11 +#define RT5682S_PWR_DAC_R1 (0x1 << 10) +#define RT5682S_PWR_DAC_R1_BIT 10 +#define RT5682S_PWR_LDO (0x1 << 8) +#define RT5682S_PWR_LDO_BIT 8 +#define RT5682S_PWR_D2S_L (0x1 << 7) +#define RT5682S_PWR_D2S_L_BIT 7 +#define RT5682S_PWR_D2S_R (0x1 << 6) +#define RT5682S_PWR_D2S_R_BIT 6 +#define RT5682S_PWR_ADC_L1 (0x1 << 4) +#define RT5682S_PWR_ADC_L1_BIT 4 +#define RT5682S_PWR_ADC_R1 (0x1 << 3) +#define RT5682S_PWR_ADC_R1_BIT 3 +#define RT5682S_EFUSE_SW_EN (0x1 << 2) +#define RT5682S_EFUSE_SW_DIS (0x0 << 2) +#define RT5682S_PWR_EFUSE (0x1 << 1) +#define RT5682S_PWR_EFUSE_BIT 1 +#define RT5682S_DIG_GATE_CTRL (0x1 << 0) +#define RT5682S_DIG_GATE_CTRL_SFT 0 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5682S_PWR_ADC_S1F (0x1 << 15) +#define RT5682S_PWR_ADC_S1F_BIT 15 +#define RT5682S_PWR_DAC_S1F (0x1 << 10) +#define RT5682S_PWR_DAC_S1F_BIT 10 +#define RT5682S_DLDO_I_LIMIT_MASK (0x1 << 7) +#define RT5682S_DLDO_I_LIMIT_EN (0x1 << 7) +#define RT5682S_DLDO_I_LIMIT_DIS (0x0 << 7) +#define RT5682S_DLDO_I_BIAS_SEL_4 (0x1 << 6) +#define RT5682S_DLDO_I_BIAS_SEL_0 (0x0 << 6) +#define RT5682S_DLDO_REG_TEST_1 (0x1 << 5) +#define RT5682S_DLDO_REG_TEST_0 (0x0 << 5) +#define RT5682S_DLDO_SRC_REG (0x1 << 4) +#define RT5682S_DLDO_SRC_EFUSE (0x0 << 4) + +/* Power Management for Analog 1 (0x0063) */ +#define RT5682S_PWR_VREF1 (0x1 << 15) +#define RT5682S_PWR_VREF1_BIT 15 +#define RT5682S_PWR_FV1 (0x1 << 14) +#define RT5682S_PWR_FV1_BIT 14 +#define RT5682S_PWR_VREF2 (0x1 << 13) +#define RT5682S_PWR_VREF2_BIT 13 +#define RT5682S_PWR_FV2 (0x1 << 12) +#define RT5682S_PWR_FV2_BIT 12 +#define RT5682S_LDO1_DBG_MASK (0x3 << 10) +#define RT5682S_PWR_MB (0x1 << 9) +#define RT5682S_PWR_MB_BIT 9 +#define RT5682S_PWR_BG (0x1 << 7) +#define RT5682S_PWR_BG_BIT 7 +#define RT5682S_LDO1_BYPASS_MASK (0x1 << 6) +#define RT5682S_LDO1_BYPASS (0x1 << 6) +#define RT5682S_LDO1_NOT_BYPASS (0x0 << 6) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5682S_PWR_MCLK0_WD (0x1 << 15) +#define RT5682S_PWR_MCLK0_WD_BIT 15 +#define RT5682S_PWR_MCLK1_WD (0x1 << 14) +#define RT5682S_PWR_MCLK1_WD_BIT 14 +#define RT5682S_RST_MCLK0 (0x1 << 13) +#define RT5682S_RST_MCLK0_BIT 13 +#define RT5682S_RST_MCLK1 (0x1 << 12) +#define RT5682S_RST_MCLK1_BIT 12 +#define RT5682S_PWR_MB1 (0x1 << 11) +#define RT5682S_PWR_MB1_PWR_DOWN (0x0 << 11) +#define RT5682S_PWR_MB1_BIT 11 +#define RT5682S_PWR_MB2 (0x1 << 10) +#define RT5682S_PWR_MB2_PWR_DOWN (0x0 << 10) +#define RT5682S_PWR_MB2_BIT 10 +#define RT5682S_PWR_JD_MASK (0x1 << 0) +#define RT5682S_PWR_JD_ENABLE (0x1 << 0) +#define RT5682S_PWR_JD_DISABLE (0x0 << 0) + +/* Power Management for Analog 3 (0x0065) */ +#define RT5682S_PWR_LDO_PLLA (0x1 << 15) +#define RT5682S_PWR_LDO_PLLA_BIT 15 +#define RT5682S_PWR_LDO_PLLB (0x1 << 14) +#define RT5682S_PWR_LDO_PLLB_BIT 14 +#define RT5682S_PWR_BIAS_PLLA (0x1 << 13) +#define RT5682S_PWR_BIAS_PLLA_BIT 13 +#define RT5682S_PWR_BIAS_PLLB (0x1 << 12) +#define RT5682S_PWR_BIAS_PLLB_BIT 12 +#define RT5682S_PWR_CBJ (0x1 << 9) +#define RT5682S_PWR_CBJ_BIT 9 +#define RT5682S_RSTB_PLLB (0x1 << 7) +#define RT5682S_RSTB_PLLB_BIT 7 +#define RT5682S_RSTB_PLLA (0x1 << 6) +#define RT5682S_RSTB_PLLA_BIT 6 +#define RT5682S_PWR_PLLB (0x1 << 5) +#define RT5682S_PWR_PLLB_BIT 5 +#define RT5682S_PWR_PLLA (0x1 << 4) +#define RT5682S_PWR_PLLA_BIT 4 +#define RT5682S_PWR_LDO_MB2 (0x1 << 2) +#define RT5682S_PWR_LDO_MB2_BIT 2 +#define RT5682S_PWR_LDO_MB1 (0x1 << 1) +#define RT5682S_PWR_LDO_MB1_BIT 1 +#define RT5682S_PWR_BGLDO (0x1 << 0) +#define RT5682S_PWR_BGLDO_BIT 0 + +/* Power Management for Mixer (0x0066) */ +#define RT5682S_PWR_CLK_COMP_8FS (0x1 << 15) +#define RT5682S_PWR_CLK_COMP_8FS_BIT 15 +#define RT5682S_DBG_BGLDO_MASK (0x3 << 12) +#define RT5682S_DBG_BGLDO_SFT 12 +#define RT5682S_DBG_BGLDO_MB1_MASK (0x3 << 10) +#define RT5682S_DBG_BGLDO_MB1_SFT 10 +#define RT5682S_DBG_BGLDO_MB2_MASK (0x3 << 8) +#define RT5682S_DBG_BGLDO_MB2_SFT 8 +#define RT5682S_DLDO_BGLDO_MASK (0x3 << 6) +#define RT5682S_DLDO_BGLDO_MB2_SFT 6 +#define RT5682S_PWR_STO1_DAC_L (0x1 << 5) +#define RT5682S_PWR_STO1_DAC_L_BIT 5 +#define RT5682S_PWR_STO1_DAC_R (0x1 << 4) +#define RT5682S_PWR_STO1_DAC_R_BIT 4 +#define RT5682S_DVO_BGLDO_MB1_MASK (0x3 << 2) +#define RT5682S_DVO_BGLDO_MB1_SFT 2 +#define RT5682S_DVO_BGLDO_MB2_MASK (0x3 << 0) + +/* MCLK and System Clock Detection Control (0x006b) */ +#define RT5682S_SYS_CLK_DET (0x1 << 15) +#define RT5682S_SYS_CLK_DET_SFT 15 +#define RT5682S_PLL1_CLK_DET (0x1 << 14) +#define RT5682S_PLL1_CLK_DET_SFT 14 + +/* Digital Microphone Control 1 (0x006e) */ +#define RT5682S_DMIC_1_EN_MASK (0x1 << 15) +#define RT5682S_DMIC_1_EN_SFT 15 +#define RT5682S_DMIC_1_DIS (0x0 << 15) +#define RT5682S_DMIC_1_EN (0x1 << 15) +#define RT5682S_FIFO_CLK_DIV_MASK (0x7 << 12) +#define RT5682S_FIFO_CLK_DIV_2 (0x1 << 12) +#define RT5682S_DMIC_1_DP_MASK (0x3 << 4) +#define RT5682S_DMIC_1_DP_SFT 4 +#define RT5682S_DMIC_1_DP_GPIO2 (0x0 << 4) +#define RT5682S_DMIC_1_DP_GPIO5 (0x1 << 4) +#define RT5682S_DMIC_CLK_MASK (0xf << 0) +#define RT5682S_DMIC_CLK_SFT 0 + +/* I2S1 Audio Serial Data Port Control (0x0070) */ +#define RT5682S_SEL_ADCDAT_MASK (0x1 << 15) +#define RT5682S_SEL_ADCDAT_OUT (0x0 << 15) +#define RT5682S_SEL_ADCDAT_IN (0x1 << 15) +#define RT5682S_SEL_ADCDAT_SFT 15 +#define RT5682S_I2S1_TX_CHL_MASK (0x7 << 12) +#define RT5682S_I2S1_TX_CHL_SFT 12 +#define RT5682S_I2S1_TX_CHL_16 (0x0 << 12) +#define RT5682S_I2S1_TX_CHL_20 (0x1 << 12) +#define RT5682S_I2S1_TX_CHL_24 (0x2 << 12) +#define RT5682S_I2S1_TX_CHL_32 (0x3 << 12) +#define RT5682S_I2S1_TX_CHL_8 (0x4 << 12) +#define RT5682S_I2S1_RX_CHL_MASK (0x7 << 8) +#define RT5682S_I2S1_RX_CHL_SFT 8 +#define RT5682S_I2S1_RX_CHL_16 (0x0 << 8) +#define RT5682S_I2S1_RX_CHL_20 (0x1 << 8) +#define RT5682S_I2S1_RX_CHL_24 (0x2 << 8) +#define RT5682S_I2S1_RX_CHL_32 (0x3 << 8) +#define RT5682S_I2S1_RX_CHL_8 (0x4 << 8) +#define RT5682S_I2S1_MONO_MASK (0x1 << 7) +#define RT5682S_I2S1_MONO_EN (0x1 << 7) +#define RT5682S_I2S1_MONO_DIS (0x0 << 7) +#define RT5682S_I2S1_DL_MASK (0x7 << 4) +#define RT5682S_I2S1_DL_SFT 4 +#define RT5682S_I2S1_DL_16 (0x0 << 4) +#define RT5682S_I2S1_DL_20 (0x1 << 4) +#define RT5682S_I2S1_DL_24 (0x2 << 4) +#define RT5682S_I2S1_DL_32 (0x3 << 4) +#define RT5682S_I2S1_DL_8 (0x4 << 4) + +/* I2S1/2 Audio Serial Data Port Control (0x0071) */ +#define RT5682S_I2S2_MS_MASK (0x1 << 15) +#define RT5682S_I2S2_MS_SFT 15 +#define RT5682S_I2S2_MS_M (0x0 << 15) +#define RT5682S_I2S2_MS_S (0x1 << 15) +#define RT5682S_I2S2_PIN_CFG_MASK (0x1 << 14) +#define RT5682S_I2S2_PIN_CFG_SFT 14 +#define RT5682S_I2S2_OUT_MASK (0x1 << 9) +#define RT5682S_I2S2_OUT_SFT 9 +#define RT5682S_I2S2_OUT_UM (0x0 << 9) +#define RT5682S_I2S2_OUT_M (0x1 << 9) +#define RT5682S_I2S_BP_MASK (0x1 << 8) +#define RT5682S_I2S_BP_SFT 8 +#define RT5682S_I2S_BP_NOR (0x0 << 8) +#define RT5682S_I2S_BP_INV (0x1 << 8) +#define RT5682S_I2S2_MONO_MASK (0x1 << 7) +#define RT5682S_I2S2_MONO_EN (0x1 << 7) +#define RT5682S_I2S2_MONO_DIS (0x0 << 7) +#define RT5682S_I2S2_DL_MASK (0x7 << 4) +#define RT5682S_I2S2_DL_SFT 4 +#define RT5682S_I2S2_DL_8 (0x0 << 4) +#define RT5682S_I2S2_DL_16 (0x1 << 4) +#define RT5682S_I2S2_DL_20 (0x2 << 4) +#define RT5682S_I2S2_DL_24 (0x3 << 4) +#define RT5682S_I2S2_DL_32 (0x4 << 4) +#define RT5682S_I2S_DF_MASK (0x7) +#define RT5682S_I2S_DF_SFT 0 +#define RT5682S_I2S_DF_I2S (0x0) +#define RT5682S_I2S_DF_LEFT (0x1) +#define RT5682S_I2S_DF_PCM_A (0x2) +#define RT5682S_I2S_DF_PCM_B (0x3) +#define RT5682S_I2S_DF_PCM_A_N (0x6) +#define RT5682S_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5682S_ADC_OSR_MASK (0xf << 12) +#define RT5682S_ADC_OSR_SFT 12 +#define RT5682S_ADC_OSR_D_1 (0x0 << 12) +#define RT5682S_ADC_OSR_D_2 (0x1 << 12) +#define RT5682S_ADC_OSR_D_4 (0x2 << 12) +#define RT5682S_ADC_OSR_D_6 (0x3 << 12) +#define RT5682S_ADC_OSR_D_8 (0x4 << 12) +#define RT5682S_ADC_OSR_D_12 (0x5 << 12) +#define RT5682S_ADC_OSR_D_16 (0x6 << 12) +#define RT5682S_ADC_OSR_D_24 (0x7 << 12) +#define RT5682S_ADC_OSR_D_32 (0x8 << 12) +#define RT5682S_ADC_OSR_D_48 (0x9 << 12) +#define RT5682S_I2S_M_D_MASK (0xf << 8) +#define RT5682S_I2S_M_D_SFT 8 +#define RT5682S_I2S_M_D_1 (0x0 << 8) +#define RT5682S_I2S_M_D_2 (0x1 << 8) +#define RT5682S_I2S_M_D_3 (0x2 << 8) +#define RT5682S_I2S_M_D_4 (0x3 << 8) +#define RT5682S_I2S_M_D_6 (0x4 << 8) +#define RT5682S_I2S_M_D_8 (0x5 << 8) +#define RT5682S_I2S_M_D_12 (0x6 << 8) +#define RT5682S_I2S_M_D_16 (0x7 << 8) +#define RT5682S_I2S_M_D_24 (0x8 << 8) +#define RT5682S_I2S_M_D_32 (0x9 << 8) +#define RT5682S_I2S_M_D_48 (0x10 << 8) +#define RT5682S_I2S_M_CLK_SRC_MASK (0x7 << 4) +#define RT5682S_I2S_M_CLK_SRC_SFT 4 +#define RT5682S_DAC_OSR_MASK (0xf << 0) +#define RT5682S_DAC_OSR_SFT 0 +#define RT5682S_DAC_OSR_D_1 (0x0 << 0) +#define RT5682S_DAC_OSR_D_2 (0x1 << 0) +#define RT5682S_DAC_OSR_D_4 (0x2 << 0) +#define RT5682S_DAC_OSR_D_6 (0x3 << 0) +#define RT5682S_DAC_OSR_D_8 (0x4 << 0) +#define RT5682S_DAC_OSR_D_12 (0x5 << 0) +#define RT5682S_DAC_OSR_D_16 (0x6 << 0) +#define RT5682S_DAC_OSR_D_24 (0x7 << 0) +#define RT5682S_DAC_OSR_D_32 (0x8 << 0) +#define RT5682S_DAC_OSR_D_48 (0x9 << 0) + +/* ADC/DAC Clock Control 2 (0x0074) */ +#define RT5682S_I2S2_BCLK_MS2_MASK (0x1 << 11) +#define RT5682S_I2S2_BCLK_MS2_SFT 11 +#define RT5682S_I2S2_BCLK_MS2_32 (0x0 << 11) +#define RT5682S_I2S2_BCLK_MS2_64 (0x1 << 11) + + +/* TDM control 1 (0x0079) */ +#define RT5682S_TDM_TX_CH_MASK (0x3 << 12) +#define RT5682S_TDM_TX_CH_2 (0x0 << 12) +#define RT5682S_TDM_TX_CH_4 (0x1 << 12) +#define RT5682S_TDM_TX_CH_6 (0x2 << 12) +#define RT5682S_TDM_TX_CH_8 (0x3 << 12) +#define RT5682S_TDM_RX_CH_MASK (0x3 << 8) +#define RT5682S_TDM_RX_CH_2 (0x0 << 8) +#define RT5682S_TDM_RX_CH_4 (0x1 << 8) +#define RT5682S_TDM_RX_CH_6 (0x2 << 8) +#define RT5682S_TDM_RX_CH_8 (0x3 << 8) +#define RT5682S_TDM_ADC_LCA_MASK (0x7 << 4) +#define RT5682S_TDM_ADC_LCA_SFT 4 +#define RT5682S_TDM_ADC_DL_SFT 0 + +/* TDM control 2 (0x007a) */ +#define RT5682S_IF1_ADC1_SEL_SFT 14 +#define RT5682S_IF1_ADC2_SEL_SFT 12 +#define RT5682S_IF1_ADC3_SEL_SFT 10 +#define RT5682S_IF1_ADC4_SEL_SFT 8 +#define RT5682S_TDM_ADC_SEL_SFT 3 + +/* TDM control 3 (0x007b) */ +#define RT5682S_TDM_EN (0x1 << 7) + +/* TDM/I2S control (0x007e) */ +#define RT5682S_TDM_S_BP_MASK (0x1 << 15) +#define RT5682S_TDM_S_BP_SFT 15 +#define RT5682S_TDM_S_BP_NOR (0x0 << 15) +#define RT5682S_TDM_S_BP_INV (0x1 << 15) +#define RT5682S_TDM_S_LP_MASK (0x1 << 14) +#define RT5682S_TDM_S_LP_SFT 14 +#define RT5682S_TDM_S_LP_NOR (0x0 << 14) +#define RT5682S_TDM_S_LP_INV (0x1 << 14) +#define RT5682S_TDM_DF_MASK (0x7 << 11) +#define RT5682S_TDM_DF_SFT 11 +#define RT5682S_TDM_DF_I2S (0x0 << 11) +#define RT5682S_TDM_DF_LEFT (0x1 << 11) +#define RT5682S_TDM_DF_PCM_A (0x2 << 11) +#define RT5682S_TDM_DF_PCM_B (0x3 << 11) +#define RT5682S_TDM_DF_PCM_A_N (0x6 << 11) +#define RT5682S_TDM_DF_PCM_B_N (0x7 << 11) +#define RT5682S_TDM_BCLK_MS1_MASK (0x3 << 8) +#define RT5682S_TDM_BCLK_MS1_SFT 8 +#define RT5682S_TDM_BCLK_MS1_32 (0x0 << 8) +#define RT5682S_TDM_BCLK_MS1_64 (0x1 << 8) +#define RT5682S_TDM_BCLK_MS1_128 (0x2 << 8) +#define RT5682S_TDM_BCLK_MS1_256 (0x3 << 8) +#define RT5682S_TDM_BCLK_MS1_16 (0x4 << 8) +#define RT5682S_TDM_CL_MASK (0x3 << 4) +#define RT5682S_TDM_CL_16 (0x0 << 4) +#define RT5682S_TDM_CL_20 (0x1 << 4) +#define RT5682S_TDM_CL_24 (0x2 << 4) +#define RT5682S_TDM_CL_32 (0x3 << 4) +#define RT5682S_TDM_M_BP_MASK (0x1 << 2) +#define RT5682S_TDM_M_BP_SFT 2 +#define RT5682S_TDM_M_BP_NOR (0x0 << 2) +#define RT5682S_TDM_M_BP_INV (0x1 << 2) +#define RT5682S_TDM_M_LP_MASK (0x1 << 1) +#define RT5682S_TDM_M_LP_SFT 1 +#define RT5682S_TDM_M_LP_NOR (0x0 << 1) +#define RT5682S_TDM_M_LP_INV (0x1 << 1) +#define RT5682S_TDM_MS_MASK (0x1 << 0) +#define RT5682S_TDM_MS_SFT 0 +#define RT5682S_TDM_MS_S (0x0 << 0) +#define RT5682S_TDM_MS_M (0x1 << 0) + +/* Global Clock Control (0x0080) */ +#define RT5682S_SCLK_SRC_MASK (0x7 << 13) +#define RT5682S_SCLK_SRC_SFT 13 +#define RT5682S_PLL_SRC_MASK (0x3 << 8) +#define RT5682S_PLL_SRC_SFT 8 +#define RT5682S_PLL_SRC_MCLK (0x0 << 8) +#define RT5682S_PLL_SRC_BCLK1 (0x1 << 8) +#define RT5682S_PLL_SRC_RC (0x3 << 8) + +/* PLL tracking mode 1 (0x0083) */ +#define RT5682S_DA_ASRC_MASK (0x1 << 13) +#define RT5682S_DA_ASRC_SFT 13 +#define RT5682S_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5682S_DAC_STO1_ASRC_SFT 12 +#define RT5682S_AD_ASRC_MASK (0x1 << 8) +#define RT5682S_AD_ASRC_SFT 8 +#define RT5682S_AD_ASRC_SEL_MASK (0x1 << 4) +#define RT5682S_AD_ASRC_SEL_SFT 4 +#define RT5682S_DMIC_ASRC_MASK (0x1 << 3) +#define RT5682S_DMIC_ASRC_SFT 3 +#define RT5682S_ADC_STO1_ASRC_MASK (0x1 << 2) +#define RT5682S_ADC_STO1_ASRC_SFT 2 +#define RT5682S_DA_ASRC_SEL_MASK (0x1 << 0) +#define RT5682S_DA_ASRC_SEL_SFT 0 + +/* PLL tracking mode 2 3 (0x0084)(0x0085)*/ +#define RT5682S_FILTER_CLK_SEL_MASK (0x7 << 12) +#define RT5682S_FILTER_CLK_SEL_SFT 12 +#define RT5682S_FILTER_CLK_DIV_MASK (0xf << 8) +#define RT5682S_FILTER_CLK_DIV_SFT 8 + +/* ASRC Control 4 (0x0086) */ +#define RT5682S_ASRCIN_FTK_N1_MASK (0x3 << 14) +#define RT5682S_ASRCIN_FTK_N1_SFT 14 +#define RT5682S_ASRCIN_FTK_N2_MASK (0x3 << 12) +#define RT5682S_ASRCIN_FTK_N2_SFT 12 +#define RT5682S_ASRCIN_FTK_M1_MASK (0x7 << 8) +#define RT5682S_ASRCIN_FTK_M1_SFT 8 +#define RT5682S_ASRCIN_FTK_M2_MASK (0x7 << 4) +#define RT5682S_ASRCIN_FTK_M2_SFT 4 + +/* Depop Mode Control 1 (0x008e) */ +#define RT5682S_OUT_HP_L_EN (0x1 << 6) +#define RT5682S_OUT_HP_R_EN (0x1 << 5) +#define RT5682S_LDO_PUMP_EN (0x1 << 4) +#define RT5682S_LDO_PUMP_EN_SFT 4 +#define RT5682S_PUMP_EN (0x1 << 3) +#define RT5682S_PUMP_EN_SFT 3 +#define RT5682S_CAPLESS_L_EN (0x1 << 1) +#define RT5682S_CAPLESS_L_EN_SFT 1 +#define RT5682S_CAPLESS_R_EN (0x1 << 0) +#define RT5682S_CAPLESS_R_EN_SFT 0 + +/* Depop Mode Control 2 (0x8f) */ +#define RT5682S_RAMP_MASK (0x1 << 12) +#define RT5682S_RAMP_SFT 12 +#define RT5682S_RAMP_DIS (0x0 << 12) +#define RT5682S_RAMP_EN (0x1 << 12) +#define RT5682S_BPS_MASK (0x1 << 11) +#define RT5682S_BPS_SFT 11 +#define RT5682S_BPS_DIS (0x0 << 11) +#define RT5682S_BPS_EN (0x1 << 11) +#define RT5682S_FAST_UPDN_MASK (0x1 << 10) +#define RT5682S_FAST_UPDN_SFT 10 +#define RT5682S_FAST_UPDN_DIS (0x0 << 10) +#define RT5682S_FAST_UPDN_EN (0x1 << 10) +#define RT5682S_VLO_MASK (0x1 << 7) +#define RT5682S_VLO_SFT 7 +#define RT5682S_VLO_3V (0x0 << 7) +#define RT5682S_VLO_33V (0x1 << 7) + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5682S_OSW_L_MASK (0x1 << 11) +#define RT5682S_OSW_L_SFT 11 +#define RT5682S_OSW_L_DIS (0x0 << 11) +#define RT5682S_OSW_L_EN (0x1 << 11) +#define RT5682S_OSW_R_MASK (0x1 << 10) +#define RT5682S_OSW_R_SFT 10 +#define RT5682S_OSW_R_DIS (0x0 << 10) +#define RT5682S_OSW_R_EN (0x1 << 10) +#define RT5682S_PM_HP_MASK (0x3 << 8) +#define RT5682S_PM_HP_SFT 8 +#define RT5682S_PM_HP_LV (0x0 << 8) +#define RT5682S_PM_HP_MV (0x1 << 8) +#define RT5682S_PM_HP_HV (0x2 << 8) + +/* Micbias Control1 (0x93) */ +#define RT5682S_MIC1_OV_MASK (0x3 << 14) +#define RT5682S_MIC1_OV_SFT 14 +#define RT5682S_MIC1_OV_2V7 (0x0 << 14) +#define RT5682S_MIC1_OV_2V4 (0x1 << 14) +#define RT5682S_MIC1_OV_2V25 (0x3 << 14) +#define RT5682S_MIC1_OV_1V8 (0x4 << 14) +#define RT5682S_MIC2_OV_MASK (0x3 << 8) +#define RT5682S_MIC2_OV_SFT 8 +#define RT5682S_MIC2_OV_2V7 (0x0 << 8) +#define RT5682S_MIC2_OV_2V4 (0x1 << 8) +#define RT5682S_MIC2_OV_2V25 (0x3 << 8) +#define RT5682S_MIC2_OV_1V8 (0x4 << 8) + +/* Micbias Control2 (0x0094) */ +#define RT5682S_PWR_CLK25M_MASK (0x1 << 9) +#define RT5682S_PWR_CLK25M_SFT 9 +#define RT5682S_PWR_CLK25M_PD (0x0 << 9) +#define RT5682S_PWR_CLK25M_PU (0x1 << 9) +#define RT5682S_PWR_CLK1M_MASK (0x1 << 8) +#define RT5682S_PWR_CLK1M_SFT 8 +#define RT5682S_PWR_CLK1M_PD (0x0 << 8) +#define RT5682S_PWR_CLK1M_PU (0x1 << 8) + +/* PLL M/N/K Code Control 1 (0x0098) */ +#define RT5682S_PLLA_N_MASK (0x1ff << 0) + +/* PLL M/N/K Code Control 2 (0x0099) */ +#define RT5682S_PLLA_M_MASK (0x1f << 8) +#define RT5682S_PLLA_M_SFT 8 +#define RT5682S_PLLA_K_MASK (0x1f << 0) + +/* PLL M/N/K Code Control 3 (0x009a) */ +#define RT5682S_PLLB_N_MASK (0x3ff << 0) + +/* PLL M/N/K Code Control 4 (0x009b) */ +#define RT5682S_PLLB_M_MASK (0x1f << 8) +#define RT5682S_PLLB_M_SFT 8 +#define RT5682S_PLLB_K_MASK (0x1f << 0) + +/* PLL M/N/K Code Control 6 (0x009d) */ +#define RT5682S_PLLB_SEL_PS_MASK (0x1 << 13) +#define RT5682S_PLLB_SEL_PS_SFT 13 +#define RT5682S_PLLB_BYP_PS_MASK (0x1 << 12) +#define RT5682S_PLLB_BYP_PS_SFT 12 +#define RT5682S_PLLB_M_BP_MASK (0x1 << 11) +#define RT5682S_PLLB_M_BP_SFT 11 +#define RT5682S_PLLB_K_BP_MASK (0x1 << 10) +#define RT5682S_PLLB_K_BP_SFT 10 +#define RT5682S_PLLA_M_BP_MASK (0x1 << 7) +#define RT5682S_PLLA_M_BP_SFT 7 +#define RT5682S_PLLA_K_BP_MASK (0x1 << 6) +#define RT5682S_PLLA_K_BP_SFT 6 + +/* PLL M/N/K Code Control 7 (0x009e) */ +#define RT5682S_PLLB_SRC_MASK (0x3 << 0) +#define RT5682S_PLLB_SRC_DFIN (0x1) +#define RT5682S_PLLB_SRC_PLLA (0x0) + +/* RC Clock Control (0x009f) */ +#define RT5682S_POW_IRQ (0x1 << 15) +#define RT5682S_POW_JDH (0x1 << 14) + +/* I2S2 Master Mode Clock Control 1 (0x00a0) */ +#define RT5682S_I2S2_M_CLK_SRC_MASK (0x7 << 4) +#define RT5682S_I2S2_M_CLK_SRC_SFT 4 +#define RT5682S_I2S2_M_D_MASK (0xf << 0) +#define RT5682S_I2S2_M_D_1 (0x0) +#define RT5682S_I2S2_M_D_2 (0x1) +#define RT5682S_I2S2_M_D_3 (0x2) +#define RT5682S_I2S2_M_D_4 (0x3) +#define RT5682S_I2S2_M_D_6 (0x4) +#define RT5682S_I2S2_M_D_8 (0x5) +#define RT5682S_I2S2_M_D_12 (0x6) +#define RT5682S_I2S2_M_D_16 (0x7) +#define RT5682S_I2S2_M_D_24 (0x8) +#define RT5682S_I2S2_M_D_32 (0x9) +#define RT5682S_I2S2_M_D_48 (0xa) +#define RT5682S_I2S2_M_D_SFT 0 + +/* IRQ Control 1 (0x00b6) */ +#define RT5682S_JD1_PULSE_EN_MASK (0x1 << 10) +#define RT5682S_JD1_PULSE_EN_SFT 10 +#define RT5682S_JD1_PULSE_DIS (0x0 << 10) +#define RT5682S_JD1_PULSE_EN (0x1 << 10) + +/* IRQ Control 2 (0x00b7) */ +#define RT5682S_JD1_EN_MASK (0x1 << 15) +#define RT5682S_JD1_EN_SFT 15 +#define RT5682S_JD1_DIS (0x0 << 15) +#define RT5682S_JD1_EN (0x1 << 15) +#define RT5682S_JD1_POL_MASK (0x1 << 13) +#define RT5682S_JD1_POL_NOR (0x0 << 13) +#define RT5682S_JD1_POL_INV (0x1 << 13) +#define RT5682S_JD1_IRQ_MASK (0x1 << 10) +#define RT5682S_JD1_IRQ_LEV (0x0 << 10) +#define RT5682S_JD1_IRQ_PUL (0x1 << 10) + +/* IRQ Control 3 (0x00b8) */ +#define RT5682S_IL_IRQ_MASK (0x1 << 7) +#define RT5682S_IL_IRQ_DIS (0x0 << 7) +#define RT5682S_IL_IRQ_EN (0x1 << 7) +#define RT5682S_IL_IRQ_TYPE_MASK (0x1 << 4) +#define RT5682S_IL_IRQ_LEV (0x0 << 4) +#define RT5682S_IL_IRQ_PUL (0x1 << 4) + +/* GPIO Control 1 (0x00c0) */ +#define RT5682S_GP1_PIN_MASK (0x3 << 14) +#define RT5682S_GP1_PIN_SFT 14 +#define RT5682S_GP1_PIN_GPIO1 (0x0 << 14) +#define RT5682S_GP1_PIN_IRQ (0x1 << 14) +#define RT5682S_GP1_PIN_DMIC_CLK (0x2 << 14) +#define RT5682S_GP2_PIN_MASK (0x3 << 12) +#define RT5682S_GP2_PIN_SFT 12 +#define RT5682S_GP2_PIN_GPIO2 (0x0 << 12) +#define RT5682S_GP2_PIN_LRCK2 (0x1 << 12) +#define RT5682S_GP2_PIN_DMIC_SDA (0x2 << 12) +#define RT5682S_GP3_PIN_MASK (0x3 << 10) +#define RT5682S_GP3_PIN_SFT 10 +#define RT5682S_GP3_PIN_GPIO3 (0x0 << 10) +#define RT5682S_GP3_PIN_BCLK2 (0x1 << 10) +#define RT5682S_GP3_PIN_DMIC_CLK (0x2 << 10) +#define RT5682S_GP4_PIN_MASK (0x3 << 8) +#define RT5682S_GP4_PIN_SFT 8 +#define RT5682S_GP4_PIN_GPIO4 (0x0 << 8) +#define RT5682S_GP4_PIN_ADCDAT1 (0x1 << 8) +#define RT5682S_GP4_PIN_DMIC_CLK (0x2 << 8) +#define RT5682S_GP4_PIN_ADCDAT2 (0x3 << 8) +#define RT5682S_GP5_PIN_MASK (0x3 << 6) +#define RT5682S_GP5_PIN_SFT 6 +#define RT5682S_GP5_PIN_GPIO5 (0x0 << 6) +#define RT5682S_GP5_PIN_DACDAT1 (0x1 << 6) +#define RT5682S_GP5_PIN_DMIC_SDA (0x2 << 6) +#define RT5682S_GP6_PIN_MASK (0x1 << 5) +#define RT5682S_GP6_PIN_SFT 5 +#define RT5682S_GP6_PIN_GPIO6 (0x0 << 5) +#define RT5682S_GP6_PIN_LRCK1 (0x1 << 5) + +/* GPIO Control 2 (0x00c1)*/ +#define RT5682S_GP1_PF_MASK (0x1 << 15) +#define RT5682S_GP1_PF_IN (0x0 << 15) +#define RT5682S_GP1_PF_OUT (0x1 << 15) +#define RT5682S_GP1_OUT_MASK (0x1 << 14) +#define RT5682S_GP1_OUT_L (0x0 << 14) +#define RT5682S_GP1_OUT_H (0x1 << 14) +#define RT5682S_GP2_PF_MASK (0x1 << 13) +#define RT5682S_GP2_PF_IN (0x0 << 13) +#define RT5682S_GP2_PF_OUT (0x1 << 13) +#define RT5682S_GP2_OUT_MASK (0x1 << 12) +#define RT5682S_GP2_OUT_L (0x0 << 12) +#define RT5682S_GP2_OUT_H (0x1 << 12) +#define RT5682S_GP3_PF_MASK (0x1 << 11) +#define RT5682S_GP3_PF_IN (0x0 << 11) +#define RT5682S_GP3_PF_OUT (0x1 << 11) +#define RT5682S_GP3_OUT_MASK (0x1 << 10) +#define RT5682S_GP3_OUT_L (0x0 << 10) +#define RT5682S_GP3_OUT_H (0x1 << 10) +#define RT5682S_GP4_PF_MASK (0x1 << 9) +#define RT5682S_GP4_PF_IN (0x0 << 9) +#define RT5682S_GP4_PF_OUT (0x1 << 9) +#define RT5682S_GP4_OUT_MASK (0x1 << 8) +#define RT5682S_GP4_OUT_L (0x0 << 8) +#define RT5682S_GP4_OUT_H (0x1 << 8) +#define RT5682S_GP5_PF_MASK (0x1 << 7) +#define RT5682S_GP5_PF_IN (0x0 << 7) +#define RT5682S_GP5_PF_OUT (0x1 << 7) +#define RT5682S_GP5_OUT_MASK (0x1 << 6) +#define RT5682S_GP5_OUT_L (0x0 << 6) +#define RT5682S_GP5_OUT_H (0x1 << 6) +#define RT5682S_GP6_PF_MASK (0x1 << 5) +#define RT5682S_GP6_PF_IN (0x0 << 5) +#define RT5682S_GP6_PF_OUT (0x1 << 5) +#define RT5682S_GP6_OUT_MASK (0x1 << 4) +#define RT5682S_GP6_OUT_L (0x0 << 4) +#define RT5682S_GP6_OUT_H (0x1 << 4) + +/* GPIO Status (0x00c2) */ +#define RT5682S_GP6_ST (0x1 << 6) +#define RT5682S_GP5_ST (0x1 << 5) +#define RT5682S_GP4_ST (0x1 << 4) +#define RT5682S_GP3_ST (0x1 << 3) +#define RT5682S_GP2_ST (0x1 << 2) +#define RT5682S_GP1_ST (0x1 << 1) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5682S_ZCD_MASK (0x1 << 10) +#define RT5682S_ZCD_SFT 10 +#define RT5682S_ZCD_PD (0x0 << 10) +#define RT5682S_ZCD_PU (0x1 << 10) + +/* 4 Button Inline Command Control 2 (0x00e3) */ +#define RT5682S_4BTN_IL_MASK (0x1 << 15) +#define RT5682S_4BTN_IL_EN (0x1 << 15) +#define RT5682S_4BTN_IL_DIS (0x0 << 15) +#define RT5682S_4BTN_IL_RST_MASK (0x1 << 14) +#define RT5682S_4BTN_IL_NOR (0x1 << 14) +#define RT5682S_4BTN_IL_RST (0x0 << 14) + +/* 4 Button Inline Command Control 3~6 (0x00e5~0x00e8) */ +#define RT5682S_4BTN_IL_HOLD_WIN_MASK (0x7f << 8) +#define RT5682S_4BTN_IL_HOLD_WIN_SFT 8 +#define RT5682S_4BTN_IL_CLICK_WIN_MASK (0x7f) +#define RT5682S_4BTN_IL_CLICK_WIN_SFT 0 + +/* Analog JD Control (0x00f0) */ +#define RT5682S_JDH_RS_MASK (0x1 << 4) +#define RT5682S_JDH_NO_PLUG (0x1 << 4) +#define RT5682S_JDH_PLUG (0x0 << 4) + +/* Charge Pump Internal Register1 (0x0125) */ +#define RT5682S_CP_CLK_HP_MASK (0x3 << 4) +#define RT5682S_CP_CLK_HP_100KHZ (0x0 << 4) +#define RT5682S_CP_CLK_HP_200KHZ (0x1 << 4) +#define RT5682S_CP_CLK_HP_300KHZ (0x2 << 4) +#define RT5682S_CP_CLK_HP_600KHZ (0x3 << 4) + +/* Pad Driving Control (0x0136) */ +#define RT5682S_PAD_DRV_GP1_MASK (0x1 << 14) +#define RT5682S_PAD_DRV_GP1_HIGH (0x1 << 14) +#define RT5682S_PAD_DRV_GP1_LOW (0x0 << 14) +#define RT5682S_PAD_DRV_GP2_MASK (0x1 << 12) +#define RT5682S_PAD_DRV_GP2_HIGH (0x1 << 12) +#define RT5682S_PAD_DRV_GP2_LOW (0x0 << 12) +#define RT5682S_PAD_DRV_GP3_MASK (0x1 << 10) +#define RT5682S_PAD_DRV_GP3_HIGH (0x1 << 10) +#define RT5682S_PAD_DRV_GP3_LOW (0x0 << 10) +#define RT5682S_PAD_DRV_GP4_MASK (0x1 << 8) +#define RT5682S_PAD_DRV_GP4_HIGH (0x1 << 8) +#define RT5682S_PAD_DRV_GP4_LOW (0x0 << 8) +#define RT5682S_PAD_DRV_GP5_MASK (0x1 << 6) +#define RT5682S_PAD_DRV_GP5_HIGH (0x1 << 6) +#define RT5682S_PAD_DRV_GP5_LOW (0x0 << 6) +#define RT5682S_PAD_DRV_GP6_MASK (0x1 << 4) +#define RT5682S_PAD_DRV_GP6_HIGH (0x1 << 4) +#define RT5682S_PAD_DRV_GP6_LOW (0x0 << 4) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5682S_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5682S_CKXEN_DAC1_SFT 13 +#define RT5682S_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5682S_CKGEN_DAC1_SFT 12 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5682S_CKXEN_ADC1_MASK (0x1 << 13) +#define RT5682S_CKXEN_ADC1_SFT 13 +#define RT5682S_CKGEN_ADC1_MASK (0x1 << 12) +#define RT5682S_CKGEN_ADC1_SFT 12 + +/* Volume test (0x013f)*/ +#define RT5682S_SEL_CLK_VOL_MASK (0x1 << 15) +#define RT5682S_SEL_CLK_VOL_EN (0x1 << 15) +#define RT5682S_SEL_CLK_VOL_DIS (0x0 << 15) + +/* Test Mode Control 1 (0x0145) */ +#define RT5682S_AD2DA_LB_MASK (0x1 << 10) +#define RT5682S_AD2DA_LB_SFT 10 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5682S_NG2_EN_MASK (0x1 << 15) +#define RT5682S_NG2_EN (0x1 << 15) +#define RT5682S_NG2_DIS (0x0 << 15) + +/* Stereo1 DAC Silence Detection Control (0x0190) */ +#define RT5682S_DEB_STO_DAC_MASK (0x7 << 4) +#define RT5682S_DEB_80_MS (0x0 << 4) + +/* HP Behavior Logic Control 2 (0x01db) */ +#define RT5682S_HP_SIG_SRC_MASK (0x3) +#define RT5682S_HP_SIG_SRC_1BIT_CTL (0x3) +#define RT5682S_HP_SIG_SRC_REG (0x2) +#define RT5682S_HP_SIG_SRC_IMPE_REG (0x1) +#define RT5682S_HP_SIG_SRC_DC_CALI (0x0) + +/* SAR ADC Inline Command Control 1 (0x0210) */ +#define RT5682S_SAR_BUTDET_MASK (0x1 << 15) +#define RT5682S_SAR_BUTDET_EN (0x1 << 15) +#define RT5682S_SAR_BUTDET_DIS (0x0 << 15) +#define RT5682S_SAR_BUTDET_POW_MASK (0x1 << 14) +#define RT5682S_SAR_BUTDET_POW_SAV (0x1 << 14) +#define RT5682S_SAR_BUTDET_POW_NORM (0x0 << 14) +#define RT5682S_SAR_BUTDET_RST_MASK (0x1 << 13) +#define RT5682S_SAR_BUTDET_RST_NORM (0x1 << 13) +#define RT5682S_SAR_BUTDET_RST (0x0 << 13) +#define RT5682S_SAR_POW_MASK (0x1 << 12) +#define RT5682S_SAR_POW_EN (0x1 << 12) +#define RT5682S_SAR_POW_DIS (0x0 << 12) +#define RT5682S_SAR_RST_MASK (0x1 << 11) +#define RT5682S_SAR_RST_NORMAL (0x1 << 11) +#define RT5682S_SAR_RST (0x0 << 11) +#define RT5682S_SAR_BYPASS_MASK (0x1 << 10) +#define RT5682S_SAR_BYPASS_EN (0x1 << 10) +#define RT5682S_SAR_BYPASS_DIS (0x0 << 10) +#define RT5682S_SAR_SEL_MB1_2_MASK (0x3 << 8) +#define RT5682S_SAR_SEL_MB1_2_SFT 8 +#define RT5682S_SAR_SEL_MODE_MASK (0x1 << 7) +#define RT5682S_SAR_SEL_MODE_CMP (0x1 << 7) +#define RT5682S_SAR_SEL_MODE_ADC (0x0 << 7) +#define RT5682S_SAR_SEL_MB1_2_CTL_MASK (0x1 << 5) +#define RT5682S_SAR_SEL_MB1_2_AUTO (0x1 << 5) +#define RT5682S_SAR_SEL_MB1_2_MANU (0x0 << 5) +#define RT5682S_SAR_SEL_SIGNAL_MASK (0x1 << 4) +#define RT5682S_SAR_SEL_SIGNAL_AUTO (0x1 << 4) +#define RT5682S_SAR_SEL_SIGNAL_MANU (0x0 << 4) + +/* SAR ADC Inline Command Control 2 (0x0211) */ +#define RT5682S_SAR_ADC_PSV_MASK (0x1 << 4) +#define RT5682S_SAR_ADC_PSV_ENTRY (0x1 << 4) + + +/* SAR ADC Inline Command Control 13 (0x021c) */ +#define RT5682S_SAR_SOUR_MASK (0x3f) +#define RT5682S_SAR_SOUR_BTN (0x3f) +#define RT5682S_SAR_SOUR_TYPE (0x0) + + +#define RT5682S_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5682S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +/* System Clock Source */ +enum { + RT5682S_SCLK_S_MCLK, + RT5682S_SCLK_S_PLL1, + RT5682S_SCLK_S_PLL2, + RT5682S_SCLK_S_RCCLK, +}; + +/* PLL Source */ +enum { + RT5682S_PLL_S_MCLK, + RT5682S_PLL_S_BCLK1, + RT5682S_PLL_S_BCLK2, + RT5682S_PLL_S_RCCLK, +}; + +enum { + RT5682S_PLL1, + RT5682S_PLL2, + RT5682S_PLLS, +}; + +enum { + RT5682S_AIF1, + RT5682S_AIF2, + RT5682S_AIFS +}; + +/* filter mask */ +enum { + RT5682S_DA_STEREO1_FILTER = 0x1, + RT5682S_AD_STEREO1_FILTER = (0x1 << 1), +}; + +enum { + RT5682S_CLK_SEL_SYS, + RT5682S_CLK_SEL_I2S1_ASRC, + RT5682S_CLK_SEL_I2S2_ASRC, +}; + +enum { + USE_PLLA, + USE_PLLB, + USE_PLLAB, +}; + +struct pll_calc_map { + unsigned int freq_in; + unsigned int freq_out; + int m; + int n; + int k; + bool m_bp; + bool k_bp; + bool byp_ps; + bool sel_ps; +}; + +#define RT5682S_NUM_SUPPLIES 2 + +struct rt5682s_priv { + struct snd_soc_component *component; + struct rt5682s_platform_data pdata; + struct regmap *regmap; + struct snd_soc_jack *hs_jack; + struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES]; + struct delayed_work jack_detect_work; + struct delayed_work jd_check_work; + struct mutex calibrate_mutex; + struct mutex sar_mutex; + +#ifdef CONFIG_COMMON_CLK + struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS]; + struct clk *mclk; +#endif + + int sysclk; + int sysclk_src; + int lrck[RT5682S_AIFS]; + int bclk[RT5682S_AIFS]; + int master[RT5682S_AIFS]; + + int pll_src[RT5682S_PLLS]; + int pll_in[RT5682S_PLLS]; + int pll_out[RT5682S_PLLS]; + int pll_comb; + + int jack_type; + int irq_work_delay_time; +}; + +int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component, + unsigned int filter_mask, unsigned int clk_src); + +#endif /* __RT5682S_H__ */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index d885ced34f6066..bc5d68c53e5abc 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -4859,7 +4859,7 @@ static int wcd9335_codec_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, wcd->regmap); /* Class-H Init*/ - wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version); + wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, WCD9335); if (IS_ERR(wcd->clsh_ctrl)) return PTR_ERR(wcd->clsh_ctrl); diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c35673e7f4202d..8863b533f9c417 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -145,13 +145,13 @@ static const struct regmap_range_cfg wm2200_ranges[] = { .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, }, }; -static const struct wm_adsp_region wm2200_dsp1_regions[] = { +static const struct cs_dsp_region wm2200_dsp1_regions[] = { { .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE }, { .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE }, { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE }, }; -static const struct wm_adsp_region wm2200_dsp2_regions[] = { +static const struct cs_dsp_region wm2200_dsp2_regions[] = { { .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE }, { .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE }, { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, @@ -2202,23 +2202,23 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, } for (i = 0; i < 2; i++) { - wm2200->dsp[i].type = WMFW_ADSP1; + wm2200->dsp[i].cs_dsp.type = WMFW_ADSP1; wm2200->dsp[i].part = "wm2200"; - wm2200->dsp[i].num = i + 1; - wm2200->dsp[i].dev = &i2c->dev; - wm2200->dsp[i].regmap = wm2200->regmap; - wm2200->dsp[i].sysclk_reg = WM2200_CLOCKING_3; - wm2200->dsp[i].sysclk_mask = WM2200_SYSCLK_FREQ_MASK; - wm2200->dsp[i].sysclk_shift = WM2200_SYSCLK_FREQ_SHIFT; + wm2200->dsp[i].cs_dsp.num = i + 1; + wm2200->dsp[i].cs_dsp.dev = &i2c->dev; + wm2200->dsp[i].cs_dsp.regmap = wm2200->regmap; + wm2200->dsp[i].cs_dsp.sysclk_reg = WM2200_CLOCKING_3; + wm2200->dsp[i].cs_dsp.sysclk_mask = WM2200_SYSCLK_FREQ_MASK; + wm2200->dsp[i].cs_dsp.sysclk_shift = WM2200_SYSCLK_FREQ_SHIFT; } - wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1; - wm2200->dsp[0].mem = wm2200_dsp1_regions; - wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions); + wm2200->dsp[0].cs_dsp.base = WM2200_DSP1_CONTROL_1; + wm2200->dsp[0].cs_dsp.mem = wm2200_dsp1_regions; + wm2200->dsp[0].cs_dsp.num_mems = ARRAY_SIZE(wm2200_dsp1_regions); - wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1; - wm2200->dsp[1].mem = wm2200_dsp2_regions; - wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions); + wm2200->dsp[1].cs_dsp.base = WM2200_DSP2_CONTROL_1; + wm2200->dsp[1].cs_dsp.mem = wm2200_dsp2_regions; + wm2200->dsp[1].cs_dsp.num_mems = ARRAY_SIZE(wm2200_dsp2_regions); for (i = 0; i < ARRAY_SIZE(wm2200->dsp); i++) wm_adsp1_init(&wm2200->dsp[i]); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 621598608bf0b7..da2f8998df87a6 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -44,7 +44,7 @@ static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); -static const struct wm_adsp_region wm5102_dsp1_regions[] = { +static const struct cs_dsp_region wm5102_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, { .type = WMFW_ADSP2_ZM, .base = 0x180000 }, { .type = WMFW_ADSP2_XM, .base = 0x190000 }, @@ -2046,13 +2046,13 @@ static int wm5102_probe(struct platform_device *pdev) arizona_init_dvfs(&wm5102->core); wm5102->core.adsp[0].part = "wm5102"; - wm5102->core.adsp[0].num = 1; - wm5102->core.adsp[0].type = WMFW_ADSP2; - wm5102->core.adsp[0].base = ARIZONA_DSP1_CONTROL_1; - wm5102->core.adsp[0].dev = arizona->dev; - wm5102->core.adsp[0].regmap = arizona->regmap; - wm5102->core.adsp[0].mem = wm5102_dsp1_regions; - wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions); + wm5102->core.adsp[0].cs_dsp.num = 1; + wm5102->core.adsp[0].cs_dsp.type = WMFW_ADSP2; + wm5102->core.adsp[0].cs_dsp.base = ARIZONA_DSP1_CONTROL_1; + wm5102->core.adsp[0].cs_dsp.dev = arizona->dev; + wm5102->core.adsp[0].cs_dsp.regmap = arizona->regmap; + wm5102->core.adsp[0].cs_dsp.mem = wm5102_dsp1_regions; + wm5102->core.adsp[0].cs_dsp.num_mems = ARRAY_SIZE(wm5102_dsp1_regions); ret = wm_adsp2_init(&wm5102->core.adsp[0]); if (ret != 0) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 5c2d45d05c975c..4973ba1ed7791a 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -45,35 +45,35 @@ struct wm5110_priv { unsigned int in_pga_cache[6]; }; -static const struct wm_adsp_region wm5110_dsp1_regions[] = { +static const struct cs_dsp_region wm5110_dsp1_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x100000 }, { .type = WMFW_ADSP2_ZM, .base = 0x180000 }, { .type = WMFW_ADSP2_XM, .base = 0x190000 }, { .type = WMFW_ADSP2_YM, .base = 0x1a8000 }, }; -static const struct wm_adsp_region wm5110_dsp2_regions[] = { +static const struct cs_dsp_region wm5110_dsp2_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x200000 }, { .type = WMFW_ADSP2_ZM, .base = 0x280000 }, { .type = WMFW_ADSP2_XM, .base = 0x290000 }, { .type = WMFW_ADSP2_YM, .base = 0x2a8000 }, }; -static const struct wm_adsp_region wm5110_dsp3_regions[] = { +static const struct cs_dsp_region wm5110_dsp3_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x300000 }, { .type = WMFW_ADSP2_ZM, .base = 0x380000 }, { .type = WMFW_ADSP2_XM, .base = 0x390000 }, { .type = WMFW_ADSP2_YM, .base = 0x3a8000 }, }; -static const struct wm_adsp_region wm5110_dsp4_regions[] = { +static const struct cs_dsp_region wm5110_dsp4_regions[] = { { .type = WMFW_ADSP2_PM, .base = 0x400000 }, { .type = WMFW_ADSP2_ZM, .base = 0x480000 }, { .type = WMFW_ADSP2_XM, .base = 0x490000 }, { .type = WMFW_ADSP2_YM, .base = 0x4a8000 }, }; -static const struct wm_adsp_region *wm5110_dsp_regions[] = { +static const struct cs_dsp_region *wm5110_dsp_regions[] = { wm5110_dsp1_regions, wm5110_dsp2_regions, wm5110_dsp3_regions, @@ -2409,15 +2409,15 @@ static int wm5110_probe(struct platform_device *pdev) for (i = 0; i < WM5110_NUM_ADSP; i++) { wm5110->core.adsp[i].part = "wm5110"; - wm5110->core.adsp[i].num = i + 1; - wm5110->core.adsp[i].type = WMFW_ADSP2; - wm5110->core.adsp[i].dev = arizona->dev; - wm5110->core.adsp[i].regmap = arizona->regmap; + wm5110->core.adsp[i].cs_dsp.num = i + 1; + wm5110->core.adsp[i].cs_dsp.type = WMFW_ADSP2; + wm5110->core.adsp[i].cs_dsp.dev = arizona->dev; + wm5110->core.adsp[i].cs_dsp.regmap = arizona->regmap; - wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 + wm5110->core.adsp[i].cs_dsp.base = ARIZONA_DSP1_CONTROL_1 + (0x100 * i); - wm5110->core.adsp[i].mem = wm5110_dsp_regions[i]; - wm5110->core.adsp[i].num_mems + wm5110->core.adsp[i].cs_dsp.mem = wm5110_dsp_regions[i]; + wm5110->core.adsp[i].cs_dsp.num_mems = ARRAY_SIZE(wm5110_dsp1_regions); ret = wm_adsp2_init(&wm5110->core.adsp[i]); diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f7c800927cb2f9..6c5d55b3b31100 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -29,18 +29,28 @@ #include <sound/jack.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <linux/firmware.h> #include "wm_adsp.h" #define adsp_crit(_dsp, fmt, ...) \ - dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) + dev_crit(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__) #define adsp_err(_dsp, fmt, ...) \ - dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) + dev_err(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__) #define adsp_warn(_dsp, fmt, ...) \ - dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) + dev_warn(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__) #define adsp_info(_dsp, fmt, ...) \ - dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) + dev_info(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__) #define adsp_dbg(_dsp, fmt, ...) \ + dev_dbg(_dsp->cs_dsp.dev, "%s: " fmt, _dsp->cs_dsp.name, ##__VA_ARGS__) + +#define cs_dsp_err(_dsp, fmt, ...) \ + dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) +#define cs_dsp_warn(_dsp, fmt, ...) \ + dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) +#define cs_dsp_info(_dsp, fmt, ...) \ + dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) +#define cs_dsp_dbg(_dsp, fmt, ...) \ dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) #define compr_err(_obj, fmt, ...) \ @@ -214,15 +224,15 @@ #define ADSP_MAX_STD_CTRL_SIZE 512 -#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 -#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10 -#define WM_ADSP_ACKED_CTL_MIN_VALUE 0 -#define WM_ADSP_ACKED_CTL_MAX_VALUE 0xFFFFFF +#define CS_DSP_ACKED_CTL_TIMEOUT_MS 100 +#define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10 +#define CS_DSP_ACKED_CTL_MIN_VALUE 0 +#define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF /* * Event control messages */ -#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 +#define CS_DSP_FW_EVENT_SHUTDOWN 0x000001 /* * HALO system info @@ -304,19 +314,22 @@ #define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff #define HALO_MPU_VIO_ERR_SRC_SHIFT 0 -static const struct wm_adsp_ops wm_adsp1_ops; -static const struct wm_adsp_ops wm_adsp2_ops[]; -static const struct wm_adsp_ops wm_halo_ops; +static const struct cs_dsp_ops cs_dsp_adsp1_ops; +static const struct cs_dsp_ops cs_dsp_adsp2_ops[]; +static const struct cs_dsp_ops cs_dsp_halo_ops; -struct wm_adsp_buf { +static const struct cs_dsp_client_ops wm_adsp1_client_ops; +static const struct cs_dsp_client_ops wm_adsp2_client_ops; + +struct cs_dsp_buf { struct list_head list; void *buf; }; -static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, - struct list_head *list) +static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len, + struct list_head *list) { - struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); + struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (buf == NULL) return NULL; @@ -334,12 +347,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, return buf; } -static void wm_adsp_buf_free(struct list_head *list) +static void cs_dsp_buf_free(struct list_head *list) { while (!list_empty(list)) { - struct wm_adsp_buf *buf = list_first_entry(list, - struct wm_adsp_buf, - list); + struct cs_dsp_buf *buf = list_first_entry(list, + struct cs_dsp_buf, + list); list_del(&buf->list); vfree(buf->buf); kfree(buf); @@ -470,12 +483,12 @@ struct wm_adsp_compr { const char *name; }; -#define WM_ADSP_DATA_WORD_SIZE 3 +#define CS_DSP_DATA_WORD_SIZE 3 #define WM_ADSP_MIN_FRAGMENTS 1 #define WM_ADSP_MAX_FRAGMENTS 256 -#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE) -#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE) +#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * CS_DSP_DATA_WORD_SIZE) +#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * CS_DSP_DATA_WORD_SIZE) #define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7 @@ -598,24 +611,12 @@ static const struct { struct wm_coeff_ctl { const char *name; - const char *fw_name; - /* Subname is needed to match with firmware */ - const char *subname; - unsigned int subname_len; - struct wm_adsp_alg_region alg_region; - struct wm_adsp *dsp; - unsigned int enabled:1; - struct list_head list; - void *cache; - unsigned int offset; - size_t len; - unsigned int set:1; + struct cs_dsp_coeff_ctl *cs_ctl; struct soc_bytes_ext bytes_ext; - unsigned int flags; - snd_ctl_elem_type_t type; + struct work_struct work; }; -static const char *wm_adsp_mem_region_name(unsigned int type) +static const char *cs_dsp_mem_region_name(unsigned int type) { switch (type) { case WMFW_ADSP1_PM: @@ -640,7 +641,7 @@ static const char *wm_adsp_mem_region_name(unsigned int type) } #ifdef CONFIG_DEBUG_FS -static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) +static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); @@ -648,7 +649,7 @@ static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) dsp->wmfw_file_name = tmp; } -static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) +static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); @@ -656,7 +657,7 @@ static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) dsp->bin_file_name = tmp; } -static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +static void cs_dsp_debugfs_clear(struct cs_dsp *dsp) { kfree(dsp->wmfw_file_name); kfree(dsp->bin_file_name); @@ -664,11 +665,11 @@ static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) dsp->bin_file_name = NULL; } -static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - struct wm_adsp *dsp = file->private_data; + struct cs_dsp *dsp = file->private_data; ssize_t ret; mutex_lock(&dsp->pwr_lock); @@ -684,11 +685,11 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, return ret; } -static ssize_t wm_adsp_debugfs_bin_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t cs_dsp_debugfs_bin_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - struct wm_adsp *dsp = file->private_data; + struct cs_dsp *dsp = file->private_data; ssize_t ret; mutex_lock(&dsp->pwr_lock); @@ -707,70 +708,70 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, static const struct { const char *name; const struct file_operations fops; -} wm_adsp_debugfs_fops[] = { +} cs_dsp_debugfs_fops[] = { { .name = "wmfw_file_name", .fops = { .open = simple_open, - .read = wm_adsp_debugfs_wmfw_read, + .read = cs_dsp_debugfs_wmfw_read, }, }, { .name = "bin_file_name", .fops = { .open = simple_open, - .read = wm_adsp_debugfs_bin_read, + .read = cs_dsp_debugfs_bin_read, }, }, }; -static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, - struct snd_soc_component *component) +static void cs_dsp_init_debugfs(struct cs_dsp *dsp, + struct dentry *debugfs_root) { struct dentry *root = NULL; int i; - root = debugfs_create_dir(dsp->name, component->debugfs_root); + root = debugfs_create_dir(dsp->name, debugfs_root); debugfs_create_bool("booted", 0444, root, &dsp->booted); debugfs_create_bool("running", 0444, root, &dsp->running); debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id); debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version); - for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) - debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root, - dsp, &wm_adsp_debugfs_fops[i].fops); + for (i = 0; i < ARRAY_SIZE(cs_dsp_debugfs_fops); ++i) + debugfs_create_file(cs_dsp_debugfs_fops[i].name, 0444, root, + dsp, &cs_dsp_debugfs_fops[i].fops); dsp->debugfs_root = root; } -static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +static void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) { - wm_adsp_debugfs_clear(dsp); + cs_dsp_debugfs_clear(dsp); debugfs_remove_recursive(dsp->debugfs_root); dsp->debugfs_root = NULL; } #else -static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp, - struct snd_soc_component *component) +static inline void cs_dsp_init_debugfs(struct cs_dsp *dsp, + struct dentry *debugfs_root) { } -static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +static inline void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) { } -static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, - const char *s) +static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, + const char *s) { } -static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, - const char *s) +static inline void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, + const char *s) { } -static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +static inline void cs_dsp_debugfs_clear(struct cs_dsp *dsp) { } #endif @@ -802,14 +803,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) return -EINVAL; - mutex_lock(&dsp[e->shift_l].pwr_lock); + mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock); - if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list)) + if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list)) ret = -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; - mutex_unlock(&dsp[e->shift_l].pwr_lock); + mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock); return ret; } @@ -826,8 +827,8 @@ const struct soc_enum wm_adsp_fw_enum[] = { }; EXPORT_SYMBOL_GPL(wm_adsp_fw_enum); -static const struct wm_adsp_region *wm_adsp_find_region(struct wm_adsp *dsp, - int type) +static const struct cs_dsp_region *cs_dsp_find_region(struct cs_dsp *dsp, + int type) { int i; @@ -838,8 +839,8 @@ static const struct wm_adsp_region *wm_adsp_find_region(struct wm_adsp *dsp, return NULL; } -static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, - unsigned int offset) +static unsigned int cs_dsp_region_to_reg(struct cs_dsp_region const *mem, + unsigned int offset) { switch (mem->type) { case WMFW_ADSP1_PM: @@ -855,8 +856,8 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, } } -static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem, - unsigned int offset) +static unsigned int cs_dsp_halo_region_to_reg(struct cs_dsp_region const *mem, + unsigned int offset) { switch (mem->type) { case WMFW_ADSP2_XM: @@ -873,8 +874,8 @@ static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem, } } -static void wm_adsp_read_fw_status(struct wm_adsp *dsp, - int noffs, unsigned int *offs) +static void cs_dsp_read_fw_status(struct cs_dsp *dsp, + int noffs, unsigned int *offs) { unsigned int i; int ret; @@ -882,45 +883,45 @@ static void wm_adsp_read_fw_status(struct wm_adsp *dsp, for (i = 0; i < noffs; ++i) { ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]); if (ret) { - adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret); + cs_dsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret); return; } } } -static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) +static void cs_dsp_adsp2_show_fw_status(struct cs_dsp *dsp) { unsigned int offs[] = { ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3, }; - wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); + cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); - adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", - offs[0], offs[1], offs[2], offs[3]); + cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + offs[0], offs[1], offs[2], offs[3]); } -static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp) +static void cs_dsp_adsp2v2_show_fw_status(struct cs_dsp *dsp) { unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 }; - wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); + cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); - adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", - offs[0] & 0xFFFF, offs[0] >> 16, - offs[1] & 0xFFFF, offs[1] >> 16); + cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + offs[0] & 0xFFFF, offs[0] >> 16, + offs[1] & 0xFFFF, offs[1] >> 16); } -static void wm_halo_show_fw_status(struct wm_adsp *dsp) +static void cs_dsp_halo_show_fw_status(struct cs_dsp *dsp) { unsigned int offs[] = { HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4, }; - wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); + cs_dsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs); - adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", - offs[0], offs[1], offs[2], offs[3]); + cs_dsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + offs[0], offs[1], offs[2], offs[3]); } static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) @@ -928,16 +929,16 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) return container_of(ext, struct wm_coeff_ctl, bytes_ext); } -static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) +static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg) { - const struct wm_adsp_alg_region *alg_region = &ctl->alg_region; - struct wm_adsp *dsp = ctl->dsp; - const struct wm_adsp_region *mem; + const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; + struct cs_dsp *dsp = ctl->dsp; + const struct cs_dsp_region *mem; - mem = wm_adsp_find_region(dsp, alg_region->type); + mem = cs_dsp_find_region(dsp, alg_region->type); if (!mem) { - adsp_err(dsp, "No base for region %x\n", - alg_region->type); + cs_dsp_err(dsp, "No base for region %x\n", + alg_region->type); return -EINVAL; } @@ -952,43 +953,47 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - switch (ctl->type) { + switch (cs_ctl->type) { case WMFW_CTL_TYPE_ACKED: uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE; - uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE; + uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE; + uinfo->value.integer.max = CS_DSP_ACKED_CTL_MAX_VALUE; uinfo->value.integer.step = 1; uinfo->count = 1; break; default: uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = ctl->len; + uinfo->count = cs_ctl->len; break; } return 0; } -static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, - unsigned int event_id) +static int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, + unsigned int event_id) { - struct wm_adsp *dsp = ctl->dsp; + struct cs_dsp *dsp = ctl->dsp; __be32 val = cpu_to_be32(event_id); unsigned int reg; int i, ret; - ret = wm_coeff_base_reg(ctl, ®); + if (!dsp->running) + return -EPERM; + + ret = cs_dsp_coeff_base_reg(ctl, ®); if (ret) return ret; - adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", - event_id, ctl->alg_region.alg, - wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset); + cs_dsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", + event_id, ctl->alg_region.alg, + cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset); ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); if (ret) { - adsp_err(dsp, "Failed to write %x: %d\n", reg, ret); + cs_dsp_err(dsp, "Failed to write %x: %d\n", reg, ret); return ret; } @@ -998,9 +1003,9 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, * to ack instantly so we do the first 1ms delay before reading the * control to avoid a pointless bus transaction */ - for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) { + for (i = 0; i < CS_DSP_ACKED_CTL_TIMEOUT_MS;) { switch (i) { - case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1: + case 0 ... CS_DSP_ACKED_CTL_N_QUICKPOLLS - 1: usleep_range(1000, 2000); i++; break; @@ -1012,33 +1017,33 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); if (ret) { - adsp_err(dsp, "Failed to read %x: %d\n", reg, ret); + cs_dsp_err(dsp, "Failed to read %x: %d\n", reg, ret); return ret; } if (val == 0) { - adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); + cs_dsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); return 0; } } - adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", - reg, ctl->alg_region.alg, - wm_adsp_mem_region_name(ctl->alg_region.type), - ctl->offset); + cs_dsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", + reg, ctl->alg_region.alg, + cs_dsp_mem_region_name(ctl->alg_region.type), + ctl->offset); return -ETIMEDOUT; } -static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl, - const void *buf, size_t len) +static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, + const void *buf, size_t len) { - struct wm_adsp *dsp = ctl->dsp; + struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = wm_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®); if (ret) return ret; @@ -1049,20 +1054,20 @@ static int wm_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl, ret = regmap_raw_write(dsp->regmap, reg, scratch, len); if (ret) { - adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", - len, reg, ret); + cs_dsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", + len, reg, ret); kfree(scratch); return ret; } - adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg); + cs_dsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg); kfree(scratch); return 0; } -static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl, - const void *buf, size_t len) +static int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, + const void *buf, size_t len) { int ret = 0; @@ -1073,7 +1078,7 @@ static int wm_coeff_write_ctrl(struct wm_coeff_ctl *ctl, ctl->set = 1; if (ctl->enabled && ctl->dsp->running) - ret = wm_coeff_write_ctrl_raw(ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl_raw(ctl, buf, len); return ret; } @@ -1084,12 +1089,13 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; char *p = ucontrol->value.bytes.data; int ret = 0; - mutex_lock(&ctl->dsp->pwr_lock); - ret = wm_coeff_write_ctrl(ctl, p, ctl->len); - mutex_unlock(&ctl->dsp->pwr_lock); + mutex_lock(&cs_ctl->dsp->pwr_lock); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, p, cs_ctl->len); + mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; } @@ -1100,16 +1106,17 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; int ret = 0; - mutex_lock(&ctl->dsp->pwr_lock); + mutex_lock(&cs_ctl->dsp->pwr_lock); - if (copy_from_user(ctl->cache, bytes, size)) + if (copy_from_user(cs_ctl->cache, bytes, size)) ret = -EFAULT; else - ret = wm_coeff_write_ctrl(ctl, ctl->cache, size); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, cs_ctl->cache, size); - mutex_unlock(&ctl->dsp->pwr_lock); + mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; } @@ -1120,33 +1127,34 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; unsigned int val = ucontrol->value.integer.value[0]; int ret; if (val == 0) return 0; /* 0 means no event */ - mutex_lock(&ctl->dsp->pwr_lock); + mutex_lock(&cs_ctl->dsp->pwr_lock); - if (ctl->enabled && ctl->dsp->running) - ret = wm_coeff_write_acked_control(ctl, val); + if (cs_ctl->enabled) + ret = cs_dsp_coeff_write_acked_control(cs_ctl, val); else ret = -EPERM; - mutex_unlock(&ctl->dsp->pwr_lock); + mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; } -static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, - void *buf, size_t len) +static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, + void *buf, size_t len) { - struct wm_adsp *dsp = ctl->dsp; + struct cs_dsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - ret = wm_coeff_base_reg(ctl, ®); + ret = cs_dsp_coeff_base_reg(ctl, ®); if (ret) return ret; @@ -1156,12 +1164,12 @@ static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, ret = regmap_raw_read(dsp->regmap, reg, scratch, len); if (ret) { - adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", - len, reg, ret); + cs_dsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", + len, reg, ret); kfree(scratch); return ret; } - adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg); + cs_dsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg); memcpy(buf, scratch, len); kfree(scratch); @@ -1169,18 +1177,18 @@ static int wm_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, return 0; } -static int wm_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len) +static int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len) { int ret = 0; if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled && ctl->dsp->running) - return wm_coeff_read_ctrl_raw(ctl, buf, len); + return cs_dsp_coeff_read_ctrl_raw(ctl, buf, len); else return -EPERM; } else { if (!ctl->flags && ctl->enabled && ctl->dsp->running) - ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); if (buf != ctl->cache) memcpy(buf, ctl->cache, len); @@ -1195,12 +1203,13 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; char *p = ucontrol->value.bytes.data; int ret; - mutex_lock(&ctl->dsp->pwr_lock); - ret = wm_coeff_read_ctrl(ctl, p, ctl->len); - mutex_unlock(&ctl->dsp->pwr_lock); + mutex_lock(&cs_ctl->dsp->pwr_lock); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, p, cs_ctl->len); + mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; } @@ -1211,16 +1220,17 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; int ret = 0; - mutex_lock(&ctl->dsp->pwr_lock); + mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = wm_coeff_read_ctrl(ctl, ctl->cache, size); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, cs_ctl->cache, size); - if (!ret && copy_to_user(bytes, ctl->cache, size)) + if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) ret = -EFAULT; - mutex_unlock(&ctl->dsp->pwr_lock); + mutex_unlock(&cs_ctl->dsp->pwr_lock); return ret; } @@ -1240,12 +1250,6 @@ static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol, return 0; } -struct wmfw_ctl_work { - struct wm_adsp *dsp; - struct wm_coeff_ctl *ctl; - struct work_struct work; -}; - static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) { unsigned int out, rd, wr, vol; @@ -1279,12 +1283,10 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) { + struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; struct snd_kcontrol_new *kcontrol; int ret; - if (!ctl || !ctl->name) - return -EINVAL; - kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); if (!kcontrol) return -ENOMEM; @@ -1294,16 +1296,16 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->tlv.c = snd_soc_bytes_tlv_callback; kcontrol->private_value = (unsigned long)&ctl->bytes_ext; - kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); + kcontrol->access = wmfw_convert_flags(cs_ctl->flags, cs_ctl->len); - switch (ctl->type) { + switch (cs_ctl->type) { case WMFW_CTL_TYPE_ACKED: kcontrol->get = wm_coeff_get_acked; kcontrol->put = wm_coeff_put_acked; break; default: if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - ctl->bytes_ext.max = ctl->len; + ctl->bytes_ext.max = cs_ctl->len; ctl->bytes_ext.get = wm_coeff_tlv_get; ctl->bytes_ext.put = wm_coeff_tlv_put; } else { @@ -1326,9 +1328,9 @@ err_kcontrol: return ret; } -static int wm_coeff_init_control_caches(struct wm_adsp *dsp) +static int cs_dsp_coeff_init_control_caches(struct cs_dsp *dsp) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *ctl; int ret; list_for_each_entry(ctl, &dsp->ctl_list, list) { @@ -1343,7 +1345,7 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp) * created so we don't need to do anything. */ if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) { - ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); + ret = cs_dsp_coeff_read_ctrl_raw(ctl, ctl->cache, ctl->len); if (ret < 0) return ret; } @@ -1352,17 +1354,17 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp) return 0; } -static int wm_coeff_sync_controls(struct wm_adsp *dsp) +static int cs_dsp_coeff_sync_controls(struct cs_dsp *dsp) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *ctl; int ret; list_for_each_entry(ctl, &dsp->ctl_list, list) { if (!ctl->enabled) continue; if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { - ret = wm_coeff_write_ctrl_raw(ctl, ctl->cache, - ctl->len); + ret = cs_dsp_coeff_write_ctrl_raw(ctl, ctl->cache, + ctl->len); if (ret < 0) return ret; } @@ -1371,10 +1373,10 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp) return 0; } -static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, - unsigned int event) +static void cs_dsp_signal_event_controls(struct cs_dsp *dsp, + unsigned int event) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *ctl; int ret; list_for_each_entry(ctl, &dsp->ctl_list, list) { @@ -1384,70 +1386,70 @@ static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, if (!ctl->enabled) continue; - ret = wm_coeff_write_acked_control(ctl, event); + ret = cs_dsp_coeff_write_acked_control(ctl, event); if (ret) - adsp_warn(dsp, - "Failed to send 0x%x event to alg 0x%x (%d)\n", - event, ctl->alg_region.alg, ret); + cs_dsp_warn(dsp, + "Failed to send 0x%x event to alg 0x%x (%d)\n", + event, ctl->alg_region.alg, ret); } } static void wm_adsp_ctl_work(struct work_struct *work) { - struct wmfw_ctl_work *ctl_work = container_of(work, - struct wmfw_ctl_work, - work); + struct wm_coeff_ctl *ctl = container_of(work, + struct wm_coeff_ctl, + work); + struct wm_adsp *dsp = container_of(ctl->cs_ctl->dsp, + struct wm_adsp, + cs_dsp); - wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl); - kfree(ctl_work); + wmfw_add_ctl(dsp, ctl); } -static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) +static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl) { kfree(ctl->cache); - kfree(ctl->name); kfree(ctl->subname); kfree(ctl); } -static int wm_adsp_create_control(struct wm_adsp *dsp, - const struct wm_adsp_alg_region *alg_region, - unsigned int offset, unsigned int len, - const char *subname, unsigned int subname_len, - unsigned int flags, snd_ctl_elem_type_t type) +static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl) { + struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp); + struct cs_dsp *cs_dsp = &dsp->cs_dsp; struct wm_coeff_ctl *ctl; - struct wmfw_ctl_work *ctl_work; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; const char *region_name; int ret; - region_name = wm_adsp_mem_region_name(alg_region->type); + if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) + return 0; + + region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type); if (!region_name) { - adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); + adsp_err(dsp, "Unknown region type: %d\n", cs_ctl->alg_region.type); return -EINVAL; } - switch (dsp->fw_ver) { + switch (cs_dsp->fw_ver) { case 0: case 1: snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x", - dsp->name, region_name, alg_region->alg); - subname = NULL; /* don't append subname */ + cs_dsp->name, region_name, cs_ctl->alg_region.alg); break; case 2: ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "%s%c %.12s %x", dsp->name, *region_name, - wm_adsp_fw_text[dsp->fw], alg_region->alg); + "%s%c %.12s %x", cs_dsp->name, *region_name, + wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg); break; default: ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "%s %.12s %x", dsp->name, - wm_adsp_fw_text[dsp->fw], alg_region->alg); + "%s %.12s %x", cs_dsp->name, + wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg); break; } - if (subname) { + if (cs_ctl->subname) { int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; int skip = 0; @@ -1455,38 +1457,82 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, avail -= strlen(dsp->component->name_prefix) + 1; /* Truncate the subname from the start if it is too long */ - if (subname_len > avail) - skip = subname_len - avail; + if (cs_ctl->subname_len > avail) + skip = cs_ctl->subname_len - avail; snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, - " %.*s", subname_len - skip, subname + skip); - } - - list_for_each_entry(ctl, &dsp->ctl_list, list) { - if (!strcmp(ctl->name, name)) { - if (!ctl->enabled) - ctl->enabled = 1; - return 0; - } + " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip); } ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); if (!ctl) return -ENOMEM; - ctl->fw_name = wm_adsp_fw_text[dsp->fw]; - ctl->alg_region = *alg_region; + ctl->cs_ctl = cs_ctl; + ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); if (!ctl->name) { ret = -ENOMEM; goto err_ctl; } - if (subname) { + + cs_ctl->priv = ctl; + + INIT_WORK(&ctl->work, wm_adsp_ctl_work); + schedule_work(&ctl->work); + + return 0; + +err_ctl: + kfree(ctl); + + return ret; +} + +static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) +{ + struct wm_coeff_ctl *ctl = cs_ctl->priv; + + cancel_work_sync(&ctl->work); + + kfree(ctl->name); + kfree(ctl); +} + +static int cs_dsp_create_control(struct cs_dsp *dsp, + const struct cs_dsp_alg_region *alg_region, + unsigned int offset, unsigned int len, + const char *subname, unsigned int subname_len, + unsigned int flags, unsigned int type) +{ + struct cs_dsp_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->fw_name == dsp->fw_name && + ctl->alg_region.alg == alg_region->alg && + ctl->alg_region.type == alg_region->type) { + if ((!subname && !ctl->subname) || + (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) { + if (!ctl->enabled) + ctl->enabled = 1; + return 0; + } + } + } + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return -ENOMEM; + + ctl->fw_name = dsp->fw_name; + ctl->alg_region = *alg_region; + if (subname && dsp->fw_ver >= 2) { ctl->subname_len = subname_len; ctl->subname = kmemdup(subname, strlen(subname) + 1, GFP_KERNEL); if (!ctl->subname) { ret = -ENOMEM; - goto err_ctl_name; + goto err_ctl; } } ctl->enabled = 1; @@ -1505,20 +1551,12 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, list_add(&ctl->list, &dsp->ctl_list); - if (flags & WMFW_CTL_FLAG_SYS) - return 0; - - ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); - if (!ctl_work) { - ret = -ENOMEM; - goto err_list_del; + if (dsp->client_ops->control_add) { + ret = dsp->client_ops->control_add(ctl); + if (ret) + goto err_list_del; } - ctl_work->dsp = dsp; - ctl_work->ctl = ctl; - INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); - schedule_work(&ctl_work->work); - return 0; err_list_del: @@ -1526,32 +1564,30 @@ err_list_del: kfree(ctl->cache); err_ctl_subname: kfree(ctl->subname); -err_ctl_name: - kfree(ctl->name); err_ctl: kfree(ctl); return ret; } -struct wm_coeff_parsed_alg { +struct cs_dsp_coeff_parsed_alg { int id; const u8 *name; int name_len; int ncoeff; }; -struct wm_coeff_parsed_coeff { +struct cs_dsp_coeff_parsed_coeff { int offset; int mem_type; const u8 *name; int name_len; - snd_ctl_elem_type_t ctl_type; + unsigned int ctl_type; int flags; int len; }; -static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) +static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) { int length; @@ -1574,7 +1610,7 @@ static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) return length; } -static int wm_coeff_parse_int(int bytes, const u8 **pos) +static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) { int val = 0; @@ -1594,8 +1630,8 @@ static int wm_coeff_parse_int(int bytes, const u8 **pos) return val; } -static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, - struct wm_coeff_parsed_alg *blk) +static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, + struct cs_dsp_coeff_parsed_alg *blk) { const struct wmfw_adsp_alg_data *raw; @@ -1611,21 +1647,21 @@ static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, blk->ncoeff = le32_to_cpu(raw->ncoeff); break; default: - blk->id = wm_coeff_parse_int(sizeof(raw->id), data); - blk->name_len = wm_coeff_parse_string(sizeof(u8), data, - &blk->name); - wm_coeff_parse_string(sizeof(u16), data, NULL); - blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); + blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); + blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, + &blk->name); + cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); + blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); break; } - adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); - adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); - adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); + cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); + cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); + cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); } -static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, - struct wm_coeff_parsed_coeff *blk) +static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, + struct cs_dsp_coeff_parsed_coeff *blk) { const struct wmfw_adsp_coeff_data *raw; const u8 *tmp; @@ -1641,160 +1677,213 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, blk->mem_type = le16_to_cpu(raw->hdr.type); blk->name = raw->name; blk->name_len = strlen(raw->name); - blk->ctl_type = (__force snd_ctl_elem_type_t)le16_to_cpu(raw->ctl_type); + blk->ctl_type = le16_to_cpu(raw->ctl_type); blk->flags = le16_to_cpu(raw->flags); blk->len = le32_to_cpu(raw->len); break; default: tmp = *data; - blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); - blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); - length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); - blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, - &blk->name); - wm_coeff_parse_string(sizeof(u8), &tmp, NULL); - wm_coeff_parse_string(sizeof(u16), &tmp, NULL); - blk->ctl_type = - (__force snd_ctl_elem_type_t)wm_coeff_parse_int(sizeof(raw->ctl_type), - &tmp); - blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); - blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); + blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); + blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); + length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); + blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, + &blk->name); + cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); + cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); + blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); + blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); + blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); *data = *data + sizeof(raw->hdr) + length; break; } - adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); - adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); - adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); - adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); - adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); - adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); + cs_dsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); + cs_dsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); + cs_dsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); + cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); + cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); + cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); } -static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, - const struct wm_coeff_parsed_coeff *coeff_blk, - unsigned int f_required, - unsigned int f_illegal) +static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, + const struct cs_dsp_coeff_parsed_coeff *coeff_blk, + unsigned int f_required, + unsigned int f_illegal) { if ((coeff_blk->flags & f_illegal) || ((coeff_blk->flags & f_required) != f_required)) { - adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", - coeff_blk->flags, coeff_blk->ctl_type); + cs_dsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", + coeff_blk->flags, coeff_blk->ctl_type); return -EINVAL; } return 0; } -static int wm_adsp_parse_coeff(struct wm_adsp *dsp, - const struct wmfw_region *region) +static int cs_dsp_parse_coeff(struct cs_dsp *dsp, + const struct wmfw_region *region) { - struct wm_adsp_alg_region alg_region = {}; - struct wm_coeff_parsed_alg alg_blk; - struct wm_coeff_parsed_coeff coeff_blk; + struct cs_dsp_alg_region alg_region = {}; + struct cs_dsp_coeff_parsed_alg alg_blk; + struct cs_dsp_coeff_parsed_coeff coeff_blk; const u8 *data = region->data; int i, ret; - wm_coeff_parse_alg(dsp, &data, &alg_blk); + cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); for (i = 0; i < alg_blk.ncoeff; i++) { - wm_coeff_parse_coeff(dsp, &data, &coeff_blk); + cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); switch (coeff_blk.ctl_type) { - case SNDRV_CTL_ELEM_TYPE_BYTES: + case WMFW_CTL_TYPE_BYTES: break; case WMFW_CTL_TYPE_ACKED: if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) continue; /* ignore */ - ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, - WMFW_CTL_FLAG_VOLATILE | - WMFW_CTL_FLAG_WRITEABLE | - WMFW_CTL_FLAG_READABLE, - 0); + ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); if (ret) return -EINVAL; break; case WMFW_CTL_TYPE_HOSTEVENT: - ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, - WMFW_CTL_FLAG_SYS | - WMFW_CTL_FLAG_VOLATILE | - WMFW_CTL_FLAG_WRITEABLE | - WMFW_CTL_FLAG_READABLE, - 0); + ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_SYS | + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); if (ret) return -EINVAL; break; case WMFW_CTL_TYPE_HOST_BUFFER: - ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, - WMFW_CTL_FLAG_SYS | - WMFW_CTL_FLAG_VOLATILE | - WMFW_CTL_FLAG_READABLE, - 0); + ret = cs_dsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_SYS | + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_READABLE, + 0); if (ret) return -EINVAL; break; default: - adsp_err(dsp, "Unknown control type: %d\n", - coeff_blk.ctl_type); + cs_dsp_err(dsp, "Unknown control type: %d\n", + coeff_blk.ctl_type); return -EINVAL; } alg_region.type = coeff_blk.mem_type; alg_region.alg = alg_blk.id; - ret = wm_adsp_create_control(dsp, &alg_region, - coeff_blk.offset, - coeff_blk.len, - coeff_blk.name, - coeff_blk.name_len, - coeff_blk.flags, - coeff_blk.ctl_type); + ret = cs_dsp_create_control(dsp, &alg_region, + coeff_blk.offset, + coeff_blk.len, + coeff_blk.name, + coeff_blk.name_len, + coeff_blk.flags, + coeff_blk.ctl_type); if (ret < 0) - adsp_err(dsp, "Failed to create control: %.*s, %d\n", - coeff_blk.name_len, coeff_blk.name, ret); + cs_dsp_err(dsp, "Failed to create control: %.*s, %d\n", + coeff_blk.name_len, coeff_blk.name, ret); } return 0; } -static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp, - const char * const file, - unsigned int pos, - const struct firmware *firmware) +static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, + const char * const file, + unsigned int pos, + const struct firmware *firmware) { const struct wmfw_adsp1_sizes *adsp1_sizes; adsp1_sizes = (void *)&firmware->data[pos]; - adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, - le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), - le32_to_cpu(adsp1_sizes->zm)); + cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, + le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), + le32_to_cpu(adsp1_sizes->zm)); return pos + sizeof(*adsp1_sizes); } -static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp, - const char * const file, - unsigned int pos, - const struct firmware *firmware) +static void wm_adsp_release_firmware_files(struct wm_adsp *dsp, + const struct firmware *wmfw_firmware, + char *wmfw_filename, + const struct firmware *coeff_firmware, + char *coeff_filename) +{ + if (wmfw_firmware) + release_firmware(wmfw_firmware); + kfree(wmfw_filename); + + if (coeff_firmware) + release_firmware(coeff_firmware); + kfree(coeff_filename); +} + +static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, + const struct firmware **firmware, + char **filename, + char *suffix) +{ + struct cs_dsp *cs_dsp = &dsp->cs_dsp; + int ret = 0; + + *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name, + wm_adsp_fw[dsp->fw].file, suffix); + if (*filename == NULL) + return -ENOMEM; + + ret = request_firmware(firmware, *filename, cs_dsp->dev); + if (ret != 0) { + adsp_err(dsp, "Failed to request '%s'\n", *filename); + kfree(*filename); + *filename = NULL; + } + + return ret; +} + +static int wm_adsp_request_firmware_files(struct wm_adsp *dsp, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) +{ + int ret = 0; + + ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw"); + if (ret != 0) + return ret; + + wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin"); + + return 0; +} + +static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, + const char * const file, + unsigned int pos, + const struct firmware *firmware) { const struct wmfw_adsp2_sizes *adsp2_sizes; adsp2_sizes = (void *)&firmware->data[pos]; - adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, - le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), - le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); + cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, + le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), + le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm)); return pos + sizeof(*adsp2_sizes); } -static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version) +static bool cs_dsp_validate_version(struct cs_dsp *dsp, unsigned int version) { switch (version) { case 0: - adsp_warn(dsp, "Deprecated file format %d\n", version); + cs_dsp_warn(dsp, "Deprecated file format %d\n", version); return true; case 1: case 2: @@ -1804,7 +1893,7 @@ static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version) } } -static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version) +static bool cs_dsp_halo_validate_version(struct cs_dsp *dsp, unsigned int version) { switch (version) { case 3: @@ -1814,65 +1903,52 @@ static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version) } } -static int wm_adsp_load(struct wm_adsp *dsp) +static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + const char *file) { LIST_HEAD(buf_list); - const struct firmware *firmware; struct regmap *regmap = dsp->regmap; unsigned int pos = 0; const struct wmfw_header *header; const struct wmfw_adsp1_sizes *adsp1_sizes; const struct wmfw_footer *footer; const struct wmfw_region *region; - const struct wm_adsp_region *mem; + const struct cs_dsp_region *mem; const char *region_name; - char *file, *text = NULL; - struct wm_adsp_buf *buf; + char *text = NULL; + struct cs_dsp_buf *buf; unsigned int reg; int regions = 0; int ret, offset, type; - file = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (file == NULL) - return -ENOMEM; - - snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name, - wm_adsp_fw[dsp->fw].file); - file[PAGE_SIZE - 1] = '\0'; - - ret = request_firmware(&firmware, file, dsp->dev); - if (ret != 0) { - adsp_err(dsp, "Failed to request '%s'\n", file); - goto out; - } ret = -EINVAL; pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); if (pos >= firmware->size) { - adsp_err(dsp, "%s: file too short, %zu bytes\n", - file, firmware->size); + cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); goto out_fw; } header = (void *)&firmware->data[0]; if (memcmp(&header->magic[0], "WMFW", 4) != 0) { - adsp_err(dsp, "%s: invalid magic\n", file); + cs_dsp_err(dsp, "%s: invalid magic\n", file); goto out_fw; } if (!dsp->ops->validate_version(dsp, header->ver)) { - adsp_err(dsp, "%s: unknown file format %d\n", - file, header->ver); + cs_dsp_err(dsp, "%s: unknown file format %d\n", + file, header->ver); goto out_fw; } - adsp_info(dsp, "Firmware version: %d\n", header->ver); + cs_dsp_info(dsp, "Firmware version: %d\n", header->ver); dsp->fw_ver = header->ver; if (header->core != dsp->type) { - adsp_err(dsp, "%s: invalid core %d != %d\n", - file, header->core, dsp->type); + cs_dsp_err(dsp, "%s: invalid core %d != %d\n", + file, header->core, dsp->type); goto out_fw; } @@ -1883,13 +1959,13 @@ static int wm_adsp_load(struct wm_adsp *dsp) pos += sizeof(*footer); if (le32_to_cpu(header->len) != pos) { - adsp_err(dsp, "%s: unexpected header length %d\n", - file, le32_to_cpu(header->len)); + cs_dsp_err(dsp, "%s: unexpected header length %d\n", + file, le32_to_cpu(header->len)); goto out_fw; } - adsp_dbg(dsp, "%s: timestamp %llu\n", file, - le64_to_cpu(footer->timestamp)); + cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, + le64_to_cpu(footer->timestamp)); while (pos < firmware->size && sizeof(*region) < firmware->size - pos) { @@ -1908,7 +1984,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) break; case WMFW_ALGORITHM_DATA: region_name = "Algorithm"; - ret = wm_adsp_parse_coeff(dsp, region); + ret = cs_dsp_parse_coeff(dsp, region); if (ret != 0) goto out_fw; break; @@ -1929,50 +2005,50 @@ static int wm_adsp_load(struct wm_adsp *dsp) case WMFW_HALO_PM_PACKED: case WMFW_HALO_XM_PACKED: case WMFW_HALO_YM_PACKED: - mem = wm_adsp_find_region(dsp, type); + mem = cs_dsp_find_region(dsp, type); if (!mem) { - adsp_err(dsp, "No region of type: %x\n", type); + cs_dsp_err(dsp, "No region of type: %x\n", type); ret = -EINVAL; goto out_fw; } - region_name = wm_adsp_mem_region_name(type); + region_name = cs_dsp_mem_region_name(type); reg = dsp->ops->region_to_reg(mem, offset); break; default: - adsp_warn(dsp, - "%s.%d: Unknown region type %x at %d(%x)\n", - file, regions, type, pos, pos); + cs_dsp_warn(dsp, + "%s.%d: Unknown region type %x at %d(%x)\n", + file, regions, type, pos, pos); break; } - adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, - regions, le32_to_cpu(region->len), offset, - region_name); + cs_dsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, + regions, le32_to_cpu(region->len), offset, + region_name); if (le32_to_cpu(region->len) > firmware->size - pos - sizeof(*region)) { - adsp_err(dsp, - "%s.%d: %s region len %d bytes exceeds file length %zu\n", - file, regions, region_name, - le32_to_cpu(region->len), firmware->size); + cs_dsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, regions, region_name, + le32_to_cpu(region->len), firmware->size); ret = -EINVAL; goto out_fw; } if (text) { memcpy(text, region->data, le32_to_cpu(region->len)); - adsp_info(dsp, "%s: %s\n", file, text); + cs_dsp_info(dsp, "%s: %s\n", file, text); kfree(text); text = NULL; } if (reg) { - buf = wm_adsp_buf_alloc(region->data, - le32_to_cpu(region->len), - &buf_list); + buf = cs_dsp_buf_alloc(region->data, + le32_to_cpu(region->len), + &buf_list); if (!buf) { - adsp_err(dsp, "Out of memory\n"); + cs_dsp_err(dsp, "Out of memory\n"); ret = -ENOMEM; goto out_fw; } @@ -1980,11 +2056,11 @@ static int wm_adsp_load(struct wm_adsp *dsp) ret = regmap_raw_write_async(regmap, reg, buf->buf, le32_to_cpu(region->len)); if (ret != 0) { - adsp_err(dsp, - "%s.%d: Failed to write %d bytes at %d in %s: %d\n", - file, regions, - le32_to_cpu(region->len), offset, - region_name, ret); + cs_dsp_err(dsp, + "%s.%d: Failed to write %d bytes at %d in %s: %d\n", + file, regions, + le32_to_cpu(region->len), offset, + region_name, ret); goto out_fw; } } @@ -1995,43 +2071,39 @@ static int wm_adsp_load(struct wm_adsp *dsp) ret = regmap_async_complete(regmap); if (ret != 0) { - adsp_err(dsp, "Failed to complete async write: %d\n", ret); + cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); goto out_fw; } if (pos > firmware->size) - adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", - file, regions, pos - firmware->size); + cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, regions, pos - firmware->size); - wm_adsp_debugfs_save_wmfwname(dsp, file); + cs_dsp_debugfs_save_wmfwname(dsp, file); out_fw: regmap_async_complete(regmap); - wm_adsp_buf_free(&buf_list); - release_firmware(firmware); + cs_dsp_buf_free(&buf_list); kfree(text); -out: - kfree(file); return ret; } /* - * Find wm_coeff_ctl with input name as its subname + * Find cs_dsp_coeff_ctl with input name as its subname * If not found, return NULL */ -static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp, - const char *name, int type, - unsigned int alg) +static struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, + const char *name, int type, + unsigned int alg) { - struct wm_coeff_ctl *pos, *rslt = NULL; - const char *fw_txt = wm_adsp_fw_text[dsp->fw]; + struct cs_dsp_coeff_ctl *pos, *rslt = NULL; list_for_each_entry(pos, &dsp->ctl_list, list) { if (!pos->subname) continue; if (strncmp(pos->subname, name, pos->subname_len) == 0 && - pos->fw_name == fw_txt && + pos->fw_name == dsp->fw_name && pos->alg_region.alg == alg && pos->alg_region.type == type) { rslt = pos; @@ -2045,23 +2117,26 @@ static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp, int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { + struct cs_dsp_coeff_ctl *cs_ctl; struct wm_coeff_ctl *ctl; struct snd_kcontrol *kcontrol; char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ret; - ctl = wm_adsp_get_ctl(dsp, name, type, alg); - if (!ctl) + cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); + if (!cs_ctl) return -EINVAL; - if (len > ctl->len) + ctl = cs_ctl->priv; + + if (len > cs_ctl->len) return -EINVAL; - ret = wm_coeff_write_ctrl(ctl, buf, len); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, buf, len); if (ret) return ret; - if (ctl->flags & WMFW_CTL_FLAG_SYS) + if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) return 0; if (dsp->component->name_prefix) @@ -2087,26 +2162,26 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *cs_ctl; - ctl = wm_adsp_get_ctl(dsp, name, type, alg); - if (!ctl) + cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); + if (!cs_ctl) return -EINVAL; - if (len > ctl->len) + if (len > cs_ctl->len) return -EINVAL; - return wm_coeff_read_ctrl(ctl, buf, len); + return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len); } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); -static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, - const struct wm_adsp_alg_region *alg_region) +static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, + const struct cs_dsp_alg_region *alg_region) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *ctl; list_for_each_entry(ctl, &dsp->ctl_list, list) { - if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && + if (ctl->fw_name == dsp->fw_name && alg_region->alg == ctl->alg_region.alg && alg_region->type == ctl->alg_region.type) { ctl->alg_region.base = alg_region->base; @@ -2114,9 +2189,9 @@ static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, } } -static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, - const struct wm_adsp_region *mem, - unsigned int pos, unsigned int len) +static void *cs_dsp_read_algs(struct cs_dsp *dsp, size_t n_algs, + const struct cs_dsp_region *mem, + unsigned int pos, unsigned int len) { void *alg; unsigned int reg; @@ -2124,12 +2199,12 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, __be32 val; if (n_algs == 0) { - adsp_err(dsp, "No algorithms\n"); + cs_dsp_err(dsp, "No algorithms\n"); return ERR_PTR(-EINVAL); } if (n_algs > 1024) { - adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); + cs_dsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); return ERR_PTR(-EINVAL); } @@ -2138,14 +2213,14 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm list end: %d\n", - ret); + cs_dsp_err(dsp, "Failed to read algorithm list end: %d\n", + ret); return ERR_PTR(ret); } if (be32_to_cpu(val) != 0xbedead) - adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", - reg, be32_to_cpu(val)); + cs_dsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", + reg, be32_to_cpu(val)); /* Convert length from DSP words to bytes */ len *= sizeof(u32); @@ -2158,7 +2233,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, ret = regmap_raw_read(dsp->regmap, reg, alg, len); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm list: %d\n", ret); + cs_dsp_err(dsp, "Failed to read algorithm list: %d\n", ret); kfree(alg); return ERR_PTR(ret); } @@ -2166,10 +2241,10 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, return alg; } -static struct wm_adsp_alg_region * - wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id) +static struct cs_dsp_alg_region * + cs_dsp_find_alg_region(struct cs_dsp *dsp, int type, unsigned int id) { - struct wm_adsp_alg_region *alg_region; + struct cs_dsp_alg_region *alg_region; list_for_each_entry(alg_region, &dsp->alg_regions, list) { if (id == alg_region->alg && type == alg_region->type) @@ -2179,11 +2254,11 @@ static struct wm_adsp_alg_region * return NULL; } -static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, - int type, __be32 id, - __be32 base) +static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, + int type, __be32 id, + __be32 base) { - struct wm_adsp_alg_region *alg_region; + struct cs_dsp_alg_region *alg_region; alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); if (!alg_region) @@ -2196,58 +2271,58 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, list_add_tail(&alg_region->list, &dsp->alg_regions); if (dsp->fw_ver > 0) - wm_adsp_ctl_fixup_base(dsp, alg_region); + cs_dsp_ctl_fixup_base(dsp, alg_region); return alg_region; } -static void wm_adsp_free_alg_regions(struct wm_adsp *dsp) +static void cs_dsp_free_alg_regions(struct cs_dsp *dsp) { - struct wm_adsp_alg_region *alg_region; + struct cs_dsp_alg_region *alg_region; while (!list_empty(&dsp->alg_regions)) { alg_region = list_first_entry(&dsp->alg_regions, - struct wm_adsp_alg_region, + struct cs_dsp_alg_region, list); list_del(&alg_region->list); kfree(alg_region); } } -static void wmfw_parse_id_header(struct wm_adsp *dsp, - struct wmfw_id_hdr *fw, int nalgs) +static void cs_dsp_parse_wmfw_id_header(struct cs_dsp *dsp, + struct wmfw_id_hdr *fw, int nalgs) { dsp->fw_id = be32_to_cpu(fw->id); dsp->fw_id_version = be32_to_cpu(fw->ver); - adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", - dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, - (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, - nalgs); + cs_dsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n", + dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16, + (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, + nalgs); } -static void wmfw_v3_parse_id_header(struct wm_adsp *dsp, - struct wmfw_v3_id_hdr *fw, int nalgs) +static void cs_dsp_parse_wmfw_v3_id_header(struct cs_dsp *dsp, + struct wmfw_v3_id_hdr *fw, int nalgs) { dsp->fw_id = be32_to_cpu(fw->id); dsp->fw_id_version = be32_to_cpu(fw->ver); dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id); - adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", - dsp->fw_id, dsp->fw_vendor_id, - (dsp->fw_id_version & 0xff0000) >> 16, - (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, - nalgs); + cs_dsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n", + dsp->fw_id, dsp->fw_vendor_id, + (dsp->fw_id_version & 0xff0000) >> 16, + (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff, + nalgs); } -static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions, - const int *type, __be32 *base) +static int cs_dsp_create_regions(struct cs_dsp *dsp, __be32 id, int nregions, + const int *type, __be32 *base) { - struct wm_adsp_alg_region *alg_region; + struct cs_dsp_alg_region *alg_region; int i; for (i = 0; i < nregions; i++) { - alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]); + alg_region = cs_dsp_create_region(dsp, type[i], id, base[i]); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); } @@ -2255,39 +2330,39 @@ static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions, return 0; } -static int wm_adsp1_setup_algs(struct wm_adsp *dsp) +static int cs_dsp_adsp1_setup_algs(struct cs_dsp *dsp) { struct wmfw_adsp1_id_hdr adsp1_id; struct wmfw_adsp1_alg_hdr *adsp1_alg; - struct wm_adsp_alg_region *alg_region; - const struct wm_adsp_region *mem; + struct cs_dsp_alg_region *alg_region; + const struct cs_dsp_region *mem; unsigned int pos, len; size_t n_algs; int i, ret; - mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); + mem = cs_dsp_find_region(dsp, WMFW_ADSP1_DM); if (WARN_ON(!mem)) return -EINVAL; ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id, sizeof(adsp1_id)); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm info: %d\n", - ret); + cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); return ret; } n_algs = be32_to_cpu(adsp1_id.n_algs); - wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs); + cs_dsp_parse_wmfw_id_header(dsp, &adsp1_id.fw, n_algs); - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, - adsp1_id.fw.id, adsp1_id.zm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, + adsp1_id.fw.id, adsp1_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, - adsp1_id.fw.id, adsp1_id.dm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, + adsp1_id.fw.id, adsp1_id.dm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -2295,22 +2370,22 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) pos = sizeof(adsp1_id) / sizeof(u32); len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32); - adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); + adsp1_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); if (IS_ERR(adsp1_alg)) return PTR_ERR(adsp1_alg); for (i = 0; i < n_algs; i++) { - adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", - i, be32_to_cpu(adsp1_alg[i].alg.id), - (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, - be32_to_cpu(adsp1_alg[i].dm), - be32_to_cpu(adsp1_alg[i].zm)); - - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, - adsp1_alg[i].alg.id, - adsp1_alg[i].dm); + cs_dsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", + i, be32_to_cpu(adsp1_alg[i].alg.id), + (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, + be32_to_cpu(adsp1_alg[i].dm), + be32_to_cpu(adsp1_alg[i].zm)); + + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_DM, + adsp1_alg[i].alg.id, + adsp1_alg[i].dm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); goto out; @@ -2320,18 +2395,18 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len = be32_to_cpu(adsp1_alg[i + 1].dm); len -= be32_to_cpu(adsp1_alg[i].dm); len *= 4; - wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0, - SNDRV_CTL_ELEM_TYPE_BYTES); + cs_dsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + WMFW_CTL_TYPE_BYTES); } else { - adsp_warn(dsp, "Missing length info for region DM with ID %x\n", - be32_to_cpu(adsp1_alg[i].alg.id)); + cs_dsp_warn(dsp, "Missing length info for region DM with ID %x\n", + be32_to_cpu(adsp1_alg[i].alg.id)); } } - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, - adsp1_alg[i].alg.id, - adsp1_alg[i].zm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP1_ZM, + adsp1_alg[i].alg.id, + adsp1_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); goto out; @@ -2341,12 +2416,12 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len = be32_to_cpu(adsp1_alg[i + 1].zm); len -= be32_to_cpu(adsp1_alg[i].zm); len *= 4; - wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0, - SNDRV_CTL_ELEM_TYPE_BYTES); + cs_dsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + WMFW_CTL_TYPE_BYTES); } else { - adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", - be32_to_cpu(adsp1_alg[i].alg.id)); + cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", + be32_to_cpu(adsp1_alg[i].alg.id)); } } } @@ -2356,44 +2431,44 @@ out: return ret; } -static int wm_adsp2_setup_algs(struct wm_adsp *dsp) +static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) { struct wmfw_adsp2_id_hdr adsp2_id; struct wmfw_adsp2_alg_hdr *adsp2_alg; - struct wm_adsp_alg_region *alg_region; - const struct wm_adsp_region *mem; + struct cs_dsp_alg_region *alg_region; + const struct cs_dsp_region *mem; unsigned int pos, len; size_t n_algs; int i, ret; - mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); + mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); if (WARN_ON(!mem)) return -EINVAL; ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id, sizeof(adsp2_id)); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm info: %d\n", - ret); + cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); return ret; } n_algs = be32_to_cpu(adsp2_id.n_algs); - wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs); + cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs); - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, - adsp2_id.fw.id, adsp2_id.xm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, + adsp2_id.fw.id, adsp2_id.xm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, - adsp2_id.fw.id, adsp2_id.ym); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, + adsp2_id.fw.id, adsp2_id.ym); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, - adsp2_id.fw.id, adsp2_id.zm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, + adsp2_id.fw.id, adsp2_id.zm); if (IS_ERR(alg_region)) return PTR_ERR(alg_region); @@ -2401,24 +2476,24 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) pos = sizeof(adsp2_id) / sizeof(u32); len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32); - adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); + adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); if (IS_ERR(adsp2_alg)) return PTR_ERR(adsp2_alg); for (i = 0; i < n_algs; i++) { - adsp_info(dsp, - "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", - i, be32_to_cpu(adsp2_alg[i].alg.id), - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, - be32_to_cpu(adsp2_alg[i].xm), - be32_to_cpu(adsp2_alg[i].ym), - be32_to_cpu(adsp2_alg[i].zm)); - - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, - adsp2_alg[i].alg.id, - adsp2_alg[i].xm); + cs_dsp_info(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", + i, be32_to_cpu(adsp2_alg[i].alg.id), + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, + be32_to_cpu(adsp2_alg[i].xm), + be32_to_cpu(adsp2_alg[i].ym), + be32_to_cpu(adsp2_alg[i].zm)); + + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, + adsp2_alg[i].alg.id, + adsp2_alg[i].xm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); goto out; @@ -2428,18 +2503,18 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len = be32_to_cpu(adsp2_alg[i + 1].xm); len -= be32_to_cpu(adsp2_alg[i].xm); len *= 4; - wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0, - SNDRV_CTL_ELEM_TYPE_BYTES); + cs_dsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + WMFW_CTL_TYPE_BYTES); } else { - adsp_warn(dsp, "Missing length info for region XM with ID %x\n", - be32_to_cpu(adsp2_alg[i].alg.id)); + cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); } } - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, - adsp2_alg[i].alg.id, - adsp2_alg[i].ym); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM, + adsp2_alg[i].alg.id, + adsp2_alg[i].ym); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); goto out; @@ -2449,18 +2524,18 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len = be32_to_cpu(adsp2_alg[i + 1].ym); len -= be32_to_cpu(adsp2_alg[i].ym); len *= 4; - wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0, - SNDRV_CTL_ELEM_TYPE_BYTES); + cs_dsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + WMFW_CTL_TYPE_BYTES); } else { - adsp_warn(dsp, "Missing length info for region YM with ID %x\n", - be32_to_cpu(adsp2_alg[i].alg.id)); + cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); } } - alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, - adsp2_alg[i].alg.id, - adsp2_alg[i].zm); + alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM, + adsp2_alg[i].alg.id, + adsp2_alg[i].zm); if (IS_ERR(alg_region)) { ret = PTR_ERR(alg_region); goto out; @@ -2470,12 +2545,12 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len = be32_to_cpu(adsp2_alg[i + 1].zm); len -= be32_to_cpu(adsp2_alg[i].zm); len *= 4; - wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0, - SNDRV_CTL_ELEM_TYPE_BYTES); + cs_dsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + WMFW_CTL_TYPE_BYTES); } else { - adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", - be32_to_cpu(adsp2_alg[i].alg.id)); + cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); } } } @@ -2485,8 +2560,8 @@ out: return ret; } -static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id, - __be32 xm_base, __be32 ym_base) +static int cs_dsp_halo_create_regions(struct cs_dsp *dsp, __be32 id, + __be32 xm_base, __be32 ym_base) { static const int types[] = { WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, @@ -2494,36 +2569,36 @@ static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id, }; __be32 bases[] = { xm_base, xm_base, ym_base, ym_base }; - return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); + return cs_dsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases); } -static int wm_halo_setup_algs(struct wm_adsp *dsp) +static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) { struct wmfw_halo_id_hdr halo_id; struct wmfw_halo_alg_hdr *halo_alg; - const struct wm_adsp_region *mem; + const struct cs_dsp_region *mem; unsigned int pos, len; size_t n_algs; int i, ret; - mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); + mem = cs_dsp_find_region(dsp, WMFW_ADSP2_XM); if (WARN_ON(!mem)) return -EINVAL; ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id, sizeof(halo_id)); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm info: %d\n", - ret); + cs_dsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); return ret; } n_algs = be32_to_cpu(halo_id.n_algs); - wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs); + cs_dsp_parse_wmfw_v3_id_header(dsp, &halo_id.fw, n_algs); - ret = wm_halo_create_regions(dsp, halo_id.fw.id, - halo_id.xm_base, halo_id.ym_base); + ret = cs_dsp_halo_create_regions(dsp, halo_id.fw.id, + halo_id.xm_base, halo_id.ym_base); if (ret) return ret; @@ -2531,23 +2606,23 @@ static int wm_halo_setup_algs(struct wm_adsp *dsp) pos = sizeof(halo_id) / sizeof(u32); len = (sizeof(*halo_alg) * n_algs) / sizeof(u32); - halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len); + halo_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len); if (IS_ERR(halo_alg)) return PTR_ERR(halo_alg); for (i = 0; i < n_algs; i++) { - adsp_info(dsp, - "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", - i, be32_to_cpu(halo_alg[i].alg.id), - (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(halo_alg[i].alg.ver) & 0xff, - be32_to_cpu(halo_alg[i].xm_base), - be32_to_cpu(halo_alg[i].ym_base)); - - ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id, - halo_alg[i].xm_base, - halo_alg[i].ym_base); + cs_dsp_info(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", + i, be32_to_cpu(halo_alg[i].alg.id), + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(halo_alg[i].alg.ver) & 0xff, + be32_to_cpu(halo_alg[i].xm_base), + be32_to_cpu(halo_alg[i].ym_base)); + + ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, + halo_alg[i].xm_base, + halo_alg[i].ym_base); if (ret) goto out; } @@ -2557,45 +2632,33 @@ out: return ret; } -static int wm_adsp_load_coeff(struct wm_adsp *dsp) +static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware, + const char *file) { LIST_HEAD(buf_list); struct regmap *regmap = dsp->regmap; struct wmfw_coeff_hdr *hdr; struct wmfw_coeff_item *blk; - const struct firmware *firmware; - const struct wm_adsp_region *mem; - struct wm_adsp_alg_region *alg_region; + const struct cs_dsp_region *mem; + struct cs_dsp_alg_region *alg_region; const char *region_name; int ret, pos, blocks, type, offset, reg; - char *file; - struct wm_adsp_buf *buf; - - file = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (file == NULL) - return -ENOMEM; + struct cs_dsp_buf *buf; - snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name, - wm_adsp_fw[dsp->fw].file); - file[PAGE_SIZE - 1] = '\0'; + if (!firmware) + return 0; - ret = request_firmware(&firmware, file, dsp->dev); - if (ret != 0) { - adsp_warn(dsp, "Failed to request '%s'\n", file); - ret = 0; - goto out; - } ret = -EINVAL; if (sizeof(*hdr) >= firmware->size) { - adsp_err(dsp, "%s: file too short, %zu bytes\n", - file, firmware->size); + cs_dsp_err(dsp, "%s: coefficient file too short, %zu bytes\n", + file, firmware->size); goto out_fw; } hdr = (void *)&firmware->data[0]; if (memcmp(hdr->magic, "WMDR", 4) != 0) { - adsp_err(dsp, "%s: invalid magic\n", file); + cs_dsp_err(dsp, "%s: invalid coefficient magic\n", file); goto out_fw; } @@ -2603,16 +2666,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) case 1: break; default: - adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", - file, be32_to_cpu(hdr->rev) & 0xff); + cs_dsp_err(dsp, "%s: Unsupported coefficient file format %d\n", + file, be32_to_cpu(hdr->rev) & 0xff); ret = -EINVAL; goto out_fw; } - adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, - (le32_to_cpu(hdr->ver) >> 16) & 0xff, - (le32_to_cpu(hdr->ver) >> 8) & 0xff, - le32_to_cpu(hdr->ver) & 0xff); + cs_dsp_dbg(dsp, "%s: v%d.%d.%d\n", file, + (le32_to_cpu(hdr->ver) >> 16) & 0xff, + (le32_to_cpu(hdr->ver) >> 8) & 0xff, + le32_to_cpu(hdr->ver) & 0xff); pos = le32_to_cpu(hdr->len); @@ -2624,13 +2687,13 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) type = le16_to_cpu(blk->type); offset = le16_to_cpu(blk->offset); - adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", - file, blocks, le32_to_cpu(blk->id), - (le32_to_cpu(blk->ver) >> 16) & 0xff, - (le32_to_cpu(blk->ver) >> 8) & 0xff, - le32_to_cpu(blk->ver) & 0xff); - adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", - file, blocks, le32_to_cpu(blk->len), offset, type); + cs_dsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", + file, blocks, le32_to_cpu(blk->id), + (le32_to_cpu(blk->ver) >> 16) & 0xff, + (le32_to_cpu(blk->ver) >> 8) & 0xff, + le32_to_cpu(blk->ver) & 0xff); + cs_dsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", + file, blocks, le32_to_cpu(blk->len), offset, type); reg = 0; region_name = "Unknown"; @@ -2647,9 +2710,9 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) if (le32_to_cpu(blk->id) == dsp->fw_id && offset == 0) { region_name = "global coefficients"; - mem = wm_adsp_find_region(dsp, type); + mem = cs_dsp_find_region(dsp, type); if (!mem) { - adsp_err(dsp, "No ZM\n"); + cs_dsp_err(dsp, "No ZM\n"); break; } reg = dsp->ops->region_to_reg(mem, 0); @@ -2667,64 +2730,64 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) case WMFW_HALO_XM_PACKED: case WMFW_HALO_YM_PACKED: case WMFW_HALO_PM_PACKED: - adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", - file, blocks, le32_to_cpu(blk->len), - type, le32_to_cpu(blk->id)); + cs_dsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", + file, blocks, le32_to_cpu(blk->len), + type, le32_to_cpu(blk->id)); - mem = wm_adsp_find_region(dsp, type); + mem = cs_dsp_find_region(dsp, type); if (!mem) { - adsp_err(dsp, "No base for region %x\n", type); + cs_dsp_err(dsp, "No base for region %x\n", type); break; } - alg_region = wm_adsp_find_alg_region(dsp, type, - le32_to_cpu(blk->id)); + alg_region = cs_dsp_find_alg_region(dsp, type, + le32_to_cpu(blk->id)); if (alg_region) { reg = alg_region->base; reg = dsp->ops->region_to_reg(mem, reg); reg += offset; } else { - adsp_err(dsp, "No %x for algorithm %x\n", - type, le32_to_cpu(blk->id)); + cs_dsp_err(dsp, "No %x for algorithm %x\n", + type, le32_to_cpu(blk->id)); } break; default: - adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", - file, blocks, type, pos); + cs_dsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", + file, blocks, type, pos); break; } if (reg) { if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { - adsp_err(dsp, - "%s.%d: %s region len %d bytes exceeds file length %zu\n", - file, blocks, region_name, - le32_to_cpu(blk->len), - firmware->size); + cs_dsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, blocks, region_name, + le32_to_cpu(blk->len), + firmware->size); ret = -EINVAL; goto out_fw; } - buf = wm_adsp_buf_alloc(blk->data, - le32_to_cpu(blk->len), - &buf_list); + buf = cs_dsp_buf_alloc(blk->data, + le32_to_cpu(blk->len), + &buf_list); if (!buf) { - adsp_err(dsp, "Out of memory\n"); + cs_dsp_err(dsp, "Out of memory\n"); ret = -ENOMEM; goto out_fw; } - adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", - file, blocks, le32_to_cpu(blk->len), - reg); + cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", + file, blocks, le32_to_cpu(blk->len), + reg); ret = regmap_raw_write_async(regmap, reg, buf->buf, le32_to_cpu(blk->len)); if (ret != 0) { - adsp_err(dsp, - "%s.%d: Failed to write to %x in %s: %d\n", - file, blocks, reg, region_name, ret); + cs_dsp_err(dsp, + "%s.%d: Failed to write to %x in %s: %d\n", + file, blocks, reg, region_name, ret); } } @@ -2734,27 +2797,22 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ret = regmap_async_complete(regmap); if (ret != 0) - adsp_err(dsp, "Failed to complete async write: %d\n", ret); + cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret); if (pos > firmware->size) - adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", - file, blocks, pos - firmware->size); + cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, blocks, pos - firmware->size); - wm_adsp_debugfs_save_binname(dsp, file); + cs_dsp_debugfs_save_binname(dsp, file); out_fw: regmap_async_complete(regmap); - release_firmware(firmware); - wm_adsp_buf_free(&buf_list); -out: - kfree(file); + cs_dsp_buf_free(&buf_list); return ret; } -static int wm_adsp_create_name(struct wm_adsp *dsp) +static int cs_dsp_create_name(struct cs_dsp *dsp) { - char *p; - if (!dsp->name) { dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d", dsp->num); @@ -2762,161 +2820,217 @@ static int wm_adsp_create_name(struct wm_adsp *dsp) return -ENOMEM; } - if (!dsp->fwf_name) { - p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL); - if (!p) - return -ENOMEM; - - dsp->fwf_name = p; - for (; *p != 0; ++p) - *p = tolower(*p); - } - return 0; } -static int wm_adsp_common_init(struct wm_adsp *dsp) +static int cs_dsp_common_init(struct cs_dsp *dsp) { int ret; - ret = wm_adsp_create_name(dsp); + ret = cs_dsp_create_name(dsp); if (ret) return ret; INIT_LIST_HEAD(&dsp->alg_regions); INIT_LIST_HEAD(&dsp->ctl_list); + + mutex_init(&dsp->pwr_lock); + + return 0; +} + +static int wm_adsp_common_init(struct wm_adsp *dsp) +{ + char *p; + INIT_LIST_HEAD(&dsp->compr_list); INIT_LIST_HEAD(&dsp->buffer_list); - mutex_init(&dsp->pwr_lock); + if (!dsp->fwf_name) { + p = devm_kstrdup(dsp->cs_dsp.dev, dsp->cs_dsp.name, GFP_KERNEL); + if (!p) + return -ENOMEM; + + dsp->fwf_name = p; + for (; *p != 0; ++p) + *p = tolower(*p); + } return 0; } +static int cs_dsp_adsp1_init(struct cs_dsp *dsp) +{ + dsp->ops = &cs_dsp_adsp1_ops; + + return cs_dsp_common_init(dsp); +} + int wm_adsp1_init(struct wm_adsp *dsp) { - dsp->ops = &wm_adsp1_ops; + int ret; + + dsp->cs_dsp.client_ops = &wm_adsp1_client_ops; + + ret = cs_dsp_adsp1_init(&dsp->cs_dsp); + if (ret) + return ret; return wm_adsp_common_init(dsp); } EXPORT_SYMBOL_GPL(wm_adsp1_init); -int wm_adsp1_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +static int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, + const struct firmware *wmfw_firmware, char *wmfw_filename, + const struct firmware *coeff_firmware, char *coeff_filename, + const char *fw_name) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); - struct wm_adsp *dsp = &dsps[w->shift]; - struct wm_coeff_ctl *ctl; - int ret; unsigned int val; - - dsp->component = component; + int ret; mutex_lock(&dsp->pwr_lock); - switch (event) { - case SND_SOC_DAPM_POST_PMU: - regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, - ADSP1_SYS_ENA, ADSP1_SYS_ENA); - - /* - * For simplicity set the DSP clock rate to be the - * SYSCLK rate rather than making it configurable. - */ - if (dsp->sysclk_reg) { - ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); - if (ret != 0) { - adsp_err(dsp, "Failed to read SYSCLK state: %d\n", - ret); - goto err_mutex; - } + dsp->fw_name = fw_name; - val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, ADSP1_SYS_ENA); - ret = regmap_update_bits(dsp->regmap, - dsp->base + ADSP1_CONTROL_31, - ADSP1_CLK_SEL_MASK, val); - if (ret != 0) { - adsp_err(dsp, "Failed to set clock rate: %d\n", - ret); - goto err_mutex; - } + /* + * For simplicity set the DSP clock rate to be the + * SYSCLK rate rather than making it configurable. + */ + if (dsp->sysclk_reg) { + ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); + if (ret != 0) { + cs_dsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); + goto err_mutex; } - ret = wm_adsp_load(dsp); - if (ret != 0) - goto err_ena; + val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; - ret = wm_adsp1_setup_algs(dsp); - if (ret != 0) - goto err_ena; + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP1_CONTROL_31, + ADSP1_CLK_SEL_MASK, val); + if (ret != 0) { + cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); + goto err_mutex; + } + } - ret = wm_adsp_load_coeff(dsp); - if (ret != 0) - goto err_ena; + ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); + if (ret != 0) + goto err_ena; - /* Initialize caches for enabled and unset controls */ - ret = wm_coeff_init_control_caches(dsp); - if (ret != 0) - goto err_ena; + ret = cs_dsp_adsp1_setup_algs(dsp); + if (ret != 0) + goto err_ena; - /* Sync set controls */ - ret = wm_coeff_sync_controls(dsp); - if (ret != 0) - goto err_ena; + ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); + if (ret != 0) + goto err_ena; - dsp->booted = true; + /* Initialize caches for enabled and unset controls */ + ret = cs_dsp_coeff_init_control_caches(dsp); + if (ret != 0) + goto err_ena; - /* Start the core running */ - regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, - ADSP1_CORE_ENA | ADSP1_START, - ADSP1_CORE_ENA | ADSP1_START); + /* Sync set controls */ + ret = cs_dsp_coeff_sync_controls(dsp); + if (ret != 0) + goto err_ena; - dsp->running = true; - break; + dsp->booted = true; - case SND_SOC_DAPM_PRE_PMD: - dsp->running = false; - dsp->booted = false; + /* Start the core running */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, + ADSP1_CORE_ENA | ADSP1_START); - /* Halt the core */ - regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, - ADSP1_CORE_ENA | ADSP1_START, 0); + dsp->running = true; - regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, - ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); + mutex_unlock(&dsp->pwr_lock); - regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, - ADSP1_SYS_ENA, 0); + return 0; - list_for_each_entry(ctl, &dsp->ctl_list, list) - ctl->enabled = 0; +err_ena: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); + return ret; +} +static void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) +{ + struct cs_dsp_coeff_ctl *ctl; - wm_adsp_free_alg_regions(dsp); - break; + mutex_lock(&dsp->pwr_lock); - default: - break; - } + dsp->running = false; + dsp->booted = false; - mutex_unlock(&dsp->pwr_lock); + /* Halt the core */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, 0); - return 0; + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, + ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); -err_ena: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_SYS_ENA, 0); -err_mutex: + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + cs_dsp_free_alg_regions(dsp); + mutex_unlock(&dsp->pwr_lock); +} + +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret = 0; + char *wmfw_filename = NULL; + const struct firmware *wmfw_firmware = NULL; + char *coeff_filename = NULL; + const struct firmware *coeff_firmware = NULL; + + dsp->component = component; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret = wm_adsp_request_firmware_files(dsp, + &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret) + break; + + ret = cs_dsp_adsp1_power_up(&dsp->cs_dsp, + wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename, + wm_adsp_fw_text[dsp->fw]); + + wm_adsp_release_firmware_files(dsp, + wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); + break; + case SND_SOC_DAPM_PRE_PMD: + cs_dsp_adsp1_power_down(&dsp->cs_dsp); + break; + default: + break; + } return ret; } EXPORT_SYMBOL_GPL(wm_adsp1_event); -static int wm_adsp2v2_enable_core(struct wm_adsp *dsp) +static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) { unsigned int val; int ret, count; @@ -2934,16 +3048,16 @@ static int wm_adsp2v2_enable_core(struct wm_adsp *dsp) } if (!(val & ADSP2_RAM_RDY)) { - adsp_err(dsp, "Failed to start DSP RAM\n"); + cs_dsp_err(dsp, "Failed to start DSP RAM\n"); return -EBUSY; } - adsp_dbg(dsp, "RAM ready after %d polls\n", count); + cs_dsp_dbg(dsp, "RAM ready after %d polls\n", count); return 0; } -static int wm_adsp2_enable_core(struct wm_adsp *dsp) +static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp) { int ret; @@ -2952,18 +3066,18 @@ static int wm_adsp2_enable_core(struct wm_adsp *dsp) if (ret != 0) return ret; - return wm_adsp2v2_enable_core(dsp); + return cs_dsp_adsp2v2_enable_core(dsp); } -static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) +static int cs_dsp_adsp2_lock(struct cs_dsp *dsp, unsigned int lock_regions) { struct regmap *regmap = dsp->regmap; unsigned int code0, code1, lock_reg; - if (!(lock_regions & WM_ADSP2_REGION_ALL)) + if (!(lock_regions & CS_ADSP2_REGION_ALL)) return 0; - lock_regions &= WM_ADSP2_REGION_ALL; + lock_regions &= CS_ADSP2_REGION_ALL; lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; while (lock_regions) { @@ -2985,19 +3099,19 @@ static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) return 0; } -static int wm_adsp2_enable_memory(struct wm_adsp *dsp) +static int cs_dsp_adsp2_enable_memory(struct cs_dsp *dsp) { return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_MEM_ENA, ADSP2_MEM_ENA); } -static void wm_adsp2_disable_memory(struct wm_adsp *dsp) +static void cs_dsp_adsp2_disable_memory(struct cs_dsp *dsp) { regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_MEM_ENA, 0); } -static void wm_adsp2_disable_core(struct wm_adsp *dsp) +static void cs_dsp_adsp2_disable_core(struct cs_dsp *dsp) { regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); @@ -3007,71 +3121,14 @@ static void wm_adsp2_disable_core(struct wm_adsp *dsp) ADSP2_SYS_ENA, 0); } -static void wm_adsp2v2_disable_core(struct wm_adsp *dsp) +static void cs_dsp_adsp2v2_disable_core(struct cs_dsp *dsp) { regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); } -static void wm_adsp_boot_work(struct work_struct *work) -{ - struct wm_adsp *dsp = container_of(work, - struct wm_adsp, - boot_work); - int ret; - - mutex_lock(&dsp->pwr_lock); - - if (dsp->ops->enable_memory) { - ret = dsp->ops->enable_memory(dsp); - if (ret != 0) - goto err_mutex; - } - - if (dsp->ops->enable_core) { - ret = dsp->ops->enable_core(dsp); - if (ret != 0) - goto err_mem; - } - - ret = wm_adsp_load(dsp); - if (ret != 0) - goto err_ena; - - ret = dsp->ops->setup_algs(dsp); - if (ret != 0) - goto err_ena; - - ret = wm_adsp_load_coeff(dsp); - if (ret != 0) - goto err_ena; - - /* Initialize caches for enabled and unset controls */ - ret = wm_coeff_init_control_caches(dsp); - if (ret != 0) - goto err_ena; - - if (dsp->ops->disable_core) - dsp->ops->disable_core(dsp); - - dsp->booted = true; - - mutex_unlock(&dsp->pwr_lock); - - return; - -err_ena: - if (dsp->ops->disable_core) - dsp->ops->disable_core(dsp); -err_mem: - if (dsp->ops->disable_memory) - dsp->ops->disable_memory(dsp); -err_mutex: - mutex_unlock(&dsp->pwr_lock); -} - -static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions) +static int cs_dsp_halo_configure_mpu(struct cs_dsp *dsp, unsigned int lock_regions) { struct reg_sequence config[] = { { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 }, @@ -3102,21 +3159,27 @@ static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions) return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config)); } -int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq) +static int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); - struct wm_adsp *dsp = &dsps[w->shift]; int ret; ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING, ADSP2_CLK_SEL_MASK, freq << ADSP2_CLK_SEL_SHIFT); if (ret) - adsp_err(dsp, "Failed to set clock rate: %d\n", ret); + cs_dsp_err(dsp, "Failed to set clock rate: %d\n", ret); return ret; } + +int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); + struct wm_adsp *dsp = &dsps[w->shift]; + + return cs_dsp_set_dspclk(&dsp->cs_dsp, freq); +} EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk); int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, @@ -3145,7 +3208,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, struct wm_adsp *dsp = &dsps[mc->shift - 1]; char preload[32]; - snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name); + snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); dsp->preloaded = ucontrol->value.integer.value[0]; @@ -3162,51 +3225,144 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); -static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) +static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) { regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, ADSP2_WDT_ENA_MASK, 0); } -static void wm_halo_stop_watchdog(struct wm_adsp *dsp) +static void cs_dsp_halo_stop_watchdog(struct cs_dsp *dsp) { regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL, HALO_WDT_EN_MASK, 0); } +static int cs_dsp_power_up(struct cs_dsp *dsp, + const struct firmware *wmfw_firmware, char *wmfw_filename, + const struct firmware *coeff_firmware, char *coeff_filename, + const char *fw_name) +{ + int ret; + + mutex_lock(&dsp->pwr_lock); + + dsp->fw_name = fw_name; + + if (dsp->ops->enable_memory) { + ret = dsp->ops->enable_memory(dsp); + if (ret != 0) + goto err_mutex; + } + + if (dsp->ops->enable_core) { + ret = dsp->ops->enable_core(dsp); + if (ret != 0) + goto err_mem; + } + + ret = cs_dsp_load(dsp, wmfw_firmware, wmfw_filename); + if (ret != 0) + goto err_ena; + + ret = dsp->ops->setup_algs(dsp); + if (ret != 0) + goto err_ena; + + ret = cs_dsp_load_coeff(dsp, coeff_firmware, coeff_filename); + if (ret != 0) + goto err_ena; + + /* Initialize caches for enabled and unset controls */ + ret = cs_dsp_coeff_init_control_caches(dsp); + if (ret != 0) + goto err_ena; + + if (dsp->ops->disable_core) + dsp->ops->disable_core(dsp); + + dsp->booted = true; + + mutex_unlock(&dsp->pwr_lock); + + return 0; +err_ena: + if (dsp->ops->disable_core) + dsp->ops->disable_core(dsp); +err_mem: + if (dsp->ops->disable_memory) + dsp->ops->disable_memory(dsp); +err_mutex: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} + +static void cs_dsp_power_down(struct cs_dsp *dsp) +{ + struct cs_dsp_coeff_ctl *ctl; + + mutex_lock(&dsp->pwr_lock); + + cs_dsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; + + dsp->booted = false; + + if (dsp->ops->disable_memory) + dsp->ops->disable_memory(dsp); + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + cs_dsp_free_alg_regions(dsp); + + mutex_unlock(&dsp->pwr_lock); + + cs_dsp_dbg(dsp, "Shutdown complete\n"); +} + +static void wm_adsp_boot_work(struct work_struct *work) +{ + struct wm_adsp *dsp = container_of(work, + struct wm_adsp, + boot_work); + int ret = 0; + char *wmfw_filename = NULL; + const struct firmware *wmfw_firmware = NULL; + char *coeff_filename = NULL; + const struct firmware *coeff_firmware = NULL; + + ret = wm_adsp_request_firmware_files(dsp, + &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret) + return; + + cs_dsp_power_up(&dsp->cs_dsp, + wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename, + wm_adsp_fw_text[dsp->fw]); + + wm_adsp_release_firmware_files(dsp, + wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); +} + int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); struct wm_adsp *dsp = &dsps[w->shift]; - struct wm_coeff_ctl *ctl; switch (event) { case SND_SOC_DAPM_PRE_PMU: queue_work(system_unbound_wq, &dsp->boot_work); break; case SND_SOC_DAPM_PRE_PMD: - mutex_lock(&dsp->pwr_lock); - - wm_adsp_debugfs_clear(dsp); - - dsp->fw_id = 0; - dsp->fw_id_version = 0; - - dsp->booted = false; - - if (dsp->ops->disable_memory) - dsp->ops->disable_memory(dsp); - - list_for_each_entry(ctl, &dsp->ctl_list, list) - ctl->enabled = 0; - - wm_adsp_free_alg_regions(dsp); - - mutex_unlock(&dsp->pwr_lock); - - adsp_dbg(dsp, "Shutdown complete\n"); + cs_dsp_power_down(&dsp->cs_dsp); break; default: break; @@ -3216,121 +3372,151 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(wm_adsp_early_event); -static int wm_adsp2_start_core(struct wm_adsp *dsp) +static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) { return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, ADSP2_CORE_ENA | ADSP2_START); } -static void wm_adsp2_stop_core(struct wm_adsp *dsp) +static void cs_dsp_adsp2_stop_core(struct cs_dsp *dsp) { regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, 0); } -int wm_adsp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int wm_adsp_event_post_run(struct cs_dsp *cs_dsp) +{ + struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp); + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + return wm_adsp_buffer_init(dsp); + + return 0; +} + +static void wm_adsp_event_post_stop(struct cs_dsp *cs_dsp) +{ + struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp); + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + wm_adsp_buffer_free(dsp); + + dsp->fatal_error = false; +} + +static int cs_dsp_run(struct cs_dsp *dsp) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); - struct wm_adsp *dsp = &dsps[w->shift]; int ret; - switch (event) { - case SND_SOC_DAPM_POST_PMU: - flush_work(&dsp->boot_work); + mutex_lock(&dsp->pwr_lock); - mutex_lock(&dsp->pwr_lock); + if (!dsp->booted) { + ret = -EIO; + goto err; + } - if (!dsp->booted) { - ret = -EIO; + if (dsp->ops->enable_core) { + ret = dsp->ops->enable_core(dsp); + if (ret != 0) goto err; - } + } - if (dsp->ops->enable_core) { - ret = dsp->ops->enable_core(dsp); - if (ret != 0) - goto err; + /* Sync set controls */ + ret = cs_dsp_coeff_sync_controls(dsp); + if (ret != 0) + goto err; + + if (dsp->ops->lock_memory) { + ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); + if (ret != 0) { + cs_dsp_err(dsp, "Error configuring MPU: %d\n", ret); + goto err; } + } - /* Sync set controls */ - ret = wm_coeff_sync_controls(dsp); + if (dsp->ops->start_core) { + ret = dsp->ops->start_core(dsp); if (ret != 0) goto err; + } - if (dsp->ops->lock_memory) { - ret = dsp->ops->lock_memory(dsp, dsp->lock_regions); - if (ret != 0) { - adsp_err(dsp, "Error configuring MPU: %d\n", - ret); - goto err; - } - } + dsp->running = true; - if (dsp->ops->start_core) { - ret = dsp->ops->start_core(dsp); - if (ret != 0) - goto err; - } + if (dsp->client_ops->post_run) { + ret = dsp->client_ops->post_run(dsp); + if (ret) + goto err; + } - if (wm_adsp_fw[dsp->fw].num_caps != 0) { - ret = wm_adsp_buffer_init(dsp); - if (ret < 0) - goto err; - } + mutex_unlock(&dsp->pwr_lock); - dsp->running = true; + return 0; - mutex_unlock(&dsp->pwr_lock); - break; +err: + if (dsp->ops->stop_core) + dsp->ops->stop_core(dsp); + if (dsp->ops->disable_core) + dsp->ops->disable_core(dsp); + mutex_unlock(&dsp->pwr_lock); - case SND_SOC_DAPM_PRE_PMD: - /* Tell the firmware to cleanup */ - wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + return ret; +} - if (dsp->ops->stop_watchdog) - dsp->ops->stop_watchdog(dsp); +static void cs_dsp_stop(struct cs_dsp *dsp) +{ + /* Tell the firmware to cleanup */ + cs_dsp_signal_event_controls(dsp, CS_DSP_FW_EVENT_SHUTDOWN); - /* Log firmware state, it can be useful for analysis */ - if (dsp->ops->show_fw_status) - dsp->ops->show_fw_status(dsp); + if (dsp->ops->stop_watchdog) + dsp->ops->stop_watchdog(dsp); - mutex_lock(&dsp->pwr_lock); + /* Log firmware state, it can be useful for analysis */ + if (dsp->ops->show_fw_status) + dsp->ops->show_fw_status(dsp); - dsp->running = false; + mutex_lock(&dsp->pwr_lock); - if (dsp->ops->stop_core) - dsp->ops->stop_core(dsp); - if (dsp->ops->disable_core) - dsp->ops->disable_core(dsp); + dsp->running = false; - if (wm_adsp_fw[dsp->fw].num_caps != 0) - wm_adsp_buffer_free(dsp); + if (dsp->ops->stop_core) + dsp->ops->stop_core(dsp); + if (dsp->ops->disable_core) + dsp->ops->disable_core(dsp); - dsp->fatal_error = false; + if (dsp->client_ops->post_stop) + dsp->client_ops->post_stop(dsp); - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->pwr_lock); - adsp_dbg(dsp, "Execution stopped\n"); - break; + cs_dsp_dbg(dsp, "Execution stopped\n"); +} +int wm_adsp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + flush_work(&dsp->boot_work); + ret = cs_dsp_run(&dsp->cs_dsp); + break; + case SND_SOC_DAPM_PRE_PMD: + cs_dsp_stop(&dsp->cs_dsp); + break; default: break; } - return 0; -err: - if (dsp->ops->stop_core) - dsp->ops->stop_core(dsp); - if (dsp->ops->disable_core) - dsp->ops->disable_core(dsp); - mutex_unlock(&dsp->pwr_lock); return ret; } EXPORT_SYMBOL_GPL(wm_adsp_event); -static int wm_halo_start_core(struct wm_adsp *dsp) +static int cs_dsp_halo_start_core(struct cs_dsp *dsp) { return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, @@ -3338,7 +3524,7 @@ static int wm_halo_start_core(struct wm_adsp *dsp) HALO_CORE_RESET | HALO_CORE_EN); } -static void wm_halo_stop_core(struct wm_adsp *dsp) +static void cs_dsp_halo_stop_core(struct cs_dsp *dsp) { regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, HALO_CORE_EN, 0); @@ -3352,10 +3538,10 @@ int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *comp { char preload[32]; - snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name); + snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); snd_soc_component_disable_pin(component, preload); - wm_adsp2_init_debugfs(dsp, component); + cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root); dsp->component = component; @@ -3365,20 +3551,16 @@ EXPORT_SYMBOL_GPL(wm_adsp2_component_probe); int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component) { - wm_adsp2_cleanup_debugfs(dsp); + cs_dsp_cleanup_debugfs(&dsp->cs_dsp); return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_component_remove); -int wm_adsp2_init(struct wm_adsp *dsp) +static int cs_dsp_adsp2_init(struct cs_dsp *dsp) { int ret; - ret = wm_adsp_common_init(dsp); - if (ret) - return ret; - switch (dsp->rev) { case 0: /* @@ -3388,54 +3570,84 @@ int wm_adsp2_init(struct wm_adsp *dsp) ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_MEM_ENA, 0); if (ret) { - adsp_err(dsp, - "Failed to clear memory retention: %d\n", ret); + cs_dsp_err(dsp, + "Failed to clear memory retention: %d\n", ret); return ret; } - dsp->ops = &wm_adsp2_ops[0]; + dsp->ops = &cs_dsp_adsp2_ops[0]; break; case 1: - dsp->ops = &wm_adsp2_ops[1]; + dsp->ops = &cs_dsp_adsp2_ops[1]; break; default: - dsp->ops = &wm_adsp2_ops[2]; + dsp->ops = &cs_dsp_adsp2_ops[2]; break; } + return cs_dsp_common_init(dsp); +} + +int wm_adsp2_init(struct wm_adsp *dsp) +{ + int ret; + INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); - return 0; + dsp->sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr); + dsp->cs_dsp.client_ops = &wm_adsp2_client_ops; + + ret = cs_dsp_adsp2_init(&dsp->cs_dsp); + if (ret) + return ret; + + return wm_adsp_common_init(dsp); } EXPORT_SYMBOL_GPL(wm_adsp2_init); +static int cs_dsp_halo_init(struct cs_dsp *dsp) +{ + dsp->ops = &cs_dsp_halo_ops; + + return cs_dsp_common_init(dsp); +} + int wm_halo_init(struct wm_adsp *dsp) { int ret; - ret = wm_adsp_common_init(dsp); - if (ret) - return ret; + INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); - dsp->ops = &wm_halo_ops; + dsp->sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr); + dsp->cs_dsp.client_ops = &wm_adsp2_client_ops; - INIT_WORK(&dsp->boot_work, wm_adsp_boot_work); + ret = cs_dsp_halo_init(&dsp->cs_dsp); + if (ret) + return ret; - return 0; + return wm_adsp_common_init(dsp); } EXPORT_SYMBOL_GPL(wm_halo_init); -void wm_adsp2_remove(struct wm_adsp *dsp) +static void cs_dsp_remove(struct cs_dsp *dsp) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *ctl; while (!list_empty(&dsp->ctl_list)) { - ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, - list); + ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list); + + if (dsp->client_ops->control_remove) + dsp->client_ops->control_remove(ctl); + list_del(&ctl->list); - wm_adsp_free_ctl_blk(ctl); + cs_dsp_free_ctl_blk(ctl); } } + +void wm_adsp2_remove(struct wm_adsp *dsp) +{ + cs_dsp_remove(&dsp->cs_dsp); +} EXPORT_SYMBOL_GPL(wm_adsp2_remove); static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) @@ -3487,7 +3699,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) struct snd_soc_pcm_runtime *rtd = stream->private_data; int ret = 0; - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps == 0) { adsp_err(dsp, "%s: Firmware does not support compressed API\n", @@ -3527,7 +3739,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) stream->runtime->private_data = compr; out: - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return ret; } @@ -3539,7 +3751,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component, struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); wm_adsp_compr_detach(compr); list_del(&compr->list); @@ -3547,7 +3759,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component, kfree(compr->raw_buf); kfree(compr); - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return 0; } @@ -3566,7 +3778,7 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE || params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || - params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { + params->buffer.fragment_size % CS_DSP_DATA_WORD_SIZE) { compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n", params->buffer.fragment_size, params->buffer.fragments); @@ -3605,7 +3817,7 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) { - return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; + return compr->size.fragment_size / CS_DSP_DATA_WORD_SIZE; } int wm_adsp_compr_set_params(struct snd_soc_component *component, @@ -3661,11 +3873,11 @@ int wm_adsp_compr_get_caps(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); -static int wm_adsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type, - unsigned int mem_addr, - unsigned int num_words, __be32 *data) +static int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, + unsigned int mem_addr, + unsigned int num_words, __be32 *data) { - struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); unsigned int reg; int ret; @@ -3682,13 +3894,13 @@ static int wm_adsp_read_raw_data_block(struct wm_adsp *dsp, int mem_type, return 0; } -static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, - unsigned int mem_addr, u32 *data) +static int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, + unsigned int mem_addr, u32 *data) { __be32 raw; int ret; - ret = wm_adsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); + ret = cs_dsp_read_raw_data_block(dsp, mem_type, mem_addr, 1, &raw); if (ret < 0) return ret; @@ -3697,10 +3909,10 @@ static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, return 0; } -static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, - unsigned int mem_addr, u32 data) +static int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, + unsigned int mem_addr, u32 data) { - struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + struct cs_dsp_region const *mem = cs_dsp_find_region(dsp, mem_type); __be32 val = cpu_to_be32(data & 0x00ffffffu); unsigned int reg; @@ -3715,18 +3927,19 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, unsigned int field_offset, u32 *data) { - return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type, - buf->host_buf_ptr + field_offset, data); + return cs_dsp_read_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type, + buf->host_buf_ptr + field_offset, data); } static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, unsigned int field_offset, u32 data) { - return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type, - buf->host_buf_ptr + field_offset, data); + return cs_dsp_write_data_word(&buf->dsp->cs_dsp, buf->host_buf_mem_type, + buf->host_buf_ptr + field_offset, + data); } -static void wm_adsp_remove_padding(u32 *buf, int nwords) +static void cs_dsp_remove_padding(u32 *buf, int nwords) { const __be32 *pack_in = (__be32 *)buf; u8 *pack_out = (u8 *)buf; @@ -3810,12 +4023,12 @@ static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) { - struct wm_adsp_alg_region *alg_region; + struct cs_dsp_alg_region *alg_region; struct wm_adsp_compr_buf *buf; u32 xmalg, addr, magic; int i, ret; - alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); + alg_region = cs_dsp_find_alg_region(&dsp->cs_dsp, WMFW_ADSP2_XM, dsp->cs_dsp.fw_id); if (!alg_region) { adsp_err(dsp, "No algorithm region found\n"); return -EINVAL; @@ -3825,10 +4038,10 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) if (!buf) return -ENOMEM; - xmalg = dsp->ops->sys_config_size / sizeof(__be32); + xmalg = dsp->sys_config_size / sizeof(__be32); addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); - ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); + ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr, &magic); if (ret < 0) return ret; @@ -3837,8 +4050,8 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); for (i = 0; i < 5; ++i) { - ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, - &buf->host_buf_ptr); + ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr, + &buf->host_buf_ptr); if (ret < 0) return ret; @@ -3862,40 +4075,36 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) return 0; } -static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) +static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl) { struct wm_adsp_host_buf_coeff_v1 coeff_v1; struct wm_adsp_compr_buf *buf; - unsigned int reg, version; - __be32 bufp; + struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp); + unsigned int version; int ret, i; - ret = wm_coeff_base_reg(ctl, ®); - if (ret) - return ret; - for (i = 0; i < 5; ++i) { - ret = regmap_raw_read(ctl->dsp->regmap, reg, &bufp, sizeof(bufp)); + ret = cs_dsp_coeff_read_ctrl(cs_ctl, &coeff_v1, sizeof(coeff_v1)); if (ret < 0) return ret; - if (bufp) + if (coeff_v1.host_buf_ptr) break; usleep_range(1000, 2000); } - if (!bufp) { - adsp_err(ctl->dsp, "Failed to acquire host buffer\n"); + if (!coeff_v1.host_buf_ptr) { + adsp_err(dsp, "Failed to acquire host buffer\n"); return -EIO; } - buf = wm_adsp_buffer_alloc(ctl->dsp); + buf = wm_adsp_buffer_alloc(dsp); if (!buf) return -ENOMEM; - buf->host_buf_mem_type = ctl->alg_region.type; - buf->host_buf_ptr = be32_to_cpu(bufp); + buf->host_buf_mem_type = cs_ctl->alg_region.type; + buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr); ret = wm_adsp_buffer_populate(buf); if (ret < 0) @@ -3905,29 +4114,24 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) * v0 host_buffer coefficients didn't have versioning, so if the * control is one word, assume version 0. */ - if (ctl->len == 4) { + if (cs_ctl->len == 4) { compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; } - ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1, - sizeof(coeff_v1)); - if (ret < 0) - return ret; - version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK; version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) { - adsp_err(ctl->dsp, + adsp_err(dsp, "Host buffer coeff ver %u > supported version %u\n", version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); return -EINVAL; } - wm_adsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name)); + cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name)); - buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, + buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part, (char *)&coeff_v1.name); compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", @@ -3938,17 +4142,17 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) static int wm_adsp_buffer_init(struct wm_adsp *dsp) { - struct wm_coeff_ctl *ctl; + struct cs_dsp_coeff_ctl *cs_ctl; int ret; - list_for_each_entry(ctl, &dsp->ctl_list, list) { - if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) + list_for_each_entry(cs_ctl, &dsp->cs_dsp.ctl_list, list) { + if (cs_ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) continue; - if (!ctl->enabled) + if (!cs_ctl->enabled) continue; - ret = wm_adsp_buffer_parse_coeff(ctl); + ret = wm_adsp_buffer_parse_coeff(cs_ctl); if (ret < 0) { adsp_err(dsp, "Failed to parse coeff: %d\n", ret); goto error; @@ -4016,7 +4220,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, compr_dbg(compr, "Trigger: %d\n", cmd); - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -4052,7 +4256,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, break; } - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return ret; } @@ -4101,7 +4305,7 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) avail += wm_adsp_buffer_size(buf); compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n", - buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); + buf->read_index, write_index, avail * CS_DSP_DATA_WORD_SIZE); buf->avail = avail; @@ -4114,7 +4318,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) struct wm_adsp_compr *compr; int ret = 0; - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); if (list_empty(&dsp->buffer_list)) { ret = -ENODEV; @@ -4152,7 +4356,7 @@ out_notify: } out: - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return ret; } @@ -4182,7 +4386,7 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, compr_dbg(compr, "Pointer request\n"); - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); buf = compr->buf; @@ -4222,11 +4426,11 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, } tstamp->copied_total = compr->copied_total; - tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; + tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE; tstamp->sampling_rate = compr->sample_rate; out: - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return ret; } @@ -4264,12 +4468,12 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) return 0; /* Read data from DSP */ - ret = wm_adsp_read_raw_data_block(buf->dsp, mem_type, adsp_addr, - nwords, (__be32 *)compr->raw_buf); + ret = cs_dsp_read_raw_data_block(&buf->dsp->cs_dsp, mem_type, adsp_addr, + nwords, (__be32 *)compr->raw_buf); if (ret < 0) return ret; - wm_adsp_remove_padding(compr->raw_buf, nwords); + cs_dsp_remove_padding(compr->raw_buf, nwords); /* update read index to account for words read */ buf->read_index += nwords; @@ -4301,7 +4505,7 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, return -EIO; } - count /= WM_ADSP_DATA_WORD_SIZE; + count /= CS_DSP_DATA_WORD_SIZE; do { nwords = wm_adsp_buffer_capture_block(compr, count); @@ -4311,7 +4515,7 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, return nwords; } - nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; + nbytes = nwords * CS_DSP_DATA_WORD_SIZE; compr_dbg(compr, "Read %d bytes\n", nbytes); @@ -4338,21 +4542,22 @@ int wm_adsp_compr_copy(struct snd_soc_component *component, struct wm_adsp *dsp = compr->dsp; int ret; - mutex_lock(&dsp->pwr_lock); + mutex_lock(&dsp->cs_dsp.pwr_lock); if (stream->direction == SND_COMPRESS_CAPTURE) ret = wm_adsp_compr_read(compr, buf, count); else ret = -ENOTSUPP; - mutex_unlock(&dsp->pwr_lock); + mutex_unlock(&dsp->cs_dsp.pwr_lock); return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); -static void wm_adsp_fatal_error(struct wm_adsp *dsp) +static void wm_adsp_fatal_error(struct cs_dsp *cs_dsp) { + struct wm_adsp *dsp = container_of(cs_dsp, struct wm_adsp, cs_dsp); struct wm_adsp_compr *compr; dsp->fatal_error = true; @@ -4363,9 +4568,8 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp) } } -irqreturn_t wm_adsp2_bus_error(int irq, void *data) +static void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) { - struct wm_adsp *dsp = (struct wm_adsp *)data; unsigned int val; struct regmap *regmap = dsp->regmap; int ret = 0; @@ -4374,49 +4578,50 @@ irqreturn_t wm_adsp2_bus_error(int irq, void *data) ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); if (ret) { - adsp_err(dsp, - "Failed to read Region Lock Ctrl register: %d\n", ret); + cs_dsp_err(dsp, + "Failed to read Region Lock Ctrl register: %d\n", ret); goto error; } if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { - adsp_err(dsp, "watchdog timeout error\n"); + cs_dsp_err(dsp, "watchdog timeout error\n"); dsp->ops->stop_watchdog(dsp); - wm_adsp_fatal_error(dsp); + if (dsp->client_ops->watchdog_expired) + dsp->client_ops->watchdog_expired(dsp); } if (val & (ADSP2_ADDR_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { if (val & ADSP2_ADDR_ERR_MASK) - adsp_err(dsp, "bus error: address error\n"); + cs_dsp_err(dsp, "bus error: address error\n"); else - adsp_err(dsp, "bus error: region lock error\n"); + cs_dsp_err(dsp, "bus error: region lock error\n"); ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); if (ret) { - adsp_err(dsp, - "Failed to read Bus Err Addr register: %d\n", - ret); + cs_dsp_err(dsp, + "Failed to read Bus Err Addr register: %d\n", + ret); goto error; } - adsp_err(dsp, "bus error address = 0x%x\n", - val & ADSP2_BUS_ERR_ADDR_MASK); + cs_dsp_err(dsp, "bus error address = 0x%x\n", + val & ADSP2_BUS_ERR_ADDR_MASK); ret = regmap_read(regmap, dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, &val); if (ret) { - adsp_err(dsp, - "Failed to read Pmem Xmem Err Addr register: %d\n", - ret); + cs_dsp_err(dsp, + "Failed to read Pmem Xmem Err Addr register: %d\n", + ret); goto error; } - adsp_err(dsp, "xmem error address = 0x%x\n", - val & ADSP2_XMEM_ERR_ADDR_MASK); - adsp_err(dsp, "pmem error address = 0x%x\n", - (val & ADSP2_PMEM_ERR_ADDR_MASK) >> - ADSP2_PMEM_ERR_ADDR_SHIFT); + cs_dsp_err(dsp, "xmem error address = 0x%x\n", + val & ADSP2_XMEM_ERR_ADDR_MASK); + cs_dsp_err(dsp, "pmem error address = 0x%x\n", + (val & ADSP2_PMEM_ERR_ADDR_MASK) >> + ADSP2_PMEM_ERR_ADDR_SHIFT); } regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, @@ -4424,14 +4629,20 @@ irqreturn_t wm_adsp2_bus_error(int irq, void *data) error: mutex_unlock(&dsp->pwr_lock); +} + +irqreturn_t wm_adsp2_bus_error(int irq, void *data) +{ + struct wm_adsp *dsp = (struct wm_adsp *)data; + + cs_dsp_adsp2_bus_error(&dsp->cs_dsp); return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); -irqreturn_t wm_halo_bus_error(int irq, void *data) +static void cs_dsp_halo_bus_error(struct cs_dsp *dsp) { - struct wm_adsp *dsp = (struct wm_adsp *)data; struct regmap *regmap = dsp->regmap; unsigned int fault[6]; struct reg_sequence clear[] = { @@ -4446,143 +4657,166 @@ irqreturn_t wm_halo_bus_error(int irq, void *data) ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, fault); if (ret) { - adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); + cs_dsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret); goto exit_unlock; } - adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", - *fault & HALO_AHBM_FLAGS_ERR_MASK, - (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> - HALO_AHBM_CORE_ERR_ADDR_SHIFT); + cs_dsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n", + *fault & HALO_AHBM_FLAGS_ERR_MASK, + (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >> + HALO_AHBM_CORE_ERR_ADDR_SHIFT); ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, fault); if (ret) { - adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); + cs_dsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret); goto exit_unlock; } - adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); + cs_dsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault); ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, fault, ARRAY_SIZE(fault)); if (ret) { - adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); + cs_dsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret); goto exit_unlock; } - adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); - adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); - adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); + cs_dsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]); + cs_dsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]); + cs_dsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]); ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear)); if (ret) - adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); + cs_dsp_warn(dsp, "Failed to clear MPU status: %d\n", ret); exit_unlock: mutex_unlock(&dsp->pwr_lock); +} + +irqreturn_t wm_halo_bus_error(int irq, void *data) +{ + struct wm_adsp *dsp = (struct wm_adsp *)data; + + cs_dsp_halo_bus_error(&dsp->cs_dsp); return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(wm_halo_bus_error); -irqreturn_t wm_halo_wdt_expire(int irq, void *data) +static void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) { - struct wm_adsp *dsp = data; - mutex_lock(&dsp->pwr_lock); - adsp_warn(dsp, "WDT Expiry Fault\n"); + cs_dsp_warn(dsp, "WDT Expiry Fault\n"); + dsp->ops->stop_watchdog(dsp); - wm_adsp_fatal_error(dsp); + if (dsp->client_ops->watchdog_expired) + dsp->client_ops->watchdog_expired(dsp); mutex_unlock(&dsp->pwr_lock); +} + +irqreturn_t wm_halo_wdt_expire(int irq, void *data) +{ + struct wm_adsp *dsp = data; + + cs_dsp_halo_wdt_expire(&dsp->cs_dsp); return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(wm_halo_wdt_expire); -static const struct wm_adsp_ops wm_adsp1_ops = { - .validate_version = wm_adsp_validate_version, - .parse_sizes = wm_adsp1_parse_sizes, - .region_to_reg = wm_adsp_region_to_reg, +static const struct cs_dsp_ops cs_dsp_adsp1_ops = { + .validate_version = cs_dsp_validate_version, + .parse_sizes = cs_dsp_adsp1_parse_sizes, + .region_to_reg = cs_dsp_region_to_reg, }; -static const struct wm_adsp_ops wm_adsp2_ops[] = { +static const struct cs_dsp_client_ops wm_adsp1_client_ops = { + .control_add = wm_adsp_control_add, + .control_remove = wm_adsp_control_remove, +}; + +static const struct cs_dsp_ops cs_dsp_adsp2_ops[] = { { - .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), - .parse_sizes = wm_adsp2_parse_sizes, - .validate_version = wm_adsp_validate_version, - .setup_algs = wm_adsp2_setup_algs, - .region_to_reg = wm_adsp_region_to_reg, + .parse_sizes = cs_dsp_adsp2_parse_sizes, + .validate_version = cs_dsp_validate_version, + .setup_algs = cs_dsp_adsp2_setup_algs, + .region_to_reg = cs_dsp_region_to_reg, - .show_fw_status = wm_adsp2_show_fw_status, + .show_fw_status = cs_dsp_adsp2_show_fw_status, - .enable_memory = wm_adsp2_enable_memory, - .disable_memory = wm_adsp2_disable_memory, + .enable_memory = cs_dsp_adsp2_enable_memory, + .disable_memory = cs_dsp_adsp2_disable_memory, - .enable_core = wm_adsp2_enable_core, - .disable_core = wm_adsp2_disable_core, + .enable_core = cs_dsp_adsp2_enable_core, + .disable_core = cs_dsp_adsp2_disable_core, - .start_core = wm_adsp2_start_core, - .stop_core = wm_adsp2_stop_core, + .start_core = cs_dsp_adsp2_start_core, + .stop_core = cs_dsp_adsp2_stop_core, }, { - .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), - .parse_sizes = wm_adsp2_parse_sizes, - .validate_version = wm_adsp_validate_version, - .setup_algs = wm_adsp2_setup_algs, - .region_to_reg = wm_adsp_region_to_reg, + .parse_sizes = cs_dsp_adsp2_parse_sizes, + .validate_version = cs_dsp_validate_version, + .setup_algs = cs_dsp_adsp2_setup_algs, + .region_to_reg = cs_dsp_region_to_reg, - .show_fw_status = wm_adsp2v2_show_fw_status, + .show_fw_status = cs_dsp_adsp2v2_show_fw_status, - .enable_memory = wm_adsp2_enable_memory, - .disable_memory = wm_adsp2_disable_memory, - .lock_memory = wm_adsp2_lock, + .enable_memory = cs_dsp_adsp2_enable_memory, + .disable_memory = cs_dsp_adsp2_disable_memory, + .lock_memory = cs_dsp_adsp2_lock, - .enable_core = wm_adsp2v2_enable_core, - .disable_core = wm_adsp2v2_disable_core, + .enable_core = cs_dsp_adsp2v2_enable_core, + .disable_core = cs_dsp_adsp2v2_disable_core, - .start_core = wm_adsp2_start_core, - .stop_core = wm_adsp2_stop_core, + .start_core = cs_dsp_adsp2_start_core, + .stop_core = cs_dsp_adsp2_stop_core, }, { - .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), - .parse_sizes = wm_adsp2_parse_sizes, - .validate_version = wm_adsp_validate_version, - .setup_algs = wm_adsp2_setup_algs, - .region_to_reg = wm_adsp_region_to_reg, + .parse_sizes = cs_dsp_adsp2_parse_sizes, + .validate_version = cs_dsp_validate_version, + .setup_algs = cs_dsp_adsp2_setup_algs, + .region_to_reg = cs_dsp_region_to_reg, - .show_fw_status = wm_adsp2v2_show_fw_status, - .stop_watchdog = wm_adsp_stop_watchdog, + .show_fw_status = cs_dsp_adsp2v2_show_fw_status, + .stop_watchdog = cs_dsp_stop_watchdog, - .enable_memory = wm_adsp2_enable_memory, - .disable_memory = wm_adsp2_disable_memory, - .lock_memory = wm_adsp2_lock, + .enable_memory = cs_dsp_adsp2_enable_memory, + .disable_memory = cs_dsp_adsp2_disable_memory, + .lock_memory = cs_dsp_adsp2_lock, - .enable_core = wm_adsp2v2_enable_core, - .disable_core = wm_adsp2v2_disable_core, + .enable_core = cs_dsp_adsp2v2_enable_core, + .disable_core = cs_dsp_adsp2v2_disable_core, - .start_core = wm_adsp2_start_core, - .stop_core = wm_adsp2_stop_core, + .start_core = cs_dsp_adsp2_start_core, + .stop_core = cs_dsp_adsp2_stop_core, }, }; -static const struct wm_adsp_ops wm_halo_ops = { - .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr), - .parse_sizes = wm_adsp2_parse_sizes, - .validate_version = wm_halo_validate_version, - .setup_algs = wm_halo_setup_algs, - .region_to_reg = wm_halo_region_to_reg, +static const struct cs_dsp_ops cs_dsp_halo_ops = { + .parse_sizes = cs_dsp_adsp2_parse_sizes, + .validate_version = cs_dsp_halo_validate_version, + .setup_algs = cs_dsp_halo_setup_algs, + .region_to_reg = cs_dsp_halo_region_to_reg, - .show_fw_status = wm_halo_show_fw_status, - .stop_watchdog = wm_halo_stop_watchdog, + .show_fw_status = cs_dsp_halo_show_fw_status, + .stop_watchdog = cs_dsp_halo_stop_watchdog, - .lock_memory = wm_halo_configure_mpu, + .lock_memory = cs_dsp_halo_configure_mpu, + + .start_core = cs_dsp_halo_start_core, + .stop_core = cs_dsp_halo_stop_core, +}; - .start_core = wm_halo_start_core, - .stop_core = wm_halo_stop_core, +static const struct cs_dsp_client_ops wm_adsp2_client_ops = { + .control_add = wm_adsp_control_add, + .control_remove = wm_adsp_control_remove, + .post_run = wm_adsp_event_post_run, + .post_stop = wm_adsp_event_post_stop, + .watchdog_expired = wm_adsp_fatal_error, }; MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index f22131d9cc298b..25aaef74654c22 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -20,29 +20,29 @@ #define WM_ADSP_COMPR_OK 0 #define WM_ADSP_COMPR_VOICE_TRIGGER 1 -#define WM_ADSP2_REGION_0 BIT(0) -#define WM_ADSP2_REGION_1 BIT(1) -#define WM_ADSP2_REGION_2 BIT(2) -#define WM_ADSP2_REGION_3 BIT(3) -#define WM_ADSP2_REGION_4 BIT(4) -#define WM_ADSP2_REGION_5 BIT(5) -#define WM_ADSP2_REGION_6 BIT(6) -#define WM_ADSP2_REGION_7 BIT(7) -#define WM_ADSP2_REGION_8 BIT(8) -#define WM_ADSP2_REGION_9 BIT(9) -#define WM_ADSP2_REGION_1_9 (WM_ADSP2_REGION_1 | \ - WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3 | \ - WM_ADSP2_REGION_4 | WM_ADSP2_REGION_5 | \ - WM_ADSP2_REGION_6 | WM_ADSP2_REGION_7 | \ - WM_ADSP2_REGION_8 | WM_ADSP2_REGION_9) -#define WM_ADSP2_REGION_ALL (WM_ADSP2_REGION_0 | WM_ADSP2_REGION_1_9) - -struct wm_adsp_region { +#define CS_ADSP2_REGION_0 BIT(0) +#define CS_ADSP2_REGION_1 BIT(1) +#define CS_ADSP2_REGION_2 BIT(2) +#define CS_ADSP2_REGION_3 BIT(3) +#define CS_ADSP2_REGION_4 BIT(4) +#define CS_ADSP2_REGION_5 BIT(5) +#define CS_ADSP2_REGION_6 BIT(6) +#define CS_ADSP2_REGION_7 BIT(7) +#define CS_ADSP2_REGION_8 BIT(8) +#define CS_ADSP2_REGION_9 BIT(9) +#define CS_ADSP2_REGION_1_9 (CS_ADSP2_REGION_1 | \ + CS_ADSP2_REGION_2 | CS_ADSP2_REGION_3 | \ + CS_ADSP2_REGION_4 | CS_ADSP2_REGION_5 | \ + CS_ADSP2_REGION_6 | CS_ADSP2_REGION_7 | \ + CS_ADSP2_REGION_8 | CS_ADSP2_REGION_9) +#define CS_ADSP2_REGION_ALL (CS_ADSP2_REGION_0 | CS_ADSP2_REGION_1_9) + +struct cs_dsp_region { int type; unsigned int base; }; -struct wm_adsp_alg_region { +struct cs_dsp_alg_region { struct list_head list; unsigned int alg; int type; @@ -51,20 +51,38 @@ struct wm_adsp_alg_region { struct wm_adsp_compr; struct wm_adsp_compr_buf; -struct wm_adsp_ops; +struct cs_dsp_ops; +struct cs_dsp_client_ops; + +struct cs_dsp_coeff_ctl { + const char *fw_name; + /* Subname is needed to match with firmware */ + const char *subname; + unsigned int subname_len; + struct cs_dsp_alg_region alg_region; + struct cs_dsp *dsp; + unsigned int enabled:1; + struct list_head list; + void *cache; + unsigned int offset; + size_t len; + unsigned int set:1; + unsigned int flags; + unsigned int type; + + void *priv; +}; -struct wm_adsp { - const char *part; +struct cs_dsp { const char *name; - const char *fwf_name; int rev; int num; int type; struct device *dev; struct regmap *regmap; - struct snd_soc_component *component; - const struct wm_adsp_ops *ops; + const struct cs_dsp_ops *ops; + const struct cs_dsp_client_ops *client_ops; unsigned int base; unsigned int base_sysinfo; @@ -74,28 +92,21 @@ struct wm_adsp { struct list_head alg_regions; + const char *fw_name; unsigned int fw_id; unsigned int fw_id_version; unsigned int fw_vendor_id; - const struct wm_adsp_region *mem; + const struct cs_dsp_region *mem; int num_mems; - int fw; int fw_ver; - bool preloaded; bool booted; bool running; - bool fatal_error; struct list_head ctl_list; - struct work_struct boot_work; - - struct list_head compr_list; - struct list_head buffer_list; - struct mutex pwr_lock; unsigned int lock_regions; @@ -105,33 +116,49 @@ struct wm_adsp { char *wmfw_file_name; char *bin_file_name; #endif - }; -struct wm_adsp_ops { +struct wm_adsp { + struct cs_dsp cs_dsp; + const char *part; + const char *fwf_name; + struct snd_soc_component *component; + unsigned int sys_config_size; - bool (*validate_version)(struct wm_adsp *dsp, unsigned int version); - unsigned int (*parse_sizes)(struct wm_adsp *dsp, + int fw; + + struct work_struct boot_work; + + bool preloaded; + bool fatal_error; + + struct list_head compr_list; + struct list_head buffer_list; +}; + +struct cs_dsp_ops { + bool (*validate_version)(struct cs_dsp *dsp, unsigned int version); + unsigned int (*parse_sizes)(struct cs_dsp *dsp, const char * const file, unsigned int pos, const struct firmware *firmware); - int (*setup_algs)(struct wm_adsp *dsp); - unsigned int (*region_to_reg)(struct wm_adsp_region const *mem, + int (*setup_algs)(struct cs_dsp *dsp); + unsigned int (*region_to_reg)(struct cs_dsp_region const *mem, unsigned int offset); - void (*show_fw_status)(struct wm_adsp *dsp); - void (*stop_watchdog)(struct wm_adsp *dsp); + void (*show_fw_status)(struct cs_dsp *dsp); + void (*stop_watchdog)(struct cs_dsp *dsp); - int (*enable_memory)(struct wm_adsp *dsp); - void (*disable_memory)(struct wm_adsp *dsp); - int (*lock_memory)(struct wm_adsp *dsp, unsigned int lock_regions); + int (*enable_memory)(struct cs_dsp *dsp); + void (*disable_memory)(struct cs_dsp *dsp); + int (*lock_memory)(struct cs_dsp *dsp, unsigned int lock_regions); - int (*enable_core)(struct wm_adsp *dsp); - void (*disable_core)(struct wm_adsp *dsp); + int (*enable_core)(struct cs_dsp *dsp); + void (*disable_core)(struct cs_dsp *dsp); - int (*start_core)(struct wm_adsp *dsp); - void (*stop_core)(struct wm_adsp *dsp); + int (*start_core)(struct cs_dsp *dsp); + void (*stop_core)(struct cs_dsp *dsp); }; #define WM_ADSP1(wname, num) \ @@ -212,4 +239,12 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len); +struct cs_dsp_client_ops { + int (*control_add)(struct cs_dsp_coeff_ctl *ctl); + void (*control_remove)(struct cs_dsp_coeff_ctl *ctl); + int (*post_run)(struct cs_dsp *dsp); + void (*post_stop)(struct cs_dsp *dsp); + void (*watchdog_expired)(struct cs_dsp *dsp); +}; + #endif diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index f3d51602f85c76..a19bf7c6fc8b06 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h @@ -23,10 +23,12 @@ #define WMFW_CTL_FLAG_WRITEABLE 0x0002 #define WMFW_CTL_FLAG_READABLE 0x0001 +#define WMFW_CTL_TYPE_BYTES 0x0004 /* byte control */ + /* Non-ALSA coefficient types start at 0x1000 */ -#define WMFW_CTL_TYPE_ACKED ((__force snd_ctl_elem_type_t)0x1000) /* acked control */ -#define WMFW_CTL_TYPE_HOSTEVENT ((__force snd_ctl_elem_type_t)0x1001) /* event control */ -#define WMFW_CTL_TYPE_HOST_BUFFER ((__force snd_ctl_elem_type_t)0x1002) /* host buffer pointer */ +#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */ +#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ +#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */ struct wmfw_header { char magic[4]; diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c index d21a72314d3770..d20ec157101064 100644 --- a/sound/soc/codecs/zl38060.c +++ b/sound/soc/codecs/zl38060.c @@ -250,8 +250,8 @@ static int zl38_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: /* always 32 bits per frame (= 16 bits/channel, 2 channels) */ err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK, CFG_CLK_MASTER | CFG_CLK_PCLK_MASK, diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 33ce257ae1986e..5cb58929090d45 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -356,25 +356,25 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); int ret = 0; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: if (dev->capability & DW_I2S_SLAVE) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: if (dev->capability & DW_I2S_MASTER) ret = 0; else ret = -EINVAL; break; - case SND_SOC_DAIFMT_CBM_CFS: - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_CBC_CFP: ret = -EINVAL; break; default: - dev_dbg(dev->dev, "dwc : Invalid master/slave format\n"); + dev_dbg(dev->dev, "dwc : Invalid clock provider format\n"); ret = -EINVAL; break; } diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index e13271ea84ded1..8b61582753c868 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -70,7 +70,7 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &eukrea_tlv320_snd_ops, SND_SOC_DAILINK_REG(hifi), }; diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 06107ae46e20b3..6e6494f9f399eb 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -356,8 +356,8 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, * If only 4 wires are needed, just set SSI into * synchronous mode and enable 4 PADs in IOMUX. */ - switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | @@ -367,7 +367,7 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TCLKDIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | IMX_AUDMUX_V2_PTCR_RCLKDIR | @@ -377,7 +377,7 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, IMX_AUDMUX_V2_PTCR_RFSDIR | IMX_AUDMUX_V2_PTCR_TFSDIR; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | IMX_AUDMUX_V2_PTCR_RFSDIR | @@ -387,7 +387,7 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, IMX_AUDMUX_V2_PTCR_RCLKDIR | IMX_AUDMUX_V2_PTCR_TCLKDIR; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | @@ -533,8 +533,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct device_node *cpu_np, *codec_np, *asrc_np; struct device_node *np = pdev->dev.of_node; struct platform_device *asrc_pdev = NULL; - struct device_node *bitclkmaster = NULL; - struct device_node *framemaster = NULL; + struct device_node *bitclkprovider = NULL; + struct device_node *frameprovider = NULL; struct platform_device *cpu_pdev; struct fsl_asoc_card_priv *priv; struct device *codec_dev = NULL; @@ -617,29 +617,29 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.slot_width = 32; - priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; } else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) { codec_dai_name = "cs4271-hifi"; priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { codec_dai_name = "sgtl5000"; priv->codec_priv.mclk_id = SGTL5000_SYSCLK; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) { codec_dai_name = "tlv320aic32x4-hifi"; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { codec_dai_name = "wm8962"; priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; priv->codec_priv.pll_id = WM8962_FLL; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) { codec_dai_name = "wm8960-hifi"; priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO; priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) { codec_dai_name = "ac97-hifi"; priv->dai_fmt = SND_SOC_DAIFMT_AC97; @@ -648,7 +648,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) { codec_dai_name = "fsl-mqs-dai"; priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J | - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_NB_NF; priv->dai_link[1].dpcm_capture = 0; priv->dai_link[2].dpcm_capture = 0; @@ -656,7 +656,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) { codec_dai_name = "wm8524-hifi"; - priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; priv->dai_link[1].dpcm_capture = 0; priv->dai_link[2].dpcm_capture = 0; priv->cpu_priv.slot_width = 32; @@ -664,12 +664,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) { codec_dai_name = "si476x-codec"; - priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; priv->card.dapm_routes = audio_map_rx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) { codec_dai_name = "wm8994-aif1"; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1; priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1; priv->codec_priv.pll_id = WM8994_FLL1; @@ -683,29 +683,29 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* Format info from DT is optional. */ - snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkmaster, &framemaster); - if (bitclkmaster || framemaster) { + snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider); + if (bitclkprovider || frameprovider) { unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL); - if (codec_np == bitclkmaster) - daifmt |= (codec_np == framemaster) ? - SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; + if (codec_np == bitclkprovider) + daifmt |= (codec_np == frameprovider) ? + SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC; else - daifmt |= (codec_np == framemaster) ? - SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; + daifmt |= (codec_np == frameprovider) ? + SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC; /* Override dai_fmt with value from DT */ priv->dai_fmt = daifmt; } /* Change direction according to format */ - if (priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) { + if (priv->dai_fmt & SND_SOC_DAIFMT_CBP_CFP) { priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_IN; priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_IN; } - of_node_put(bitclkmaster); - of_node_put(framemaster); + of_node_put(bitclkprovider); + of_node_put(frameprovider); if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) { dev_dbg(&pdev->dev, "failed to find codec device\n"); diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index f931288e256ca4..6dbb8c99f62688 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -257,10 +257,10 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - /* For playback the AUDMIX is slave, and for record is master */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - case SND_SOC_DAIFMT_CBS_CFS: + /* For playback the AUDMIX is consumer, and for record is provider */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index bda66b30e063c2..3a9e2df4e16f61 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -52,7 +52,7 @@ struct fsl_esai_soc_data { * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads * @sck_div: if using PSR/PM dividers for SCKx clock - * @slave_mode: if fully using DAI slave mode + * @consumer_mode: if fully using DAI clock consumer mode * @synchronous: if using tx/rx synchronous mode * @name: driver name */ @@ -78,7 +78,7 @@ struct fsl_esai { u32 sck_rate[2]; bool hck_dir[2]; bool sck_div[2]; - bool slave_mode; + bool consumer_mode; bool synchronous; char name[32]; }; @@ -366,8 +366,8 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) u32 sub, ratio = hck_rate / freq; int ret; - /* Don't apply for fully slave mode or unchanged bclk */ - if (esai_priv->slave_mode || esai_priv->sck_rate[tx] == freq) + /* Don't apply for fully consumer mode or unchanged bclk */ + if (esai_priv->consumer_mode || esai_priv->sck_rate[tx] == freq) return 0; if (ratio * freq > hck_rate) @@ -476,20 +476,20 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - esai_priv->slave_mode = false; + esai_priv->consumer_mode = false; - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - esai_priv->slave_mode = true; + /* DAI clock provider masks */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + esai_priv->consumer_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: xccr |= ESAI_xCCR_xCKD; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: xccr |= ESAI_xCCR_xFSD; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; break; default: @@ -1016,8 +1016,8 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot number */ esai_priv->slots = 2; - /* Set a default master/slave state */ - esai_priv->slave_mode = true; + /* Set a default clock provider state */ + esai_priv->consumer_mode = true; /* Determine the FIFO depth */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 69aeb0e71844d9..27b4536dce443b 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -102,8 +102,8 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index d60f4dac6c1b34..07abad7fe37269 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -138,11 +138,42 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-rpmsg", }; +static const struct fsl_rpmsg_soc_data imx7ulp_data = { + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mm_data = { + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U8 | + SNDRV_PCM_FMTBIT_DSD_U16_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mn_data = { + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + +static const struct fsl_rpmsg_soc_data imx8mp_data = { + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + static const struct of_device_id fsl_rpmsg_ids[] = { - { .compatible = "fsl,imx7ulp-rpmsg-audio"}, - { .compatible = "fsl,imx8mm-rpmsg-audio"}, - { .compatible = "fsl,imx8mn-rpmsg-audio"}, - { .compatible = "fsl,imx8mp-rpmsg-audio"}, + { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data}, + { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data}, + { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data}, + { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); @@ -157,6 +188,13 @@ static int fsl_rpmsg_probe(struct platform_device *pdev) if (!rpmsg) return -ENOMEM; + rpmsg->soc_data = of_device_get_match_data(&pdev->dev); + + fsl_rpmsg_dai.playback.rates = rpmsg->soc_data->rates; + fsl_rpmsg_dai.capture.rates = rpmsg->soc_data->rates; + fsl_rpmsg_dai.playback.formats = rpmsg->soc_data->formats; + fsl_rpmsg_dai.capture.formats = rpmsg->soc_data->formats; + if (of_property_read_bool(np, "fsl,enable-lpa")) { rpmsg->enable_lpa = 1; rpmsg->buffer_size = LPA_LARGE_BUFFER_SIZE; diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h index 4f5b49eb18d8dd..b04086fbf82838 100644 --- a/sound/soc/fsl/fsl_rpmsg.h +++ b/sound/soc/fsl/fsl_rpmsg.h @@ -7,6 +7,16 @@ #define __FSL_RPMSG_H /* + * struct fsl_rpmsg_soc_data + * @rates: supported rates + * @formats: supported formats + */ +struct fsl_rpmsg_soc_data { + int rates; + u64 formats; +}; + +/* * struct fsl_rpmsg - rpmsg private data * * @ipg: ipg clock for cpu dai (SAI) @@ -15,6 +25,7 @@ * @pll8k: parent clock for multiple of 8kHz frequency * @pll11k: parent clock for multiple of 11kHz frequency * @card_pdev: Platform_device pointer to register a sound card + * @soc_data: soc specific data * @mclk_streams: Active streams that are using baudclk * @force_lpa: force enable low power audio routine if condition satisfy * @enable_lpa: enable low power audio routine according to dts setting @@ -27,6 +38,7 @@ struct fsl_rpmsg { struct clk *pll8k; struct clk *pll11k; struct platform_device *card_pdev; + const struct fsl_rpmsg_soc_data *soc_data; unsigned int mclk_streams; int force_lpa; int enable_lpa; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 38f6362099d587..10544fa27dc0b3 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -297,23 +297,23 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + /* DAI clock provider masks */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_slave_mode = false; + sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBM_CFM: - sai->is_slave_mode = true; + case SND_SOC_DAIFMT_CBP_CFP: + sai->is_consumer_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; - sai->is_slave_mode = false; + sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_slave_mode = true; + sai->is_consumer_mode = true; break; default: return -EINVAL; @@ -356,8 +356,8 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) u32 id; int ret = 0; - /* Don't apply to slave mode */ - if (sai->is_slave_mode) + /* Don't apply to consumer mode */ + if (sai->is_consumer_mode) return 0; /* @@ -462,7 +462,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, pins = DIV_ROUND_UP(channels, slots); - if (!sai->is_slave_mode) { + if (!sai->is_consumer_mode) { if (sai->bclk_ratio) ret = fsl_sai_set_bclk(cpu_dai, tx, sai->bclk_ratio * @@ -502,12 +502,12 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr4 |= FSL_SAI_CR4_CHMOD; /* - * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will + * For SAI provider mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), * RCR5(TCR5) for playback(capture), or there will be sync error. */ - if (!sai->is_slave_mode && fsl_sai_dir_is_synced(sai, adir)) { + if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) { regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, @@ -543,7 +543,7 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, 0); - if (!sai->is_slave_mode && + if (!sai->is_consumer_mode && sai->mclk_streams & BIT(substream->stream)) { clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); sai->mclk_streams &= ~BIT(substream->stream); @@ -577,7 +577,7 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) * This is a hardware bug, and will be fix in the * next sai version. */ - if (!sai->is_slave_mode) { + if (!sai->is_consumer_mode) { /* Software Reset */ regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index bc60030967dd86..9aaf231bc02443 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -259,7 +259,7 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool is_slave_mode; + bool is_consumer_mode; bool is_lsb_first; bool is_dsp_mode; bool synchronous[2]; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 1c53719bb61e23..928b59069283d4 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -186,6 +186,16 @@ static struct fsl_spdif_soc_data fsl_spdif_imx8mm = { .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, }; +static struct fsl_spdif_soc_data fsl_spdif_imx8ulp = { + .imx = true, + .shared_root_clock = true, + .raw_capture_mode = false, + .interrupts = 1, + .tx_burst = 2, /* Applied for EDMA */ + .rx_burst = 2, /* Applied for EDMA */ + .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */ +}; + /* Check if clk is a root clock that does not share clock source with others */ static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk) { @@ -1560,6 +1570,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = { { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, }, { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, }, + { .compatible = "fsl,imx8ulp-spdif", .data = &fsl_spdif_imx8ulp, }, {} }; MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ecbc1c365d5b17..1169d1104b9e86 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -350,16 +350,16 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) SND_SOC_DAIFMT_AC97; } -static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi) +static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi) { - return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBS_CFS; + return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_CBC_CFC; } -static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) +static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi) { - return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBM_CFS; + return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == + SND_SOC_DAIFMT_CBP_CFC; } /** @@ -808,7 +808,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u32 wl = SSI_SxCCR_WL(sample_size); int ret; - if (fsl_ssi_is_i2s_master(ssi)) { + if (fsl_ssi_is_i2s_clock_provider(ssi)) { ret = fsl_ssi_set_bclk(substream, dai, hw_params); if (ret) return ret; @@ -841,7 +841,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2s_net = ssi->i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ - if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) + if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16) i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; /* Use Normal mode to send mono data at 1st slot of 2 slots */ @@ -865,7 +865,7 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); - if (fsl_ssi_is_i2s_master(ssi) && + if (fsl_ssi_is_i2s_clock_provider(ssi) && ssi->baudclk_streams & BIT(substream->stream)) { clk_disable_unprepare(ssi->baudclk); ssi->baudclk_streams &= ~BIT(substream->stream); @@ -891,18 +891,18 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) ssi->i2s_net = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: if (IS_ERR(ssi->baudclk)) { dev_err(ssi->dev, "missing baudclk for master mode\n"); return -EINVAL; } fallthrough; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: @@ -962,17 +962,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) return -EINVAL; } - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + /* DAI clock provider masks */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: /* Output bit and frame sync clocks */ strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; scr |= SSI_SCR_SYS_CLK_EN; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: /* Input bit or frame sync clocks */ break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: /* Input bit clock but output frame sync clock */ strcr |= SSI_STCR_TFDIR; break; @@ -1341,7 +1341,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, } } - /* Do not error out for slave cases that live without a baud clock */ + /* Do not error out for consumer cases that live without a baud clock */ ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) dev_dbg(dev, "failed to get baud clock: %ld\n", diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index a364e2415de029..502fe1b522aba7 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -80,8 +80,8 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream, u32 channels = params_channels(params); int ret, dir; - /* For playback the AUDMIX is slave, and for record is master */ - fmt |= tx ? SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; + /* For playback the AUDMIX is consumer, and for record is provider */ + fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP; dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN; /* set DAI configuration */ @@ -121,8 +121,8 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream, if (!tx) return 0; - /* For playback the AUDMIX is slave */ - fmt |= SND_SOC_DAIFMT_CBM_CFM; + /* For playback the AUDMIX is consumer */ + fmt |= SND_SOC_DAIFMT_CBP_CFP; /* set AUDMIX DAI configuration */ ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); @@ -132,12 +132,12 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops imx_audmix_fe_ops = { +static const struct snd_soc_ops imx_audmix_fe_ops = { .startup = imx_audmix_fe_startup, .hw_params = imx_audmix_fe_hw_params, }; -static struct snd_soc_ops imx_audmix_be_ops = { +static const struct snd_soc_ops imx_audmix_be_ops = { .hw_params = imx_audmix_be_hw_params, }; diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 58fd0639a06984..6f06afd23b16ae 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -442,12 +442,12 @@ static int imx_aif_startup(struct snd_pcm_substream *substream) return ret; } -static struct snd_soc_ops imx_aif_ops = { +static const struct snd_soc_ops imx_aif_ops = { .hw_params = imx_aif_hw_params, .startup = imx_aif_startup, }; -static struct snd_soc_ops imx_aif_ops_be = { +static const struct snd_soc_ops imx_aif_ops_be = { .hw_params = imx_aif_hw_params, }; @@ -652,7 +652,7 @@ static int imx_card_parse_of(struct imx_card_data *data) NULL, &link->dai_fmt); if (ret) link->dai_fmt = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S; /* Get tdm slot */ diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 1981dcd7e93055..09c674ee79f1a5 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -174,7 +174,7 @@ static int imx_es8328_probe(struct platform_device *pdev) data->dai.platforms->of_node = ssi_np; data->dai.init = &imx_es8328_dai_init; data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; data->card.dev = dev; data->card.dapm_widgets = imx_es8328_dapm_widgets; diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index 34a0dceae62167..f10359a288005b 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -59,7 +59,7 @@ static int imx_hdmi_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops imx_hdmi_ops = { +static const struct snd_soc_ops imx_hdmi_ops = { .hw_params = imx_hdmi_hw_params, }; @@ -171,7 +171,7 @@ static int imx_hdmi_probe(struct platform_device *pdev) data->dai.codecs->name = "hdmi-audio-codec.1"; data->dai.dai_fmt = data->dai_fmt | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_CBC_CFC; } if (hdmi_in) { @@ -181,7 +181,7 @@ static int imx_hdmi_probe(struct platform_device *pdev) data->dai.codecs->name = "hdmi-audio-codec.2"; data->dai.dai_fmt = data->dai_fmt | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; } data->card.dapm_widgets = imx_hdmi_widgets; diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index f96fe4ff8425b3..2e117311e582fa 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -64,7 +64,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev) data->dai.stream_name = "rpmsg hifi"; data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_CBC_CFC; /* Optional codec node */ ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args); diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index f45cb4bbb6c4d1..2f1acd0110426a 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -153,7 +153,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->dai.platforms->of_node = ssi_np; data->dai.init = &imx_sgtl5000_dai_init; data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; data->card.dev = &pdev->dev; ret = snd_soc_of_parse_card_name(&data->card, "model"); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 58b9ca3c4da0e8..e71a992fbf93c4 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -264,7 +264,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) if (strcasecmp(sprop, "i2s-slave") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP; machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; @@ -282,37 +282,37 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) machine_data->clk_frequency = be32_to_cpup(iprop); } else if (strcasecmp(sprop, "i2s-master") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "lj-slave") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP; machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "lj-master") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "rj-slave") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBP_CFP; machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "rj-master") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBC_CFC; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "ac97-slave") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBP_CFP; machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "ac97-master") == 0) { machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBC_CFC; machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else { diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 317c767b0099e3..b45742931b0d11 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -275,7 +275,7 @@ static int p1022_ds_probe(struct platform_device *pdev) if (strcasecmp(sprop, "i2s-slave") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; @@ -293,37 +293,37 @@ static int p1022_ds_probe(struct platform_device *pdev) mdata->clk_frequency = be32_to_cpup(iprop); } else if (strcasecmp(sprop, "i2s-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "lj-slave") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "lj-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "rj-slave") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBP_CFP; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "rj-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBC_CFC; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else if (strcasecmp(sprop, "ac97-slave") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBP_CFP; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; } else if (strcasecmp(sprop, "ac97-master") == 0) { mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBC_CFC; mdata->codec_clk_direction = SND_SOC_CLOCK_IN; mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT; } else { diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index 714515b8081feb..b395adabe8235c 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -265,7 +265,7 @@ static int p1022_rdk_probe(struct platform_device *pdev) * only one way to configure the SSI. */ mdata->dai_format = SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP; mdata->codec_clk_direction = SND_SOC_CLOCK_OUT; mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 546f6fd0609e13..7eb02723832783 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -310,8 +310,10 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where * there are 'n' BE components in the path. */ - if (card->component_chaining && !soc_component_is_pcm(cpus)) + if (card->component_chaining && !soc_component_is_pcm(cpus)) { dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; + } asoc_simple_canonicalize_cpu(cpus, is_single_links); asoc_simple_canonicalize_platform(platforms, cpus); diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 61b71d6c44cfa2..3e20c697b569a2 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -470,6 +470,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_RT1015 select SND_SOC_RT1015P select SND_SOC_RT5682_I2C + select SND_SOC_RT5682S select SND_SOC_DMIC select SND_SOC_HDAC_HDMI select SND_SOC_INTEL_HDA_DSP_COMMON diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index c5122d3b0e6c4e..6cba5552f7a210 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -251,7 +251,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5650_ops, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index e01b7a90ca6c78..119c441f4c1045 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -351,7 +351,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5677_ops, diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 3c3aff9c61cc66..618d0645ed8d06 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -217,7 +217,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .no_pcm = 1, .init = broadwell_rt286_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &broadwell_rt286_ops, diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index e67ddfb8e46907..b768d9b8ec027e 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -572,7 +572,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broxton_ssp_fixup, .dpcm_playback = 1, @@ -585,7 +585,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .no_pcm = 1, .init = broxton_da7219_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broxton_ssp_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 47f6b1523ae6ba..920e575b4314af 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -468,7 +468,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { .no_pcm = 1, .init = broxton_rt298_codec_init, .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = broxton_ssp5_fixup, .ops = &broxton_rt298_ops, diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index a9e51bbf018c35..0a736308052a95 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; @@ -195,7 +195,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index a28773fb7892b5..fae1e7e785b043 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; @@ -195,7 +195,7 @@ static struct snd_soc_dai_link dailink[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 055248f104b245..1bb9b8e7bcc7c3 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_CBC_CFC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -336,7 +336,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 9b48fe701a2cd6..67b3c4e9786402 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -141,7 +141,7 @@ static struct snd_soc_dai_link dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a6e837290c7dc1..c28abe74816fd4 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1336,7 +1336,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; @@ -1411,7 +1411,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5640_codec_fixup, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e94c9124d4f411..00c347b528639a 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -713,7 +713,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_CBC_CFC ); if (ret < 0) { @@ -798,7 +798,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5651_codec_fixup, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 580d5fddae5ada..504ef4cab111f3 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret) { dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret); return ret; @@ -349,7 +349,7 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_wm5102_codec_fixup, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 131882378a5947..1bc21434c9de8f 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -264,7 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, } fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS; + | SND_SOC_DAIFMT_CBC_CFC; ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); if (ret < 0) { @@ -372,7 +372,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index da5a5cbc875908..da534a0b21336a 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -214,7 +214,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 804dbc7911d504..e182012d0c607a 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_CBC_CFC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS + SND_SOC_DAIFMT_CBC_CFC ); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); @@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to TDM %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9509b6e161b891..26eb8ad0d2624a 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_CBC_CFC); if (ret < 0) { dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); return ret; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 71fe26a1b7011e..9d75beec09d176 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -473,7 +473,7 @@ static struct snd_soc_dai_link geminilake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = geminilake_ssp_fixup, .dpcm_playback = 1, @@ -486,7 +486,7 @@ static struct snd_soc_dai_link geminilake_dais[] = { .no_pcm = 1, .init = geminilake_rt5682_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = geminilake_ssp_fixup, .ops = &geminilake_rt5682_ops, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index c763bfeb1f38fb..36e136acbef582 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -145,7 +145,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = haswell_ssp0_fixup, .ops = &haswell_rt5640_ops, diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 14b625e947f5f3..a4bdf634e9b9e1 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -518,7 +518,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .dpcm_playback = 1, @@ -531,7 +531,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .init = kabylake_da7219_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 2b43459adc33ae..620a9fbcb08faf 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -764,7 +764,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .dpcm_playback = 1, .dpcm_capture = 1, .ignore_pmdown_time = 1, @@ -779,7 +779,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .init = kabylake_da7219_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .dpcm_playback = 1, @@ -907,7 +907,7 @@ static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .dpcm_playback = 1, .dpcm_capture = 1, .ignore_pmdown_time = 1, diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index 289ca39b8206e1..1cb56ec363e8f2 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -436,7 +436,7 @@ static struct snd_soc_dai_link kabylake_rt5660_dais[] = { .exit = kabylake_rt5660_codec_exit, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp0_fixup, .ops = &kabylake_rt5660_ops, diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index a3e040a249f6ff..f24e0ce5d49feb 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -767,7 +767,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .dpcm_playback = 1, @@ -781,7 +781,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .init = kabylake_rt5663_max98927_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .ops = &kabylake_rt5663_ops, @@ -879,7 +879,7 @@ static struct snd_soc_dai_link kabylake_5663_dais[] = { .no_pcm = 1, .init = kabylake_rt5663_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .ops = &kabylake_rt5663_ops, diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index dd38fdaf2ff589..6874e981c8dfdc 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -639,7 +639,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .dpcm_playback = 1, @@ -653,7 +653,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .no_pcm = 1, .init = kabylake_rt5663_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = kabylake_ssp_fixup, .ops = &kabylake_rt5663_ops, diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index e3a1f04a8b5356..7297eb05613ca1 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -539,7 +539,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .dpcm_playback = 1, @@ -552,7 +552,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, .init = skylake_nau8825_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .ops = &skylake_nau8825_ops, diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index adf5992a9ec50b..68efde1633b3cd 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -578,7 +578,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .init = skylake_ssm4567_codec_init, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, @@ -593,7 +593,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, .init = skylake_nau8825_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .ops = &skylake_nau8825_ops, diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 75dab5405380fb..eca4a78668af61 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -434,7 +434,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .init = skylake_rt286_codec_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp0_fixup, .ops = &skylake_rt286_ops, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f096bd6d69be77..ad42d4c7ade5f6 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -18,9 +18,11 @@ #include <sound/soc.h> #include <sound/sof.h> #include <sound/rt5682.h> +#include <sound/rt5682s.h> #include <sound/soc-acpi.h> #include "../../codecs/rt1015.h" #include "../../codecs/rt5682.h" +#include "../../codecs/rt5682s.h" #include "../../codecs/hdac_hdmi.h" #include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" @@ -56,6 +58,7 @@ #define SOF_BT_OFFLOAD_SSP(quirk) \ (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) +#define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -208,9 +211,16 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) /* need to enable ASRC function for 24MHz mclk rate */ if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { - rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | - RT5682_AD_STEREO1_FILTER, - RT5682_CLK_SEL_I2S1_ASRC); + if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) + rt5682s_sel_asrc_clk_src(component, + RT5682S_DA_STEREO1_FILTER | + RT5682S_AD_STEREO1_FILTER, + RT5682S_CLK_SEL_I2S1_ASRC); + else + rt5682_sel_asrc_clk_src(component, + RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, + RT5682_CLK_SEL_I2S1_ASRC); } if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { @@ -277,7 +287,7 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out, ret; + int pll_id, pll_source, pll_in, pll_out, clk_id, ret; if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { @@ -289,35 +299,52 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, } } - clk_id = RT5682_PLL1_S_MCLK; + if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) + pll_source = RT5682S_PLL_S_MCLK; + else + pll_source = RT5682_PLL1_S_MCLK; /* get the tplg configured mclk. */ - clk_freq = sof_dai_get_mclk(rtd); + pll_in = sof_dai_get_mclk(rtd); /* mclk from the quirk is the first choice */ if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) { - if (clk_freq != 24000000) + if (pll_in != 24000000) dev_warn(rtd->dev, "configure wrong mclk in tplg, please use 24MHz.\n"); - clk_freq = 24000000; - } else if (clk_freq == 0) { + pll_in = 24000000; + } else if (pll_in == 0) { /* use default mclk if not specified correct in topology */ - clk_freq = 19200000; - } else if (clk_freq < 0) { - return clk_freq; + pll_in = 19200000; + } else if (pll_in < 0) { + return pll_in; } } else { - clk_id = RT5682_PLL1_S_BCLK1; - clk_freq = params_rate(params) * 50; + if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) + pll_source = RT5682S_PLL_S_BCLK1; + else + pll_source = RT5682_PLL1_S_BCLK1; + + pll_in = params_rate(params) * 50; + } + + if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { + pll_id = RT5682S_PLL2; + clk_id = RT5682S_SCLK_S_PLL2; + } else { + pll_id = RT5682_PLL1; + clk_id = RT5682_SCLK_S_PLL1; } pll_out = params_rate(params) * 512; - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + /* Configure pll for codec */ + ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in, + pll_out); if (ret < 0) dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); @@ -560,6 +587,13 @@ static struct snd_soc_dai_link_component rt5682_component[] = { } }; +static struct snd_soc_dai_link_component rt5682s_component[] = { + { + .name = "i2c-RTL5682:00", + .dai_name = "rt5682s-aif1", + } +}; + static struct snd_soc_dai_link_component dmic_component[] = { { .name = "dmic-codec", @@ -610,8 +644,13 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, goto devm_err; links[id].id = id; - links[id].codecs = rt5682_component; - links[id].num_codecs = ARRAY_SIZE(rt5682_component); + if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { + links[id].codecs = rt5682s_component; + links[id].num_codecs = ARRAY_SIZE(rt5682s_component); + } else { + links[id].codecs = rt5682_component; + links[id].num_codecs = ARRAY_SIZE(rt5682_component); + } links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_rt5682_codec_init; @@ -920,7 +959,7 @@ static const struct platform_device_id board_ids[] = { .name = "sof_rt5682", }, { - .name = "tgl_mx98357a_rt5682", + .name = "tgl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | @@ -950,7 +989,7 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_BT_OFFLOAD_PRESENT), }, { - .name = "jsl_rt5682_mx98360a", + .name = "jsl_rt5682_mx98360", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | SOF_RT5682_SSP_CODEC(0) | @@ -1000,13 +1039,43 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_BT_OFFLOAD_PRESENT), }, { - .name = "adl_mx98357a_rt5682", + .name = "adl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(2) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .name = "jsl_rt5682s_rt1015", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_RT5682S_HEADPHONE_CODEC_PRESENT | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1015_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, + { + .name = "jsl_rt5682s_rt1015p", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_RT5682S_HEADPHONE_CODEC_PRESENT | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1015P_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, + { + .name = "jsl_rt5682s_mx98360", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_RT5682S_HEADPHONE_CODEC_PRESENT | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98360A_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index a0f6a69c703865..e4ff280eac23ec 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -291,7 +291,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { }, { .id = "10EC5682", - .drv_name = "adl_mx98357a_rt5682", + .drv_name = "adl_mx98357_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_max98357a_amp, .sof_fw_filename = "sof-adl.ri", diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index 69ff7286d357f4..20fd9dcc74af6a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -67,7 +67,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { }, { .id = "10EC5682", - .drv_name = "jsl_rt5682_mx98360a", + .drv_name = "jsl_rt5682_mx98360", .sof_fw_filename = "sof-jsl.ri", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98360a_spk, @@ -81,6 +81,30 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { .quirk_data = &mx98360a_spk, .sof_tplg_filename = "sof-jsl-cs42l42-mx98360a.tplg", }, + { + .id = "RTL5682", + .drv_name = "jsl_rt5682s_rt1015", + .sof_fw_filename = "sof-jsl.ri", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt1015_spk, + .sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg", + }, + { + .id = "RTL5682", + .drv_name = "jsl_rt5682s_rt1015p", + .sof_fw_filename = "sof-jsl.ri", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt1015p_spk, + .sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg", + }, + { + .id = "RTL5682", + .drv_name = "jsl_rt5682s_mx98360", + .sof_fw_filename = "sof-jsl.ri", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mx98360a_spk, + .sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 785d5f5f8a9c9c..91ef71c2535d0a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -333,7 +333,7 @@ static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC5682", - .drv_name = "tgl_mx98357a_rt5682", + .drv_name = "tgl_mx98357_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &tgl_codecs, .sof_fw_filename = "sof-tgl.ri", diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index e95c7c018e7d4c..4f2c2379531b9d 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -288,7 +288,6 @@ const struct snd_soc_dai_ops mtk_afe_fe_ops = { }; EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); -static DEFINE_MUTEX(irqs_lock); int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) { int i; diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 6635c3f72eccc0..df8b90baf98142 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3057,7 +3057,6 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8195_afe_private *afe_priv; - struct resource *res; struct device *dev = &pdev->dev; int i, irq_id, ret; struct snd_soc_component *component; @@ -3078,8 +3077,7 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); @@ -3266,9 +3264,7 @@ static struct platform_driver mt8195_afe_pcm_driver = { .driver = { .name = "mt8195-audio", .of_match_table = mt8195_afe_pcm_dt_match, -#ifdef CONFIG_PM .pm = &mt8195_afe_pm_ops, -#endif }, .probe = mt8195_afe_pcm_dev_probe, .remove = mt8195_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c index 878dec0b69ed38..f04bd1781356a0 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c @@ -788,9 +788,11 @@ static int init_adda_priv_data(struct mtk_base_afe *afe) { struct mt8195_afe_private *afe_priv = afe->platform_priv; struct mtk_dai_adda_priv *adda_priv; - int adda_dai_list[] = { MT8195_AFE_IO_DL_SRC, - MT8195_AFE_IO_UL_SRC1, - MT8195_AFE_IO_UL_SRC2}; + static const int adda_dai_list[] = { + MT8195_AFE_IO_DL_SRC, + MT8195_AFE_IO_UL_SRC1, + MT8195_AFE_IO_UL_SRC2 + }; int i; for (i = 0; i < ARRAY_SIZE(adda_dai_list); i++) { diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index 7378e42f27669f..ac591d453e1eeb 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2094,7 +2094,7 @@ static int mtk_dai_etdm_set_sysclk(struct snd_soc_dai *dai, { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8195_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + struct mtk_dai_etdm_priv *etdm_data; int dai_id; dev_dbg(dai->dev, "%s id %d freq %u, dir %d\n", diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c index de09f67c045022..cb15467e5fc565 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359-rt1019-rt5682.c @@ -995,6 +995,8 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8195_mt6359_rt1019_rt5682_soc_card; struct device_node *platform_node; + struct device_node *dp_node; + struct device_node *hdmi_node; struct snd_soc_dai_link *dai_link; struct mt8195_mt6359_rt1019_rt5682_priv *priv = NULL; int ret, i; @@ -1013,12 +1015,12 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) dai_link->platforms->of_node = platform_node; if (strcmp(dai_link->name, "DPTX_BE") == 0) { - dai_link->codecs->of_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,dptx-codec", 0); - if (!dai_link->codecs->of_node) { + dp_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,dptx-codec", 0); + if (!dp_node) { dev_dbg(&pdev->dev, "No property 'dptx-codec'\n"); } else { + dai_link->codecs->of_node = dp_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_dptx_codec_init; @@ -1026,12 +1028,12 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) } if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { - dai_link->codecs->of_node = - of_parse_phandle(pdev->dev.of_node, - "mediatek,hdmi-codec", 0); - if (!dai_link->codecs->of_node) { + hdmi_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,hdmi-codec", 0); + if (!hdmi_node) { dev_dbg(&pdev->dev, "No property 'hdmi-codec'\n"); } else { + dai_link->codecs->of_node = hdmi_node; dai_link->codecs->name = NULL; dai_link->codecs->dai_name = "i2s-hifi"; dai_link->init = mt8195_hdmi_codec_init; @@ -1040,8 +1042,10 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + if (!priv) { + ret = -ENOMEM; + goto out; + } snd_soc_card_set_drvdata(card, priv); @@ -1049,6 +1053,11 @@ static int mt8195_mt6359_rt1019_rt5682_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + +out: + of_node_put(hdmi_node); + of_node_put(dp_node); + of_node_put(platform_node); return ret; } diff --git a/sound/soc/meson/aiu-encoder-spdif.c b/sound/soc/meson/aiu-encoder-spdif.c index de850913975f17..97da60db2c4dbd 100644 --- a/sound/soc/meson/aiu-encoder-spdif.c +++ b/sound/soc/meson/aiu-encoder-spdif.c @@ -113,7 +113,7 @@ static int aiu_encoder_spdif_hw_params(struct snd_pcm_substream *substream, val |= AIU_958_MISC_MODE_32BITS; break; default: - dev_err(dai->dev, "Unsupport physical width\n"); + dev_err(dai->dev, "Unsupported physical width\n"); return -EINVAL; } diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index ac8f7324e94bc2..8b664cbf6fa6bd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -1747,5 +1747,5 @@ static struct platform_driver q6afe_dai_platform_driver = { }; module_platform_driver(q6afe_dai_platform_driver); -MODULE_DESCRIPTION("Q6 Audio Fronend dai driver"); +MODULE_DESCRIPTION("Q6 Audio Frontend dai driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 38bd603eeb4541..64d9891b6434fa 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -20,10 +20,12 @@ #define PDM_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */ #define PDM_SIGNOFF_CLK_RATE (100000000) +#define PDM_PATH_MAX (4) enum rk_pdm_version { RK_PDM_RK3229, RK_PDM_RK3308, + RK_PDM_RV1126, }; struct rk_pdm_dev { @@ -121,6 +123,55 @@ static unsigned int get_pdm_ds_ratio(unsigned int sr) return ratio; } +static unsigned int get_pdm_cic_ratio(unsigned int clk) +{ + switch (clk) { + case 4096000: + case 5644800: + case 6144000: + return 0; + case 2048000: + case 2822400: + case 3072000: + return 1; + case 1024000: + case 1411200: + case 1536000: + return 2; + default: + return 1; + } +} + +static unsigned int samplerate_to_bit(unsigned int samplerate) +{ + switch (samplerate) { + case 8000: + case 11025: + case 12000: + return 0; + case 16000: + case 22050: + case 24000: + return 1; + case 32000: + return 2; + case 44100: + case 48000: + return 3; + case 64000: + case 88200: + case 96000: + return 4; + case 128000: + case 176400: + case 192000: + return 5; + default: + return 1; + } +} + static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai) { return snd_soc_dai_get_drvdata(dai); @@ -166,7 +217,8 @@ static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream, if (ret) return -EINVAL; - if (pdm->version == RK_PDM_RK3308) { + if (pdm->version == RK_PDM_RK3308 || + pdm->version == RK_PDM_RV1126) { rational_best_approximation(clk_out, clk_src, GENMASK(16 - 1, 0), GENMASK(16 - 1, 0), @@ -194,8 +246,18 @@ static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream, PDM_CLK_FD_RATIO_MSK, val); } - val = get_pdm_ds_ratio(samplerate); - regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); + + if (pdm->version == RK_PDM_RV1126) { + val = get_pdm_cic_ratio(clk_out); + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CIC_RATIO_MSK, val); + val = samplerate_to_bit(samplerate); + regmap_update_bits(pdm->regmap, PDM_CTRL0, + PDM_SAMPLERATE_MSK, PDM_SAMPLERATE(val)); + } else { + val = get_pdm_ds_ratio(samplerate); + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); + } + regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, PDM_HPF_CF_MSK, PDM_HPF_60HZ); regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, @@ -441,9 +503,10 @@ static bool rockchip_pdm_precious_reg(struct device *dev, unsigned int reg) } static const struct reg_default rockchip_pdm_reg_defaults[] = { - {0x04, 0x78000017}, - {0x08, 0x0bb8ea60}, - {0x18, 0x0000001f}, + { PDM_CTRL0, 0x78000017 }, + { PDM_CTRL1, 0x0bb8ea60 }, + { PDM_CLK_CTRL, 0x0000e401 }, + { PDM_DMA_CTRL, 0x0000001f }, }; static const struct regmap_config rockchip_pdm_regmap_config = { @@ -469,12 +532,44 @@ static const struct of_device_id rockchip_pdm_match[] __maybe_unused = { .data = (void *)RK_PDM_RK3308 }, { .compatible = "rockchip,rk3308-pdm", .data = (void *)RK_PDM_RK3308 }, + { .compatible = "rockchip,rk3568-pdm", + .data = (void *)RK_PDM_RV1126 }, + { .compatible = "rockchip,rv1126-pdm", + .data = (void *)RK_PDM_RV1126 }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_pdm_match); +static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *node) +{ + unsigned int path[PDM_PATH_MAX]; + int cnt = 0, ret = 0, i = 0, val = 0, msk = 0; + + cnt = of_count_phandle_with_args(node, "rockchip,path-map", + NULL); + if (cnt != PDM_PATH_MAX) + return cnt; + + ret = of_property_read_u32_array(node, "rockchip,path-map", + path, cnt); + if (ret) + return ret; + + for (i = 0; i < cnt; i++) { + if (path[i] >= PDM_PATH_MAX) + return -EINVAL; + msk |= PDM_PATH_MASK(i); + val |= PDM_PATH(i, path[i]); + } + + regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, msk, val); + + return 0; +} + static int rockchip_pdm_probe(struct platform_device *pdev) { + struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; struct rk_pdm_dev *pdm; struct resource *res; @@ -540,6 +635,11 @@ static int rockchip_pdm_probe(struct platform_device *pdev) } rockchip_pdm_rxctrl(pdm, 0); + + ret = rockchip_pdm_path_parse(pdm, node); + if (ret != 0 && ret != -ENOENT) + goto err_suspend; + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "could not register pcm: %d\n", ret); diff --git a/sound/soc/rockchip/rockchip_pdm.h b/sound/soc/rockchip/rockchip_pdm.h index 8e5bbafef7bbbe..cab977272ee6f6 100644 --- a/sound/soc/rockchip/rockchip_pdm.h +++ b/sound/soc/rockchip/rockchip_pdm.h @@ -41,6 +41,8 @@ #define PDM_PATH1_EN BIT(28) #define PDM_PATH0_EN BIT(27) #define PDM_HWT_EN BIT(26) +#define PDM_SAMPLERATE_MSK GENMASK(7, 5) +#define PDM_SAMPLERATE(x) ((x) << 5) #define PDM_VDW_MSK (0x1f << 0) #define PDM_VDW(X) ((X - 1) << 0) @@ -51,6 +53,9 @@ #define PDM_FD_DENOMINATOR_MSK GENMASK(15, 0) /* PDM CLK CTRL */ +#define PDM_PATH_SHIFT(x) (8 + (x) * 2) +#define PDM_PATH_MASK(x) (0x3 << PDM_PATH_SHIFT(x)) +#define PDM_PATH(x, v) ((v) << PDM_PATH_SHIFT(x)) #define PDM_CLK_FD_RATIO_MSK BIT(6) #define PDM_CLK_FD_RATIO_40 (0X0 << 6) #define PDM_CLK_FD_RATIO_35 BIT(6) @@ -66,6 +71,7 @@ #define PDM_CLK_1280FS (0x2 << 0) #define PDM_CLK_2560FS (0x3 << 0) #define PDM_CLK_5120FS (0x4 << 0) +#define PDM_CIC_RATIO_MSK (0x3 << 0) /* PDM HPF CTRL */ #define PDM_HPF_LE BIT(3) diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index e9481187a08c83..de66cc422e6eae 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -397,6 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, /* clear again, just in case */ writel(0x0, i2s->regs + S3C2412_IISFIC); + fallthrough; + case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (!i2s->master) { diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 8e8d917d22f8ff..a08a897c52305f 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -251,8 +251,7 @@ int snd_soc_component_set_jack(struct snd_soc_component *component, EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); int snd_soc_component_module_get(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open) + void *mark, int upon_open) { int ret = 0; @@ -260,25 +259,24 @@ int snd_soc_component_module_get(struct snd_soc_component *component, !try_module_get(component->dev->driver->owner)) ret = -ENODEV; - /* mark substream if succeeded */ + /* mark module if succeeded */ if (ret == 0) - soc_component_mark_push(component, substream, module); + soc_component_mark_push(component, mark, module); return soc_component_ret(component, ret); } void snd_soc_component_module_put(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open, int rollback) + void *mark, int upon_open, int rollback) { - if (rollback && !soc_component_mark_match(component, substream, module)) + if (rollback && !soc_component_mark_match(component, mark, module)) return; if (component->driver->module_get_upon_open == !!upon_open) module_put(component->dev->driver->owner); - /* remove marked substream */ - soc_component_mark_pop(component, substream, module); + /* remove the mark from module */ + soc_component_mark_pop(component, mark, module); } int snd_soc_component_open(struct snd_soc_component *component, @@ -425,43 +423,36 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); #endif -int snd_soc_component_compr_open(struct snd_compr_stream *cstream) +int snd_soc_component_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret; + int ret = 0; - for_each_rtd_components(rtd, i, component) { - if (component->driver->compress_ops && - component->driver->compress_ops->open) { - ret = component->driver->compress_ops->open(component, cstream); - if (ret < 0) - return soc_component_ret(component, ret); - } + if (component->driver->compress_ops && + component->driver->compress_ops->open) + ret = component->driver->compress_ops->open(component, cstream); + + /* mark substream if succeeded */ + if (ret == 0) soc_component_mark_push(component, cstream, compr_open); - } - return 0; + return soc_component_ret(component, ret); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); -void snd_soc_component_compr_free(struct snd_compr_stream *cstream, +void snd_soc_component_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int rollback) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i; + if (rollback && !soc_component_mark_match(component, cstream, compr_open)) + return; - for_each_rtd_components(rtd, i, component) { - if (rollback && !soc_component_mark_match(component, cstream, compr_open)) - continue; + if (component->driver->compress_ops && + component->driver->compress_ops->free) + component->driver->compress_ops->free(component, cstream); - if (component->driver->compress_ops && - component->driver->compress_ops->free) - component->driver->compress_ops->free(component, cstream); - - soc_component_mark_pop(component, cstream, compr_open); - } + /* remove marked substream */ + soc_component_mark_pop(component, cstream, compr_open); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 36060800e9bd97..8e2494a9f3a7f0 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,6 +22,39 @@ #include <sound/soc-link.h> #include <linux/pm_runtime.h> +static int snd_soc_compr_components_open(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int ret = 0; + int i; + + for_each_rtd_components(rtd, i, component) { + ret = snd_soc_component_module_get_when_open(component, cstream); + if (ret < 0) + break; + + ret = snd_soc_component_compr_open(component, cstream); + if (ret < 0) + break; + } + + return ret; +} + +static void snd_soc_compr_components_free(struct snd_compr_stream *cstream, + int rollback) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i; + + for_each_rtd_components(rtd, i, component) { + snd_soc_component_compr_free(component, cstream, rollback); + snd_soc_component_module_put_when_close(component, cstream, rollback); + } +} + static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -44,7 +77,7 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) snd_soc_link_compr_shutdown(cstream, rollback); - snd_soc_component_compr_free(cstream, rollback); + snd_soc_compr_components_free(cstream, rollback); snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback); @@ -80,7 +113,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (ret < 0) goto err; - ret = snd_soc_component_compr_open(cstream); + ret = snd_soc_compr_components_open(cstream); if (ret < 0) goto err; @@ -137,7 +170,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = snd_soc_component_compr_open(cstream); + ret = snd_soc_compr_components_open(cstream); if (ret < 0) goto open_err; @@ -160,7 +193,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) return 0; machine_err: - snd_soc_component_compr_free(cstream, 1); + snd_soc_compr_components_free(cstream, 1); open_err: snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: @@ -205,7 +238,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream, 0); - snd_soc_component_compr_free(cstream, 0); + snd_soc_compr_components_free(cstream, 0); snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 4aa48c74f21a01..c54c8ca8d71569 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -15,6 +15,10 @@ #include <sound/dmaengine_pcm.h> +static unsigned int prealloc_buffer_size_kbytes = 512; +module_param(prealloc_buffer_size_kbytes, uint, 0444); +MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB)."); + /* * The platforms dmaengine driver does not support reporting the amount of * bytes that are still left to transfer. @@ -237,7 +241,7 @@ static int dmaengine_pcm_new(struct snd_soc_component *component, prealloc_buffer_size = config->prealloc_buffer_size; max_buffer_size = config->pcm_hardware->buffer_bytes_max; } else { - prealloc_buffer_size = 512 * 1024; + prealloc_buffer_size = prealloc_buffer_size_kbytes * 1024; max_buffer_size = SIZE_MAX; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 48f71bb81a2f2a..e30cb5abaf7a74 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,6 +1395,10 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue; + if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) + continue; + /* newly connected FE and BE */ err = dpcm_be_connect(fe, be, stream); if (err < 0) { diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f6e5ac3e03140b..73e1b7b48ce98e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1473,10 +1473,6 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, goto widget; } - control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; - dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", - w->name, w->num_kcontrols, control_hdr->type); - template.num_kcontrols = le32_to_cpu(w->num_kcontrols); kc = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(*kc), GFP_KERNEL); if (!kc) @@ -1536,6 +1532,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, } template.kcontrol_news = kc; + dev_dbg(tplg->dev, "ASoC: template %s with %d/%d/%d (mixer/enum/bytes) control\n", + w->name, mixer_count, enum_count, bytes_count); widget: ret = soc_tplg_widget_load(tplg, &template, w); diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 606d8137cd9887..bdea0faac117e8 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -2,7 +2,8 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o utils.o sof-audio.o -snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += probe.o compress.o + +snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c deleted file mode 100644 index 57d5bf0a171e3d..00000000000000 --- a/sound/soc/sof/compress.c +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2019-2020 Intel Corporation. All rights reserved. -// -// Author: Cezary Rojewski <cezary.rojewski@intel.com> -// - -#include <sound/soc.h> -#include "compress.h" -#include "ops.h" -#include "probe.h" - -const struct snd_compress_ops sof_probe_compressed_ops = { - .copy = sof_probe_compr_copy, -}; -EXPORT_SYMBOL(sof_probe_compressed_ops); - -int sof_probe_compr_open(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) -{ - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - int ret; - - ret = snd_sof_probe_compr_assign(sdev, cstream, dai); - if (ret < 0) { - dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret); - return ret; - } - - sdev->extractor_stream_tag = ret; - return 0; -} -EXPORT_SYMBOL(sof_probe_compr_open); - -int sof_probe_compr_free(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai) -{ - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - struct sof_probe_point_desc *desc; - size_t num_desc; - int i, ret; - - /* disconnect all probe points */ - ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc); - if (ret < 0) { - dev_err(dai->dev, "Failed to get probe points: %d\n", ret); - goto exit; - } - - for (i = 0; i < num_desc; i++) - sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1); - kfree(desc); - -exit: - ret = sof_ipc_probe_deinit(sdev); - if (ret < 0) - dev_err(dai->dev, "Failed to deinit probe: %d\n", ret); - - sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; - snd_compr_free_pages(cstream); - - return snd_sof_probe_compr_free(sdev, cstream, dai); -} -EXPORT_SYMBOL(sof_probe_compr_free); - -int sof_probe_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params, struct snd_soc_dai *dai) -{ - struct snd_compr_runtime *rtd = cstream->runtime; - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - int ret; - - cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; - cstream->dma_buffer.dev.dev = sdev->dev; - ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); - if (ret < 0) - return ret; - - ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai); - if (ret < 0) - return ret; - - ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag, - rtd->dma_bytes); - if (ret < 0) { - dev_err(dai->dev, "Failed to init probe: %d\n", ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL(sof_probe_compr_set_params); - -int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - - return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai); -} -EXPORT_SYMBOL(sof_probe_compr_trigger); - -int sof_probe_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) -{ - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - - return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai); -} -EXPORT_SYMBOL(sof_probe_compr_pointer); - -int sof_probe_compr_copy(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - char __user *buf, size_t count) -{ - struct snd_compr_runtime *rtd = cstream->runtime; - unsigned int offset, n; - void *ptr; - int ret; - - if (count > rtd->buffer_size) - count = rtd->buffer_size; - - div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); - ptr = rtd->dma_area + offset; - n = rtd->buffer_size - offset; - - if (count < n) { - ret = copy_to_user(buf, ptr, count); - } else { - ret = copy_to_user(buf, ptr, n); - ret += copy_to_user(buf + n, rtd->dma_area, count - n); - } - - if (ret) - return count - ret; - return count; -} -EXPORT_SYMBOL(sof_probe_compr_copy); diff --git a/sound/soc/sof/compress.h b/sound/soc/sof/compress.h deleted file mode 100644 index 4448c799e14b00..00000000000000 --- a/sound/soc/sof/compress.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2019-2020 Intel Corporation. All rights reserved. - * - * Author: Cezary Rojewski <cezary.rojewski@intel.com> - */ - -#ifndef __SOF_COMPRESS_H -#define __SOF_COMPRESS_H - -#include <sound/compress_driver.h> - -extern const struct snd_compress_ops sof_probe_compressed_ops; - -int sof_probe_compr_open(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai); -int sof_probe_compr_free(struct snd_compr_stream *cstream, - struct snd_soc_dai *dai); -int sof_probe_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params, struct snd_soc_dai *dai); -int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, - struct snd_soc_dai *dai); -int sof_probe_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai); -int sof_probe_compr_copy(struct snd_soc_component *component, - struct snd_compr_stream *cstream, - char __user *buf, size_t count); - -#endif diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a5dd728c580a93..58bb89af4de1f7 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -65,6 +65,40 @@ static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) return i - 1; } +static void snd_sof_refresh_control(struct snd_sof_control *scontrol) +{ + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_soc_component *scomp = scontrol->scomp; + enum sof_ipc_ctrl_type ctrl_type; + int ret; + + if (!scontrol->comp_data_dirty) + return; + + if (!pm_runtime_active(scomp->dev)) + return; + + if (scontrol->cmd == SOF_CTRL_CMD_BINARY) + ctrl_type = SOF_IPC_COMP_GET_DATA; + else + ctrl_type = SOF_IPC_COMP_GET_VALUE; + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + + /* refresh the component data from DSP */ + scontrol->comp_data_dirty = false; + ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + scontrol->cmd, false); + if (ret < 0) { + dev_err(scomp->dev, "error: failed to get control data: %d\n", ret); + /* Set the flag to re-try next time to get the data */ + scontrol->comp_data_dirty = true; + } +} + int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -74,6 +108,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = @@ -108,7 +144,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_VOLUME, true); return change; @@ -145,6 +181,8 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value; @@ -179,7 +217,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_SWITCH, true); @@ -195,6 +233,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + snd_sof_refresh_control(scontrol); + /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; @@ -226,7 +266,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, if (pm_runtime_active(scomp->dev)) snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_TYPE_VALUE_CHAN_SET, SOF_CTRL_CMD_ENUM, true); @@ -244,6 +284,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_abi_hdr *data = cdata->data; size_t size; + snd_sof_refresh_control(scontrol); + if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(scomp->dev, "error: data max %d exceeds ucontrol data array size\n", @@ -475,6 +517,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, (struct snd_ctl_tlv __user *)binary_data; size_t data_size; + snd_sof_refresh_control(scontrol); + /* * Decrement the limit by ext bytes header size to * ensure the user space buffer is not exceeded. @@ -511,3 +555,145 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, return 0; } + +static void snd_sof_update_control(struct snd_sof_control *scontrol, + struct sof_ipc_ctrl_data *cdata) +{ + struct snd_soc_component *scomp = scontrol->scomp; + struct sof_ipc_ctrl_data *local_cdata; + int i; + + local_cdata = scontrol->control_data; + + if (cdata->cmd == SOF_CTRL_CMD_BINARY) { + if (cdata->num_elems != local_cdata->data->size) { + dev_err(scomp->dev, + "error: cdata binary size mismatch %u - %u\n", + cdata->num_elems, local_cdata->data->size); + return; + } + + /* copy the new binary data */ + memcpy(local_cdata->data, cdata->data, cdata->num_elems); + } else if (cdata->num_elems != scontrol->num_channels) { + dev_err(scomp->dev, + "error: cdata channel count mismatch %u - %d\n", + cdata->num_elems, scontrol->num_channels); + } else { + /* copy the new values */ + for (i = 0; i < cdata->num_elems; i++) + local_cdata->chanv[i].value = cdata->chanv[i].value; + } +} + +void snd_sof_control_notify(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata) +{ + struct snd_soc_dapm_widget *widget; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct snd_kcontrol *kc = NULL; + struct soc_mixer_control *sm; + struct soc_bytes_ext *be; + size_t expected_size; + struct soc_enum *se; + bool found = false; + int i, type; + + /* Find the swidget first */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->comp_id == cdata->comp_id) { + found = true; + break; + } + } + + if (!found) + return; + + /* Translate SOF cmd to TPLG type */ + switch (cdata->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_SWITCH: + type = SND_SOC_TPLG_TYPE_MIXER; + break; + case SOF_CTRL_CMD_BINARY: + type = SND_SOC_TPLG_TYPE_BYTES; + break; + case SOF_CTRL_CMD_ENUM: + type = SND_SOC_TPLG_TYPE_ENUM; + break; + default: + dev_err(sdev->dev, "error: unknown cmd %u\n", cdata->cmd); + return; + } + + widget = swidget->widget; + for (i = 0; i < widget->num_kcontrols; i++) { + /* skip non matching types or non matching indexes within type */ + if (widget->dobj.widget.kcontrol_type[i] == type && + widget->kcontrol_news[i].index == cdata->index) { + kc = widget->kcontrols[i]; + break; + } + } + + if (!kc) + return; + + switch (cdata->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_SWITCH: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SOF_CTRL_CMD_BINARY: + be = (struct soc_bytes_ext *)kc->private_value; + scontrol = be->dobj.private; + break; + case SOF_CTRL_CMD_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + return; + } + + expected_size = sizeof(struct sof_ipc_ctrl_data); + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + expected_size += cdata->num_elems * + sizeof(struct sof_ipc_ctrl_value_chan); + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + expected_size += cdata->num_elems * + sizeof(struct sof_ipc_ctrl_value_comp); + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr); + break; + default: + return; + } + + if (cdata->rhdr.hdr.size != expected_size) { + dev_err(sdev->dev, "error: component notification size mismatch\n"); + return; + } + + if (cdata->num_elems) + /* + * The message includes the updated value/data, update the + * control's local cache using the received notification + */ + snd_sof_update_control(scontrol, cdata); + else + /* Mark the scontrol that the value/data is changed in SOF */ + scontrol->comp_data_dirty = true; + + snd_ctl_notify_one(swidget->scomp->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); +} diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 59d0d7b2b55c82..2ea29186e397b0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -15,11 +15,11 @@ #include "sof-priv.h" #include "ops.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) -#include "probe.h" +#include "sof-probes.h" #endif /* see SOF_DBG_ flags */ -int sof_core_debug; +int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); @@ -202,8 +202,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || - (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { + if (sof_core_debug & SOF_DBG_ENABLE_TRACE) { sdev->dtrace_is_supported = true; /* init DMA trace */ @@ -326,9 +325,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) spin_lock_init(&sdev->hw_lock); mutex_init(&sdev->power_state_access); - if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) - INIT_WORK(&sdev->probe_work, sof_probe_work); - /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; @@ -340,6 +336,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->boot_timeout = plat_data->desc->boot_timeout; if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { + INIT_WORK(&sdev->probe_work, sof_probe_work); schedule_work(&sdev->probe_work); return 0; } diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index a51a928ea40a73..f37ea195640615 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -20,7 +20,7 @@ #include "ops.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) -#include "probe.h" +#include "sof-probes.h" /** * strsplit_u32 - Split string into sequence of u32 tokens @@ -546,10 +546,10 @@ static const struct file_operations sof_dfs_fops = { }; /* create FS entry for debug files that can expose DSP memories, registers */ -int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name, - enum sof_debugfs_access_type access_type) +static int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name, + enum sof_debugfs_access_type access_type) { struct snd_sof_dfsentry *dfse; @@ -586,7 +586,21 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item); + +int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, u32 offset, + size_t size, const char *name, + enum sof_debugfs_access_type access_type) +{ + int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); + + if (bar < 0) + return bar; + + return snd_sof_debugfs_io_item(sdev, sdev->bar[bar] + offset, size, name, + access_type); +} +EXPORT_SYMBOL_GPL(snd_sof_debugfs_add_region_item_iomem); /* create FS entry for debug files to expose kernel memory */ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/imx/imx-ops.h b/sound/soc/sof/imx/imx-ops.h new file mode 100644 index 00000000000000..24235ef8c8faff --- /dev/null +++ b/sound/soc/sof/imx/imx-ops.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ + +#ifndef __IMX_OPS_H__ +#define __IMX_OPS_H__ + +extern struct snd_sof_dsp_ops sof_imx8_ops; +extern struct snd_sof_dsp_ops sof_imx8x_ops; +extern struct snd_sof_dsp_ops sof_imx8m_ops; + +#endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 7e9723a10d02e0..0247806be8d720 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -22,6 +22,7 @@ #include <dt-bindings/firmware/imx/rsrc.h> #include "../ops.h" #include "imx-common.h" +#include "imx-ops.h" /* DSP memories */ #define IRAM_OFFSET 0x10000 @@ -375,11 +376,12 @@ static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) } } -static void imx8_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +static int imx8_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + return 0; } static int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, @@ -426,9 +428,6 @@ struct snd_sof_dsp_ops sof_imx8_ops = { .block_read = sof_block_read, .block_write = sof_block_write, - /* Module IO */ - .read64 = sof_io_read64, - /* ipc */ .send_msg = imx8_send_msg, .fw_ready = sof_fw_ready, @@ -446,9 +445,10 @@ struct snd_sof_dsp_ops sof_imx8_ops = { /* Debug information */ .dbg_dump = imx8_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* Firmware ops */ - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, /* DAI drivers */ .drv = imx8_dai, @@ -475,9 +475,6 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { .block_read = sof_block_read, .block_write = sof_block_write, - /* Module IO */ - .read64 = sof_io_read64, - /* ipc */ .send_msg = imx8_send_msg, .fw_ready = sof_fw_ready, @@ -495,9 +492,10 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { /* Debug information */ .dbg_dump = imx8_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* Firmware ops */ - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, /* DAI drivers */ .drv = imx8_dai, diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 892e1482f97faa..08d29f095d5159 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -18,6 +18,7 @@ #include "../ops.h" #include "imx-common.h" +#include "imx-ops.h" #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 @@ -238,11 +239,12 @@ static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type) } } -static void imx8m_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +static int imx8m_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + return 0; } static int imx8m_ipc_pcm_params(struct snd_sof_dev *sdev, @@ -254,6 +256,17 @@ static int imx8m_ipc_pcm_params(struct snd_sof_dev *sdev, static struct snd_soc_dai_driver imx8m_dai[] = { { + .name = "sai1", + .playback = { + .channels_min = 1, + .channels_max = 32, + }, + .capture = { + .channels_min = 1, + .channels_max = 32, + }, +}, +{ .name = "sai3", .playback = { .channels_min = 1, @@ -278,9 +291,6 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { .block_read = sof_block_read, .block_write = sof_block_write, - /* Module IO */ - .read64 = sof_io_read64, - /* ipc */ .send_msg = imx8m_send_msg, .fw_ready = sof_fw_ready, @@ -298,9 +308,10 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { /* Debug information */ .dbg_dump = imx8_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* Firmware ops */ - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, /* DAI drivers */ .drv = imx8m_dai, diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index feae487f02274d..9635dd47a17d8e 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -9,7 +9,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ apl.o cnl.o tgl.o icl.o -snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o +snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o snd-sof-intel-hda-objs := hda-codec.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index c7ed2b3d6abca2..e6a1f6532547fc 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -65,6 +65,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), .dbg_dump = hda_dsp_dump, .ipc_dump = hda_ipc_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, @@ -125,7 +126,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; EXPORT_SYMBOL_NS(sof_apl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 89a6c1f04a5558..d0927541774934 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -535,8 +535,8 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } - /* set default mailbox */ - snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; return ret; } @@ -635,6 +635,7 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = { .debug_map = bdw_debugfs, .debug_map_count = ARRAY_SIZE(bdw_debugfs), .dbg_dump = bdw_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -657,7 +658,7 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; static const struct sof_intel_dsp_desc bdw_chip_info = { diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 8edaf6fdd218d5..8f60c72fee7e93 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -249,6 +249,7 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), .dbg_dump = atom_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -275,7 +276,7 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; static const struct sof_intel_dsp_desc byt_chip_info = { @@ -326,6 +327,7 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .debug_map = cht_debugfs, .debug_map_count = ARRAY_SIZE(cht_debugfs), .dbg_dump = atom_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -353,7 +355,7 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; static const struct sof_intel_dsp_desc cht_chip_info = { diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index e115e12a856fda..430a268e6b26b6 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -270,6 +270,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), .dbg_dump = hda_dsp_dump, .ipc_dump = cnl_ipc_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, @@ -330,7 +331,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 6704dbcd101cdd..d58514aa363705 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -16,6 +16,10 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) +#include "../sof-probes.h" +#endif + struct hda_pipe_params { u8 host_dma_id; u8 link_dma_id; @@ -401,18 +405,6 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = { .prepare = hda_link_pcm_prepare, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) -#include "../compress.h" - -static struct snd_soc_cdai_ops sof_probe_compr_ops = { - .startup = sof_probe_compr_open, - .shutdown = sof_probe_compr_free, - .set_params = sof_probe_compr_set_params, - .trigger = sof_probe_compr_trigger, - .pointer = sof_probe_compr_pointer, -}; - -#endif #endif static int ssp_dai_hw_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 623cf291e20747..058baca2cd0e90 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(enable_trace_D0I3_S0, * DSP Core control. */ -int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) +static int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; u32 reset; @@ -73,7 +73,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) +static int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) { unsigned int crst; u32 adspcs; @@ -113,7 +113,7 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) +static int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) { /* stall core */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, @@ -125,6 +125,31 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) return hda_dsp_core_reset_enter(sdev, core_mask); } +static bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + int val; + bool is_enable; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); + +#define MASK_IS_EQUAL(v, m, field) ({ \ + u32 _m = field(m); \ + ((v) & _m) == _m; \ +}) + + is_enable = MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_CPA_MASK) && + MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_SPA_MASK) && + !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + +#undef MASK_IS_EQUAL + + dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", + is_enable, core_mask); + + return is_enable; +} + int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) { int ret; @@ -156,7 +181,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) * Power Management. */ -int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) +static int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) { unsigned int cpa; u32 adspcs; @@ -195,7 +220,7 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) +static int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; int ret; @@ -218,32 +243,6 @@ int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, - unsigned int core_mask) -{ - int val; - bool is_enable; - - val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); - -#define MASK_IS_EQUAL(v, m, field) ({ \ - u32 _m = field(m); \ - ((v) & _m) == _m; \ -}) - - is_enable = MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_CPA_MASK) && - MASK_IS_EQUAL(val, core_mask, HDA_DSP_ADSPCS_SPA_MASK) && - !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && - !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); - -#undef MASK_IS_EQUAL - - dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", - is_enable, core_mask); - - return is_enable; -} - int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index acfeca42604cde..11f20a5a62dfaf 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -253,9 +253,9 @@ int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) return SRAM_WINDOW_OFFSET(id); } -void hda_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +int hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { if (!substream || !sdev->stream_box.size) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); @@ -268,10 +268,13 @@ void hda_ipc_msg_data(struct snd_sof_dev *sdev, hda_stream.hstream); /* The stream might already be closed */ - if (hstream) - sof_mailbox_read(sdev, hda_stream->stream.posn_offset, - p, sz); + if (!hstream) + return -ESTRPIPE; + + sof_mailbox_read(sdev, hda_stream->stream.posn_offset, p, sz); } + + return 0; } int hda_ipc_pcm_params(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-compress.c b/sound/soc/sof/intel/hda-probes.c index fe2f3f7d236b10..fe2f3f7d236b10 100644 --- a/sound/soc/sof/intel/hda-compress.c +++ b/sound/soc/sof/intel/hda-probes.c diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 63c367478f1c9a..1d845c2cbc33d4 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -25,6 +25,33 @@ #define HDA_LTRP_GB_VALUE_US 95 +static inline const char *hda_hstream_direction_str(struct hdac_stream *hstream) +{ + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + +static char *hda_hstream_dbg_get_stream_info_str(struct hdac_stream *hstream) +{ + struct snd_soc_pcm_runtime *rtd; + + if (hstream->substream) + rtd = asoc_substream_to_rtd(hstream->substream); + else if (hstream->cstream) + rtd = hstream->cstream->private_data; + else + /* Non audio DMA user, like dma-trace */ + return kasprintf(GFP_KERNEL, "-- (%s, stream_tag: %u)", + hda_hstream_direction_str(hstream), + hstream->stream_tag); + + return kasprintf(GFP_KERNEL, "dai_link \"%s\" (%s, stream_tag: %u)", + rtd->dai_link->name, hda_hstream_direction_str(hstream), + hstream->stream_tag); +} + /* * set up one of BDL entries for a stream */ @@ -89,13 +116,13 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, int remain, ioc; period_bytes = stream->period_bytes; - dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); + dev_dbg(sdev->dev, "%s: period_bytes:0x%x\n", __func__, period_bytes); if (!period_bytes) period_bytes = stream->bufsize; periods = stream->bufsize / period_bytes; - dev_dbg(sdev->dev, "periods:%d\n", periods); + dev_dbg(sdev->dev, "%s: periods:%d\n", __func__, periods); remain = stream->bufsize % period_bytes; if (remain) @@ -244,7 +271,8 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN); if (!found) { - dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); + dev_dbg(sdev->dev, "%s: stream_tag %d not opened!\n", + __func__, stream_tag); return -ENODEV; } @@ -257,7 +285,7 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); u32 dma_start = SOF_HDA_SD_CTL_DMA_START; - int ret; + int ret = 0; u32 run; /* cmd must be for audio stream */ @@ -283,14 +311,9 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret < 0) { - dev_err(sdev->dev, - "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", - __func__, cmd); - return ret; - } + if (ret >= 0) + hstream->running = true; - hstream->running = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -306,27 +329,32 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret < 0) { - dev_err(sdev->dev, - "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", - __func__, cmd); - return ret; - } + if (ret >= 0) { + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK); - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK); - - hstream->running = false; - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - 1 << hstream->index, 0x0); + hstream->running = false; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_INTCTL, + 1 << hstream->index, 0x0); + } break; default: dev_err(sdev->dev, "error: unknown command: %d\n", cmd); return -EINVAL; } - return 0; + if (ret < 0) { + char *stream_name = hda_hstream_dbg_get_stream_info_str(hstream); + + dev_err(sdev->dev, + "%s: cmd %d on %s: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd, stream_name ? stream_name : "unknown stream"); + kfree(stream_name); + } + + return ret; } /* minimal recommended programming for ICCMAX stream */ @@ -440,9 +468,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_STREAM_RUN_TIMEOUT); if (ret < 0) { + char *stream_name = hda_hstream_dbg_get_stream_info_str(hstream); + dev_err(sdev->dev, - "error: %s: timeout on STREAM_SD_OFFSET read1\n", - __func__); + "%s: on %s: timeout on STREAM_SD_OFFSET read1\n", + __func__, stream_name ? stream_name : "unknown stream"); + kfree(stream_name); return ret; } @@ -506,9 +537,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_STREAM_RUN_TIMEOUT); if (ret < 0) { + char *stream_name = hda_hstream_dbg_get_stream_info_str(hstream); + dev_err(sdev->dev, - "error: %s: timeout on STREAM_SD_OFFSET read2\n", - __func__); + "%s: on %s: timeout on STREAM_SD_OFFSET read1\n", + __func__, stream_name ? stream_name : "unknown stream"); + kfree(stream_name); return ret; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f60e2c57d3d0c6..c11e4c14d87558 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -294,7 +294,38 @@ void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) sdw_intel_process_wakeen_event(hdev->sdw); } -#endif +#else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ +static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline int hda_sdw_probe(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline int hda_sdw_exit(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + return false; +} + +static inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context) +{ + return IRQ_HANDLED; +} + +static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + return false; +} + +#endif /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ /* * Debug diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 4fdfb108645c52..cb5a1b17f15328 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -492,17 +492,8 @@ struct sof_intel_hda_stream { */ int hda_dsp_probe(struct snd_sof_dev *sdev); int hda_dsp_remove(struct snd_sof_dev *sdev); -int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, - unsigned int core_mask); -int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, - unsigned int core_mask); -int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask); -int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask); -int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); -bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, - unsigned int core_mask); int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); @@ -572,9 +563,9 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int enable, u32 size); -void hda_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz); +int hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); int hda_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, const struct sof_ipc_pcm_params_reply *reply); @@ -619,8 +610,6 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); */ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev); -int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev); -int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); /* pre and post fw run ops */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); @@ -695,45 +684,15 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); #else -static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) -{ - return 0; -} - -static inline int hda_sdw_probe(struct snd_sof_dev *sdev) -{ - return 0; -} - static inline int hda_sdw_startup(struct snd_sof_dev *sdev) { return 0; } -static inline int hda_sdw_exit(struct snd_sof_dev *sdev) -{ - return 0; -} - static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } -static inline bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) -{ - return false; -} - -static inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context) -{ - return IRQ_HANDLED; -} - -static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) -{ - return false; -} - static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { } diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index ee095b8f2d01ca..38a40c03c9da99 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -64,6 +64,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { .debug_map_count = ARRAY_SIZE(icl_dsp_debugfs), .dbg_dump = hda_dsp_dump, .ipc_dump = cnl_ipc_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, @@ -125,7 +126,7 @@ const struct snd_sof_dsp_ops sof_icl_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c index de66f8a82a07a4..df37187c8427d9 100644 --- a/sound/soc/sof/intel/intel-ipc.c +++ b/sound/soc/sof/intel/intel-ipc.c @@ -25,9 +25,9 @@ struct intel_stream { }; /* Mailbox-based Intel IPC implementation */ -void intel_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +int intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { if (!substream || !sdev->stream_box.size) { sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); @@ -35,9 +35,13 @@ void intel_ipc_msg_data(struct snd_sof_dev *sdev, struct intel_stream *stream = substream->runtime->private_data; /* The stream might already be closed */ - if (stream) - sof_mailbox_read(sdev, stream->posn_offset, p, sz); + if (!stream) + return -ESTRPIPE; + + sof_mailbox_read(sdev, stream->posn_offset, p, sz); } + + return 0; } EXPORT_SYMBOL_NS(intel_ipc_msg_data, SND_SOC_SOF_INTEL_HIFI_EP_IPC); diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index f89e746c25709c..a023b3cc0af4b3 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -26,7 +26,6 @@ static const struct sof_dev_desc bxt_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &apl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -42,7 +41,6 @@ static const struct sof_dev_desc glk_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &apl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index f23257adf2abdf..40cf1cd00042fa 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -27,7 +27,6 @@ static const struct sof_dev_desc cnl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -44,7 +43,6 @@ static const struct sof_dev_desc cfl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -61,7 +59,6 @@ static const struct sof_dev_desc cml_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 2f60c28ae81f87..39c84121b31310 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -27,7 +27,6 @@ static const struct sof_dev_desc icl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &icl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -43,7 +42,6 @@ static const struct sof_dev_desc jsl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &jsl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index d04ce84fe7cc2a..f2ea34df9741da 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -27,7 +27,6 @@ static const struct sof_dev_desc tgl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &tgl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -44,7 +43,6 @@ static const struct sof_dev_desc tglh_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &tglh_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -60,7 +58,6 @@ static const struct sof_dev_desc ehl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &ehl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -77,7 +74,6 @@ static const struct sof_dev_desc adls_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &adls_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", @@ -94,7 +90,6 @@ static const struct sof_dev_desc adl_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = -1, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &tgl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 4bded668b672e5..3d6d013844d7ca 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -165,6 +165,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .debug_map = tng_debugfs, .debug_map_count = ARRAY_SIZE(tng_debugfs), .dbg_dump = atom_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -187,7 +188,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; const struct sof_intel_dsp_desc tng_chip_info = { @@ -201,7 +202,6 @@ static const struct sof_dev_desc tng_desc = { .resindex_pcicfg_base = -1, .resindex_imr_base = 0, .irqindex_host_ipc = -1, - .resindex_dma_base = -1, .chip_info = &tng_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 199d41a7dc9bfb..664a11aaada250 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -60,6 +60,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { .debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs), .dbg_dump = hda_dsp_dump, .ipc_dump = cnl_ipc_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, @@ -120,7 +121,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .arch_ops = &sof_xtensa_arch_ops, + .dsp_arch_ops = &sof_xtensa_arch_ops, }; EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c2d07b783f60a3..0034e7a34a1d7e 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -18,7 +18,7 @@ #include "sof-audio.h" #include "ops.h" -static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type); static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); /* @@ -192,6 +192,29 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str2 = "unknown type"; break; } break; + case SOF_IPC_GLB_PROBE: + str = "GLB_PROBE"; + switch (type) { + case SOF_IPC_PROBE_INIT: + str2 = "INIT"; break; + case SOF_IPC_PROBE_DEINIT: + str2 = "DEINIT"; break; + case SOF_IPC_PROBE_DMA_ADD: + str2 = "DMA_ADD"; break; + case SOF_IPC_PROBE_DMA_INFO: + str2 = "DMA_INFO"; break; + case SOF_IPC_PROBE_DMA_REMOVE: + str2 = "DMA_REMOVE"; break; + case SOF_IPC_PROBE_POINT_ADD: + str2 = "POINT_ADD"; break; + case SOF_IPC_PROBE_POINT_INFO: + str2 = "POINT_INFO"; break; + case SOF_IPC_PROBE_POINT_REMOVE: + str2 = "POINT_REMOVE"; break; + default: + str2 = "unknown type"; break; + } + break; default: str = "unknown GLB command"; break; } @@ -226,15 +249,17 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, msecs_to_jiffies(sdev->ipc_timeout)); if (ret == 0) { - dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", - hdr->cmd, hdr->size); + dev_err(sdev->dev, + "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n", + hdr->cmd, hdr->size, msg->reply_size); snd_sof_handle_fw_exception(ipc->sdev); ret = -ETIMEDOUT; } else { ret = msg->reply_error; if (ret < 0) { - dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n", - hdr->cmd, msg->reply_size); + dev_err(sdev->dev, + "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n", + hdr->cmd, hdr->size, msg->reply_size, ret); } else { ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); if (msg->reply_size) @@ -286,7 +311,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, spin_unlock_irq(&sdev->ipc_lock); - if (ret < 0) { + if (ret) { dev_err_ratelimited(sdev->dev, "error: ipc tx failed with error %d\n", ret); @@ -296,10 +321,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, ipc_log_header(sdev->dev, "ipc tx", msg->header); /* now wait for completion */ - if (!ret) - ret = tx_wait_done(ipc, msg, reply_data); - - return ret; + return tx_wait_done(ipc, msg, reply_data); } /* send IPC message from host to DSP */ @@ -369,15 +391,52 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); +static void ipc_comp_notification(struct snd_sof_dev *sdev, + struct sof_ipc_cmd_hdr *hdr) +{ + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + struct sof_ipc_ctrl_data *cdata; + int ret; + + switch (msg_type) { + case SOF_IPC_COMP_GET_VALUE: + case SOF_IPC_COMP_GET_DATA: + cdata = kmalloc(hdr->size, GFP_KERNEL); + if (!cdata) + return; + + /* read back full message */ + ret = snd_sof_ipc_msg_data(sdev, NULL, cdata, hdr->size); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to read component event: %d\n", ret); + goto err; + } + break; + default: + dev_err(sdev->dev, "error: unhandled component message %#x\n", msg_type); + return; + } + + snd_sof_control_notify(sdev, cdata); + +err: + kfree(cdata); +} + /* DSP firmware has sent host a message */ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) { struct sof_ipc_cmd_hdr hdr; u32 cmd, type; - int err = 0; + int err; /* read back header */ - snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); + err = snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); + if (err < 0) { + dev_warn(sdev->dev, "failed to read IPC header: %d\n", err); + return; + } ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); cmd = hdr.cmd & SOF_GLB_TYPE_MASK; @@ -404,7 +463,9 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) case SOF_IPC_GLB_COMPOUND: case SOF_IPC_GLB_TPLG_MSG: case SOF_IPC_GLB_PM_MSG: + break; case SOF_IPC_GLB_COMP_MSG: + ipc_comp_notification(sdev, &hdr); break; case SOF_IPC_GLB_STREAM_MSG: /* need to pass msg id into the function */ @@ -426,19 +487,22 @@ EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); * IPC trace mechanism. */ -static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type) { struct sof_ipc_dma_trace_posn posn; + int ret; - switch (msg_id) { + switch (msg_type) { case SOF_IPC_TRACE_DMA_POSITION: /* read back full message */ - snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); - snd_sof_trace_update_pos(sdev, &posn); + ret = snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); + if (ret < 0) + dev_warn(sdev->dev, "failed to read trace position: %d\n", ret); + else + snd_sof_trace_update_pos(sdev, &posn); break; default: - dev_err(sdev->dev, "error: unhandled trace message %x\n", - msg_id); + dev_err(sdev->dev, "error: unhandled trace message %#x\n", msg_type); break; } } @@ -453,7 +517,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; - int direction; + int direction, ret; spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); if (!spcm) { @@ -464,7 +528,11 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) } stream = &spcm->stream[direction]; - snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return; + } dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", posn.host_posn, posn.dai_posn, posn.wallclock); @@ -483,7 +551,7 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; - int direction; + int direction, ret; spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); if (!spcm) { @@ -493,7 +561,11 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) } stream = &spcm->stream[direction]; - snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret); + return; + } dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", posn.host_posn, posn.xrun_comp_id, posn.xrun_size); @@ -520,7 +592,7 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) ipc_xrun(sdev, msg_id); break; default: - dev_err(sdev->dev, "error: unhandled stream message %x\n", + dev_err(sdev->dev, "error: unhandled stream message %#x\n", msg_id); break; } @@ -681,15 +753,19 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems; if (send) - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, - scontrol->readback_offset, - cdata->chanv, send_bytes); + err = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, + scontrol->readback_offset, + cdata->chanv, send_bytes); else - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, - scontrol->readback_offset, - cdata->chanv, send_bytes); - return 0; + err = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_IRAM, + scontrol->readback_offset, + cdata->chanv, send_bytes); + + if (err) + dev_err_once(sdev->dev, "error: %s TYPE_IRAM failed\n", + send ? "write to" : "read from"); + return err; } cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; @@ -762,22 +838,6 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, } EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data); -/* - * IPC layer enumeration. - */ - -int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, - size_t dspbox_size, u32 hostbox, - size_t hostbox_size) -{ - sdev->dsp_box.offset = dspbox; - sdev->dsp_box.size = dspbox_size; - sdev->host_box.offset = hostbox; - sdev->host_box.size = hostbox_size; - return 0; -} -EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); - int snd_sof_ipc_valid(struct snd_sof_dev *sdev) { struct sof_ipc_fw_ready *ready = &sdev->fw_ready; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index bb79c77775b3df..62e6f257c3f07a 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -86,7 +86,7 @@ static int get_cc_info(struct snd_sof_dev *sdev, } /* parse the extended FW boot data structures from FW boot message */ -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) +static int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) { struct sof_ipc_ext_data_hdr *ext_hdr; void *ext_data; @@ -97,15 +97,16 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ - snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr), - (void *)((u8 *)ext_data + sizeof(*ext_hdr)), - ext_hdr->hdr.size - sizeof(*ext_hdr)); + snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, + offset + sizeof(*ext_hdr), + (void *)((u8 *)ext_data + sizeof(*ext_hdr)), + ext_hdr->hdr.size - sizeof(*ext_hdr)); dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n", ext_hdr->type, ext_hdr->hdr.size); @@ -138,7 +139,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; } @@ -146,7 +147,6 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) kfree(ext_data); return ret; } -EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); static int ext_man_get_fw_version(struct snd_sof_dev *sdev, const struct sof_ext_man_elem_header *hdr) @@ -372,7 +372,6 @@ static void sof_get_windows(struct snd_sof_dev *sdev) u32 debug_size = 0; u32 debug_offset = 0; int window_offset; - int bar; int i; if (!sdev->info_window) { @@ -380,12 +379,6 @@ static void sof_get_windows(struct snd_sof_dev *sdev) return; } - bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); - if (bar < 0) { - dev_err(sdev->dev, "error: have no bar mapping\n"); - return; - } - for (i = 0; i < sdev->info_window->num_windows; i++) { elem = &sdev->info_window->window[i]; @@ -400,64 +393,53 @@ static void sof_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = window_offset + elem->offset; inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = window_offset + elem->offset; outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - window_offset + - elem->offset, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + window_offset + elem->offset, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DEBUG: debug_offset = window_offset + elem->offset; debug_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - window_offset + - elem->offset, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + window_offset + elem->offset, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_STREAM: stream_offset = window_offset + elem->offset; stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - window_offset + - elem->offset, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + window_offset + elem->offset, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = window_offset + elem->offset; - snd_sof_debugfs_io_item(sdev, - sdev->bar[bar] + - window_offset + - elem->offset, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); + snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM, + window_offset + elem->offset, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); @@ -470,8 +452,12 @@ static void sof_get_windows(struct snd_sof_dev *sdev) return; } - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); + sdev->dsp_box.offset = inbox_offset; + sdev->dsp_box.size = inbox_size; + + sdev->host_box.offset = outbox_offset; + sdev->host_box.size = outbox_size; + sdev->stream_box.offset = stream_offset; sdev->stream_box.size = stream_size; @@ -493,7 +479,6 @@ int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; int offset; - int bar; int ret; /* mailbox must be on 4k boundary */ @@ -503,12 +488,6 @@ int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return offset; } - bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); - if (bar < 0) { - dev_err(sdev->dev, "error: have no bar mapping\n"); - return -EINVAL; - } - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", msg_id, offset); @@ -516,8 +495,17 @@ int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) if (!sdev->first_boot) return 0; - /* copy data from the DSP FW ready offset */ - snd_sof_dsp_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); + /* + * copy data from the DSP FW ready offset + * Subsequent error handling is not needed for BLK_TYPE_SRAM + */ + ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready, + sizeof(*fw_ready)); + if (ret) { + dev_err(sdev->dev, + "error: unable to read fw_ready, read from TYPE_SRAM failed\n"); + return ret; + } /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); @@ -525,8 +513,7 @@ int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, bar, offset + - sizeof(struct sof_ipc_fw_ready)); + snd_sof_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready)); sof_get_windows(sdev); @@ -539,7 +526,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) { struct snd_sof_blk_hdr *block; - int count, bar; + int count, ret; u32 offset; size_t remaining; @@ -576,13 +563,6 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, case SOF_FW_BLK_TYPE_DRAM: case SOF_FW_BLK_TYPE_SRAM: offset = block->offset; - bar = snd_sof_dsp_get_bar_index(sdev, block->type); - if (bar < 0) { - dev_err(sdev->dev, - "error: no BAR mapping for block type 0x%x\n", - block->type); - return bar; - } break; default: dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", @@ -600,8 +580,13 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, bar, offset, - block + 1, block->size); + ret = snd_sof_dsp_block_write(sdev, block->type, offset, + block + 1, block->size); + if (ret < 0) { + dev_err(sdev->dev, "error: write to block type 0x%x failed\n", + block->type); + return ret; + } if (remaining < block->size) { dev_err(sdev->dev, "error: not enough data remaining\n"); @@ -800,16 +785,6 @@ error: } EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); -int snd_sof_load_firmware(struct snd_sof_dev *sdev) -{ - dev_dbg(sdev->dev, "loading firmware\n"); - - if (sof_ops(sdev)->load_firmware) - return sof_ops(sdev)->load_firmware(sdev); - return 0; -} -EXPORT_SYMBOL(snd_sof_load_firmware); - int snd_sof_run_firmware(struct snd_sof_dev *sdev) { int ret; diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 4a5d6e497f05be..a93aa5b943b217 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -253,6 +253,17 @@ static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev) sof_ops(sdev)->ipc_dump(sdev); } +static inline int snd_sof_debugfs_add_region_item(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size, + const char *name, enum sof_debugfs_access_type access_type) +{ + if (sof_ops(sdev) && sof_ops(sdev)->debugfs_add_region_item) + return sof_ops(sdev)->debugfs_add_region_item(sdev, blk_type, offset, + size, name, access_type); + + return 0; +} + /* register IO */ static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 value) @@ -297,16 +308,18 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, } /* block IO */ -static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, - u32 offset, void *dest, size_t bytes) +static inline int snd_sof_dsp_block_read(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t bytes) { - sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); + return sof_ops(sdev)->block_read(sdev, blk_type, offset, dest, bytes); } -static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, - u32 offset, void *src, size_t bytes) +static inline int snd_sof_dsp_block_write(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t bytes) { - sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); + return sof_ops(sdev)->block_write(sdev, blk_type, offset, src, bytes); } /* ipc */ @@ -400,12 +413,20 @@ snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, return 0; } +/* Firmware loading */ +static inline int snd_sof_load_firmware(struct snd_sof_dev *sdev) +{ + dev_dbg(sdev->dev, "loading firmware\n"); + + return sof_ops(sdev)->load_firmware(sdev); +} + /* host DSP message data */ -static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz) +static inline int snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) { - sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); + return sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); } /* host configure DSP HW parameters */ @@ -503,21 +524,6 @@ snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach, sof_ops(sdev)->set_mach_params(mach, sdev); } -static inline const struct snd_sof_dsp_ops -*sof_get_ops(const struct sof_dev_desc *d, - const struct sof_ops_table mach_ops[], int asize) -{ - int i; - - for (i = 0; i < asize; i++) { - if (d == mach_ops[i].desc) - return mach_ops[i].ops; - } - - /* not found */ - return NULL; -} - /** * snd_sof_dsp_register_poll_timeout - Periodically poll an address * until a condition is met or a timeout occurs diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9893b182da4334..b4280459e5db27 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -17,7 +17,7 @@ #include "sof-audio.h" #include "ops.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) -#include "compress.h" +#include "sof-probes.h" #endif /* Create DMA buffer page table for DSP */ @@ -829,11 +829,7 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->trigger = sof_pcm_trigger; pd->pointer = sof_pcm_pointer; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) - pd->compress_ops = &sof_compressed_ops; -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) - /* override cops when probe support is enabled */ pd->compress_ops = &sof_probe_compressed_ops; #endif pd->pcm_construct = sof_pcm_new; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index c83fb62559616c..89b4b3d765391f 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -191,7 +191,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) goto suspend; - /* set restore_stream for all streams during system suspend */ + /* prepare for streams to be resumed properly upon resume */ if (!runtime_suspend) { ret = sof_set_hw_params_upon_resume(sdev->dev); if (ret < 0) { diff --git a/sound/soc/sof/probe.h b/sound/soc/sof/probe.h deleted file mode 100644 index 5e159ab239fa97..00000000000000 --- a/sound/soc/sof/probe.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2019-2020 Intel Corporation. All rights reserved. - * - * Author: Cezary Rojewski <cezary.rojewski@intel.com> - */ - -#ifndef __SOF_PROBE_H -#define __SOF_PROBE_H - -#include <sound/sof/header.h> - -struct snd_sof_dev; - -#define SOF_PROBE_INVALID_NODE_ID UINT_MAX - -struct sof_probe_dma { - unsigned int stream_tag; - unsigned int dma_buffer_size; -} __packed; - -enum sof_connection_purpose { - SOF_CONNECTION_PURPOSE_EXTRACT = 1, - SOF_CONNECTION_PURPOSE_INJECT, -}; - -struct sof_probe_point_desc { - unsigned int buffer_id; - unsigned int purpose; - unsigned int stream_tag; -} __packed; - -struct sof_ipc_probe_dma_add_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - struct sof_probe_dma dma[]; -} __packed; - -struct sof_ipc_probe_info_params { - struct sof_ipc_reply rhdr; - unsigned int num_elems; - union { - struct sof_probe_dma dma[0]; - struct sof_probe_point_desc desc[0]; - }; -} __packed; - -struct sof_ipc_probe_dma_remove_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - unsigned int stream_tag[]; -} __packed; - -struct sof_ipc_probe_point_add_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - struct sof_probe_point_desc desc[]; -} __packed; - -struct sof_ipc_probe_point_remove_params { - struct sof_ipc_cmd_hdr hdr; - unsigned int num_elems; - unsigned int buffer_id[]; -} __packed; - -int sof_ipc_probe_init(struct snd_sof_dev *sdev, - u32 stream_tag, size_t buffer_size); -int sof_ipc_probe_deinit(struct snd_sof_dev *sdev); -int sof_ipc_probe_dma_info(struct snd_sof_dev *sdev, - struct sof_probe_dma **dma, size_t *num_dma); -int sof_ipc_probe_dma_add(struct snd_sof_dev *sdev, - struct sof_probe_dma *dma, size_t num_dma); -int sof_ipc_probe_dma_remove(struct snd_sof_dev *sdev, - unsigned int *stream_tag, size_t num_stream_tag); -int sof_ipc_probe_points_info(struct snd_sof_dev *sdev, - struct sof_probe_point_desc **desc, size_t *num_desc); -int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, - struct sof_probe_point_desc *desc, size_t num_desc); -int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, - unsigned int *buffer_id, size_t num_buffer_id); - -#endif diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index dc274e63ed9a07..9a8d005e75a074 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -75,6 +75,9 @@ struct snd_sof_control { struct list_head list; /* list in sdev control list */ struct snd_sof_led_control led_ctl; + + /* if true, the control's data needs to be updated from Firmware */ + bool comp_data_dirty; }; /* ASoC SOF DAPM widget */ @@ -148,6 +151,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, unsigned int size); int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, unsigned int size); +void snd_sof_control_notify(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata); /* * Topology. diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index d1a21edfa05d07..f0f819a4645610 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -11,10 +11,7 @@ #include <sound/sof.h> #include "ops.h" - -extern struct snd_sof_dsp_ops sof_imx8_ops; -extern struct snd_sof_dsp_ops sof_imx8x_ops; -extern struct snd_sof_dsp_ops sof_imx8m_ops; +#include "imx/imx-ops.h" /* platform specific devices */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index fd8423172d8f34..a6ded5bd067475 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -83,6 +83,16 @@ enum sof_system_suspend_state { SOF_SUSPEND_S3, }; +enum sof_dfsentry_type { + SOF_DFSENTRY_TYPE_IOMEM = 0, + SOF_DFSENTRY_TYPE_BUF, +}; + +enum sof_debugfs_access_type { + SOF_DEBUGFS_ACCESS_ALWAYS = 0, + SOF_DEBUGFS_ACCESS_D0_ONLY, +}; + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; @@ -127,12 +137,12 @@ struct snd_sof_dsp_ops { void __iomem *addr); /* optional */ /* memcpy IO */ - void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, - u32 offset, void *dest, - size_t size); /* mandatory */ - void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, - u32 offset, void *src, - size_t size); /* mandatory */ + int (*block_read)(struct snd_sof_dev *sof_dev, + enum snd_sof_fw_blk_type type, u32 offset, + void *dest, size_t size); /* mandatory */ + int (*block_write)(struct snd_sof_dev *sof_dev, + enum snd_sof_fw_blk_type type, u32 offset, + void *src, size_t size); /* mandatory */ /* doorbell */ irqreturn_t (*irq_handler)(int irq, void *context); /* optional */ @@ -200,9 +210,9 @@ struct snd_sof_dsp_ops { #endif /* host read DSP stream data */ - void (*ipc_msg_data)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz); /* mandatory */ + int (*ipc_msg_data)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); /* mandatory */ /* host configure DSP HW parameters */ int (*ipc_pcm_params)(struct snd_sof_dev *sdev, @@ -237,6 +247,10 @@ struct snd_sof_dsp_ops { void (*dbg_dump)(struct snd_sof_dev *sof_dev, u32 flags); /* optional */ void (*ipc_dump)(struct snd_sof_dev *sof_dev); /* optional */ + int (*debugfs_add_region_item)(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, u32 offset, + size_t size, const char *name, + enum sof_debugfs_access_type access_type); /* optional */ /* host DMA trace initialization */ int (*trace_init)(struct snd_sof_dev *sdev, @@ -268,33 +282,17 @@ struct snd_sof_dsp_ops { /* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */ u32 hw_info; - const struct sof_arch_ops *arch_ops; + const struct dsp_arch_ops *dsp_arch_ops; }; /* DSP architecture specific callbacks for oops and stack dumps */ -struct sof_arch_ops { +struct dsp_arch_ops { void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops); void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words); }; -#define sof_arch_ops(sdev) ((sdev)->pdata->desc->ops->arch_ops) - -/* DSP device HW descriptor mapping between bus ID and ops */ -struct sof_ops_table { - const struct sof_dev_desc *desc; - const struct snd_sof_dsp_ops *ops; -}; - -enum sof_dfsentry_type { - SOF_DFSENTRY_TYPE_IOMEM = 0, - SOF_DFSENTRY_TYPE_BUF, -}; - -enum sof_debugfs_access_type { - SOF_DEBUGFS_ACCESS_ALWAYS = 0, - SOF_DEBUGFS_ACCESS_D0_ONLY, -}; +#define sof_dsp_arch_ops(sdev) ((sdev)->pdata->desc->ops->dsp_arch_ops) /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { @@ -485,14 +483,12 @@ int snd_sof_create_page_table(struct device *dev, /* * Firmware loading. */ -int snd_sof_load_firmware(struct snd_sof_dev *sdev); int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev); int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev); int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); void snd_sof_fw_unload(struct snd_sof_dev *sdev); -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset); /* * IPC low level APIs. @@ -503,9 +499,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, struct sof_ipc_pcm_params *params); -int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, - size_t dspbox_size, u32 hostbox, - size_t hostbox_size); int snd_sof_ipc_valid(struct snd_sof_dev *sdev); int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, @@ -522,10 +515,6 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev); void snd_sof_free_trace(struct snd_sof_dev *sdev); int snd_sof_dbg_init(struct snd_sof_dev *sdev); void snd_sof_free_debug(struct snd_sof_dev *sdev); -int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name, - enum sof_debugfs_access_type access_type); int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, void *base, size_t size, const char *name, mode_t mode); @@ -539,11 +528,9 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); - -/* - * Platform specific ops. - */ -extern struct snd_compress_ops sof_compressed_ops; +int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, + enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size, + const char *name, enum sof_debugfs_access_type access_type); /* * DSP Architectures. @@ -551,16 +538,16 @@ extern struct snd_compress_ops sof_compressed_ops; static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words) { - sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); + sof_dsp_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); } static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) { - if (sof_arch_ops(sdev)->dsp_oops) - sof_arch_ops(sdev)->dsp_oops(sdev, oops); + if (sof_dsp_arch_ops(sdev)->dsp_oops) + sof_dsp_arch_ops(sdev)->dsp_oops(sdev, oops); } -extern const struct sof_arch_ops sof_xtensa_arch_ops; +extern const struct dsp_arch_ops sof_xtensa_arch_ops; /* * Utilities @@ -573,16 +560,16 @@ void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); -void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, - size_t size); -void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, - size_t size); +int sof_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size); +int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size); int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); -void intel_ipc_msg_data(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - void *p, size_t sz); +int intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); int intel_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, const struct sof_ipc_pcm_params_reply *reply); diff --git a/sound/soc/sof/probe.c b/sound/soc/sof/sof-probes.c index 14509f4d3f8644..5586af9f1a251c 100644 --- a/sound/soc/sof/probe.c +++ b/sound/soc/sof/sof-probes.c @@ -3,13 +3,46 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2019-2020 Intel Corporation. All rights reserved. -// +// Copyright(c) 2019-2021 Intel Corporation. All rights reserved. // Author: Cezary Rojewski <cezary.rojewski@intel.com> // +#include <sound/soc.h> +#include "ops.h" #include "sof-priv.h" -#include "probe.h" +#include "sof-probes.h" + +struct sof_probe_dma { + unsigned int stream_tag; + unsigned int dma_buffer_size; +} __packed; + +struct sof_ipc_probe_dma_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_dma dma[]; +} __packed; + +struct sof_ipc_probe_info_params { + struct sof_ipc_reply rhdr; + unsigned int num_elems; + union { + struct sof_probe_dma dma[0]; + struct sof_probe_point_desc desc[0]; + }; +} __packed; + +struct sof_ipc_probe_point_add_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + struct sof_probe_point_desc desc[]; +} __packed; + +struct sof_ipc_probe_point_remove_params { + struct sof_ipc_cmd_hdr hdr; + unsigned int num_elems; + unsigned int buffer_id[]; +} __packed; /** * sof_ipc_probe_init - initialize data probing @@ -25,8 +58,8 @@ * Probing is initialized only once and each INIT request must be * matched by DEINIT call. */ -int sof_ipc_probe_init(struct snd_sof_dev *sdev, - u32 stream_tag, size_t buffer_size) +static int sof_ipc_probe_init(struct snd_sof_dev *sdev, u32 stream_tag, + size_t buffer_size) { struct sof_ipc_probe_dma_add_params *msg; struct sof_ipc_reply reply; @@ -47,7 +80,6 @@ int sof_ipc_probe_init(struct snd_sof_dev *sdev, kfree(msg); return ret; } -EXPORT_SYMBOL(sof_ipc_probe_init); /** * sof_ipc_probe_deinit - cleanup after data probing @@ -57,7 +89,7 @@ EXPORT_SYMBOL(sof_ipc_probe_init); * on DSP side once it is no longer needed. DEINIT only when there * are no probes connected and with all injectors detached. */ -int sof_ipc_probe_deinit(struct snd_sof_dev *sdev) +static int sof_ipc_probe_deinit(struct snd_sof_dev *sdev) { struct sof_ipc_cmd_hdr msg; struct sof_ipc_reply reply; @@ -68,10 +100,9 @@ int sof_ipc_probe_deinit(struct snd_sof_dev *sdev) return sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, &reply, sizeof(reply)); } -EXPORT_SYMBOL(sof_ipc_probe_deinit); static int sof_ipc_probe_info(struct snd_sof_dev *sdev, unsigned int cmd, - void **params, size_t *num_params) + void **params, size_t *num_params) { struct sof_ipc_probe_info_params msg = {{{0}}}; struct sof_ipc_probe_info_params *reply; @@ -113,97 +144,6 @@ exit: } /** - * sof_ipc_probe_dma_info - retrieve list of active injection dmas - * @sdev: SOF sound device - * @dma: Returned list of active dmas - * @num_dma: Returned count of active dmas - * - * Host sends DMA_INFO request to obtain list of injection dmas it - * can use to transfer data over with. - * - * Note that list contains only injection dmas as there is only one - * extractor (dma) and it is always assigned on probing init. - * DSP knows exactly where data from extraction probes is going to, - * which is not the case for injection where multiple streams - * could be engaged. - */ -int sof_ipc_probe_dma_info(struct snd_sof_dev *sdev, - struct sof_probe_dma **dma, size_t *num_dma) -{ - return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_DMA_INFO, - (void **)dma, num_dma); -} -EXPORT_SYMBOL(sof_ipc_probe_dma_info); - -/** - * sof_ipc_probe_dma_add - attach to specified dmas - * @sdev: SOF sound device - * @dma: List of streams (dmas) to attach to - * @num_dma: Number of elements in @dma - * - * Contrary to extraction, injection streams are never assigned - * on init. Before attempting any data injection, host is responsible - * for specifying streams which will be later used to transfer data - * to connected probe points. - */ -int sof_ipc_probe_dma_add(struct snd_sof_dev *sdev, - struct sof_probe_dma *dma, size_t num_dma) -{ - struct sof_ipc_probe_dma_add_params *msg; - struct sof_ipc_reply reply; - size_t size = struct_size(msg, dma, num_dma); - int ret; - - msg = kmalloc(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->hdr.size = size; - msg->num_elems = num_dma; - msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_ADD; - memcpy(&msg->dma[0], dma, size - sizeof(*msg)); - - ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, - &reply, sizeof(reply)); - kfree(msg); - return ret; -} -EXPORT_SYMBOL(sof_ipc_probe_dma_add); - -/** - * sof_ipc_probe_dma_remove - detach from specified dmas - * @sdev: SOF sound device - * @stream_tag: List of stream tags to detach from - * @num_stream_tag: Number of elements in @stream_tag - * - * Host sends DMA_REMOVE request to free previously attached stream - * from being occupied for injection. Each detach operation should - * match equivalent DMA_ADD. Detach only when all probes tied to - * given stream have been disconnected. - */ -int sof_ipc_probe_dma_remove(struct snd_sof_dev *sdev, - unsigned int *stream_tag, size_t num_stream_tag) -{ - struct sof_ipc_probe_dma_remove_params *msg; - struct sof_ipc_reply reply; - size_t size = struct_size(msg, stream_tag, num_stream_tag); - int ret; - - msg = kmalloc(size, GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->hdr.size = size; - msg->num_elems = num_stream_tag; - msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DMA_REMOVE; - memcpy(&msg->stream_tag[0], stream_tag, size - sizeof(*msg)); - - ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, - &reply, sizeof(reply)); - kfree(msg); - return ret; -} -EXPORT_SYMBOL(sof_ipc_probe_dma_remove); - -/** * sof_ipc_probe_points_info - retrieve list of active probe points * @sdev: SOF sound device * @desc: Returned list of active probes @@ -214,7 +154,8 @@ EXPORT_SYMBOL(sof_ipc_probe_dma_remove); * required. */ int sof_ipc_probe_points_info(struct snd_sof_dev *sdev, - struct sof_probe_point_desc **desc, size_t *num_desc) + struct sof_probe_point_desc **desc, + size_t *num_desc) { return sof_ipc_probe_info(sdev, SOF_IPC_PROBE_POINT_INFO, (void **)desc, num_desc); @@ -235,7 +176,7 @@ EXPORT_SYMBOL(sof_ipc_probe_points_info); * request when no longer needed. */ int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, - struct sof_probe_point_desc *desc, size_t num_desc) + struct sof_probe_point_desc *desc, size_t num_desc) { struct sof_ipc_probe_point_add_params *msg; struct sof_ipc_reply reply; @@ -267,7 +208,7 @@ EXPORT_SYMBOL(sof_ipc_probe_points_add); * points and frees all resources on DSP side. */ int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, - unsigned int *buffer_id, size_t num_buffer_id) + unsigned int *buffer_id, size_t num_buffer_id) { struct sof_ipc_probe_point_remove_params *msg; struct sof_ipc_reply reply; @@ -288,3 +229,136 @@ int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, return ret; } EXPORT_SYMBOL(sof_ipc_probe_points_remove); + +static int sof_probe_compr_startup(struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + int ret; + + ret = snd_sof_probe_compr_assign(sdev, cstream, dai); + if (ret < 0) { + dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret); + return ret; + } + + sdev->extractor_stream_tag = ret; + return 0; +} + +static int sof_probe_compr_shutdown(struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct sof_probe_point_desc *desc; + size_t num_desc; + int i, ret; + + /* disconnect all probe points */ + ret = sof_ipc_probe_points_info(sdev, &desc, &num_desc); + if (ret < 0) { + dev_err(dai->dev, "Failed to get probe points: %d\n", ret); + goto exit; + } + + for (i = 0; i < num_desc; i++) + sof_ipc_probe_points_remove(sdev, &desc[i].buffer_id, 1); + kfree(desc); + +exit: + ret = sof_ipc_probe_deinit(sdev); + if (ret < 0) + dev_err(dai->dev, "Failed to deinit probe: %d\n", ret); + + sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; + snd_compr_free_pages(cstream); + + return snd_sof_probe_compr_free(sdev, cstream, dai); +} + +static int sof_probe_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + struct snd_compr_runtime *rtd = cstream->runtime; + int ret; + + cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; + cstream->dma_buffer.dev.dev = sdev->dev; + ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); + if (ret < 0) + return ret; + + ret = snd_sof_probe_compr_set_params(sdev, cstream, params, dai); + if (ret < 0) + return ret; + + ret = sof_ipc_probe_init(sdev, sdev->extractor_stream_tag, + rtd->dma_bytes); + if (ret < 0) { + dev_err(dai->dev, "Failed to init probe: %d\n", ret); + return ret; + } + + return 0; +} + +static int sof_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + + return snd_sof_probe_compr_trigger(sdev, cstream, cmd, dai); +} + +static int sof_probe_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); + + return snd_sof_probe_compr_pointer(sdev, cstream, tstamp, dai); +} + +struct snd_soc_cdai_ops sof_probe_compr_ops = { + .startup = sof_probe_compr_startup, + .shutdown = sof_probe_compr_shutdown, + .set_params = sof_probe_compr_set_params, + .trigger = sof_probe_compr_trigger, + .pointer = sof_probe_compr_pointer, +}; +EXPORT_SYMBOL(sof_probe_compr_ops); + +static int sof_probe_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_compr_runtime *rtd = cstream->runtime; + unsigned int offset, n; + void *ptr; + int ret; + + if (count > rtd->buffer_size) + count = rtd->buffer_size; + + div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); + ptr = rtd->dma_area + offset; + n = rtd->buffer_size - offset; + + if (count < n) { + ret = copy_to_user(buf, ptr, count); + } else { + ret = copy_to_user(buf, ptr, n); + ret += copy_to_user(buf + n, rtd->dma_area, count - n); + } + + if (ret) + return count - ret; + return count; +} + +const struct snd_compress_ops sof_probe_compressed_ops = { + .copy = sof_probe_compr_copy, +}; +EXPORT_SYMBOL(sof_probe_compressed_ops); diff --git a/sound/soc/sof/sof-probes.h b/sound/soc/sof/sof-probes.h new file mode 100644 index 00000000000000..35e1dd8d9e0383 --- /dev/null +++ b/sound/soc/sof/sof-probes.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019-2021 Intel Corporation. All rights reserved. + * Author: Cezary Rojewski <cezary.rojewski@intel.com> + */ + +#ifndef __SOF_PROBES_H +#define __SOF_PROBES_H + +#include <sound/compress_driver.h> +#include <sound/sof/header.h> + +struct snd_sof_dev; + +#define SOF_PROBE_INVALID_NODE_ID UINT_MAX + +struct sof_probe_point_desc { + unsigned int buffer_id; + unsigned int purpose; + unsigned int stream_tag; +} __packed; + +int sof_ipc_probe_points_info(struct snd_sof_dev *sdev, + struct sof_probe_point_desc **desc, + size_t *num_desc); +int sof_ipc_probe_points_add(struct snd_sof_dev *sdev, + struct sof_probe_point_desc *desc, + size_t num_desc); +int sof_ipc_probe_points_remove(struct snd_sof_dev *sdev, + unsigned int *buffer_id, size_t num_buffer_id); + +extern struct snd_soc_cdai_ops sof_probe_compr_ops; +extern const struct snd_compress_ops sof_probe_compressed_ops; + +#endif diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 58f6ca5cf491a6..e3afc3dac7d17a 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -417,7 +417,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) "error: fail in snd_sof_dma_trace_init %d\n", ret); return ret; } - dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag); + dev_dbg(sdev->dev, "%s: stream_tag: %d\n", __func__, params.stream_tag); /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, @@ -480,7 +480,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) goto table_err; sdev->dma_trace_pages = ret; - dev_dbg(sdev->dev, "dma_trace_pages: %d\n", sdev->dma_trace_pages); + dev_dbg(sdev->dev, "%s: dma_trace_pages: %d\n", + __func__, sdev->dma_trace_pages); if (sdev->first_boot) { ret = trace_debugfs_create(sdev); diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 5539d3afbe8f5c..66fa6602fb67a3 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -14,6 +14,7 @@ #include <sound/soc.h> #include <sound/sof.h> #include "sof-priv.h" +#include "ops.h" /* * Register IO @@ -72,15 +73,21 @@ EXPORT_SYMBOL(sof_mailbox_read); * Memory copy. */ -void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, - size_t size) +int sof_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *src, size_t size) { - void __iomem *dest = sdev->bar[bar] + offset; + int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); const u8 *src_byte = src; + void __iomem *dest; u32 affected_mask; u32 tmp; int m, n; + if (bar < 0) + return bar; + + dest = sdev->bar[bar] + offset; + m = size / 4; n = size % 4; @@ -100,15 +107,22 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, tmp |= *(u32 *)(src_byte + m * 4) & affected_mask; iowrite32(tmp, dest + m * 4); } + + return 0; } EXPORT_SYMBOL(sof_block_write); -void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, - size_t size) +int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size) { - void __iomem *src = sdev->bar[bar] + offset; + int bar = snd_sof_dsp_get_bar_index(sdev, blk_type); + + if (bar < 0) + return bar; + + memcpy_fromio(dest, sdev->bar[bar] + offset, size); - memcpy_fromio(dest, src, size); + return 0; } EXPORT_SYMBOL(sof_block_read); diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index f6e3411b33cf12..bd09c3825caffa 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -128,7 +128,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, } } -const struct sof_arch_ops sof_xtensa_arch_ops = { +const struct dsp_arch_ops sof_xtensa_arch_ops = { .dsp_oops = xtensa_dsp_oops, .dsp_stack = xtensa_stack, }; diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 83c87f35a7d3cf..cd454871d65423 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -108,6 +108,54 @@ config SND_SOC_TEGRA210_ADMAIF channel. Buffer size is configurable for each ADMAIIF channel. Say Y or M if you want to add support for Tegra210 ADMAIF module. +config SND_SOC_TEGRA210_MVC + tristate "Tegra210 MVC module" + help + Config to enable the digital Master Volume Controller (MVC) which + provides gain or attenuation to a digital signal path. It can be + used in input or output signal path. It can be used either for + per-stream volume control or for master volume control. + Say Y or M if you want to add support for Tegra210 MVC module. + +config SND_SOC_TEGRA210_SFC + tristate "Tegra210 SFC module" + help + Config to enable the Sampling Frequency Converter (SFC) which + converts the sampling frequency of input signal to another + frequency. It supports sampling frequency conversion of streams + upto 2 channels (stereo). + Say Y or M if you want to add support for Tegra210 SFC module. + +config SND_SOC_TEGRA210_AMX + tristate "Tegra210 AMX module" + help + Config to enable the Audio Multiplexer (AMX) which can multiplex + four input streams (each of up to 16 channels) and generate + output stream (of up to 16 channels). A byte RAM helps to form an + output frame by any combination of bytes from the input frames. + Say Y or M if you want to add support for Tegra210 AMX module. + +config SND_SOC_TEGRA210_ADX + tristate "Tegra210 ADX module" + help + Config to enable the Audio Demultiplexer (ADX) which takes an + input stream (up to 16 channels) and demultiplexes it into four + output streams (each of up to 16 channels). A byte RAM helps to + form output frames by any combination of bytes from the input + frame. Its design is identical to that of byte RAM in the AMX + except that the data flow direction is reversed. + Say Y or M if you want to add support for Tegra210 ADX module. + +config SND_SOC_TEGRA210_MIXER + tristate "Tegra210 Mixer module" + help + Config to enable the Mixer module which can help to mix multiple + audio streams. It supports mixing of upto 10 input streams, + where each stream can contain maximum of 8 channels. It supports + 5 output each of which can be a mix of any combination of 10 + input streams. + Say Y or M if you want to add support for Tegra210 Mixer module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index e2cec9ae31c905..f19d56690a0dda 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -13,6 +13,11 @@ snd-soc-tegra210-dmic-objs := tegra210_dmic.o snd-soc-tegra210-i2s-objs := tegra210_i2s.o snd-soc-tegra186-dspk-objs := tegra186_dspk.o snd-soc-tegra210-admaif-objs := tegra210_admaif.o +snd-soc-tegra210-mvc-objs := tegra210_mvc.o +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 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -26,6 +31,11 @@ obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o +obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o +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 # Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c new file mode 100644 index 00000000000000..d7c7849c2f92c9 --- /dev/null +++ b/sound/soc/tegra/tegra210_adx.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_adx.c - Tegra210 ADX driver +// +// Copyright (c) 2021 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_adx.h" +#include "tegra_cif.h" + +static const struct reg_default tegra210_adx_reg_defaults[] = { + { TEGRA210_ADX_RX_INT_MASK, 0x00000001}, + { TEGRA210_ADX_RX_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX_INT_MASK, 0x0000000f }, + { TEGRA210_ADX_TX1_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX2_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX3_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX4_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_CG, 0x1}, + { TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000}, +}; + +static void tegra210_adx_write_map_ram(struct tegra210_adx *adx) +{ + int i; + + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL, + TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_ADX_RAM_DEPTH; i++) + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA, + adx->map[i]); + + regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN0, adx->byte_mask[0]); + regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN1, adx->byte_mask[1]); +} + +static int tegra210_adx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai); + unsigned int val; + int err; + + /* Ensure if ADX status is disabled */ + err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to stop ADX, err = %d\n", err); + return err; + } + + /* + * Soft Reset: Below performs module soft reset which clears + * all FSM logic, flushes flow control of FIFO and resets the + * state register. It also brings module back to disabled + * state (without flushing the data in the pipe). + */ + regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET, + TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK, + TEGRA210_ADX_SOFT_RESET_SOFT_EN); + + err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to reset ADX, err = %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev) +{ + struct tegra210_adx *adx = dev_get_drvdata(dev); + + regcache_cache_only(adx->regmap, true); + regcache_mark_dirty(adx->regmap); + + return 0; +} + +static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev) +{ + struct tegra210_adx *adx = dev_get_drvdata(dev); + + regcache_cache_only(adx->regmap, false); + regcache_sync(adx->regmap); + + tegra210_adx_write_map_ram(adx); + + return 0; +} + +static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, + unsigned int channels, + unsigned int format, + unsigned int reg) +{ + struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai); + struct tegra_cif_conf cif_conf; + int audio_bits; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + if (channels < 1 || channels > 16) + return -EINVAL; + + switch (format) { + case SNDRV_PCM_FORMAT_S8: + audio_bits = TEGRA_ACIF_BITS_8; + break; + 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(adx->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_adx_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_adx_set_audio_cif(dai, params_channels(params), + params_format(params), + TEGRA210_ADX_TX1_CIF_CTRL + ((dai->id - 1) * TEGRA210_ADX_AUDIOCIF_CH_STRIDE)); +} + +static int tegra210_adx_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_adx_set_audio_cif(dai, params_channels(params), + params_format(params), + TEGRA210_ADX_RX_CIF_CTRL); +} + +static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); + struct soc_mixer_control *mc; + unsigned char *bytes_map = (unsigned char *)&adx->map; + int enabled; + + mc = (struct soc_mixer_control *)kcontrol->private_value; + enabled = adx->byte_mask[mc->reg / 32] & (1 << (mc->reg % 32)); + + if (enabled) + ucontrol->value.integer.value[0] = bytes_map[mc->reg]; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); + unsigned char *bytes_map = (unsigned char *)&adx->map; + int value = ucontrol->value.integer.value[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value;; + + if (value >= 0 && value <= 255) { + /* update byte map and enable slot */ + bytes_map[mc->reg] = value; + adx->byte_mask[mc->reg / 32] |= (1 << (mc->reg % 32)); + } else { + /* reset byte map and disable slot */ + bytes_map[mc->reg] = 0; + adx->byte_mask[mc->reg / 32] &= ~(1 << (mc->reg % 32)); + } + + return 1; +} + +static const struct snd_soc_dai_ops tegra210_adx_in_dai_ops = { + .hw_params = tegra210_adx_in_hw_params, + .startup = tegra210_adx_startup, +}; + +static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { + .hw_params = tegra210_adx_out_hw_params, +}; + +#define IN_DAI \ + { \ + .name = "ADX-RX-CIF", \ + .playback = { \ + .stream_name = "RX-CIF-Playback", \ + .channels_min = 1, \ + .channels_max = 16, \ + .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 = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_adx_in_dai_ops, \ + } + +#define OUT_DAI(id) \ + { \ + .name = "ADX-TX" #id "-CIF", \ + .playback = { \ + .stream_name = "TX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 16, \ + .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" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_adx_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_adx_dais[] = { + IN_DAI, + OUT_DAI(1), + OUT_DAI(2), + OUT_DAI(3), + OUT_DAI(4), +}; + +static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE, + TEGRA210_ADX_ENABLE_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0), + SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0), + SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0), +}; + +#define STREAM_ROUTES(id, sname) \ + { "XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX" #id, NULL, "RX" }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } + +#define ADX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +#define STREAM_ROUTES(id, sname) \ + { "XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX" #id, NULL, "RX" }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } + +#define ADX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_adx_routes[] = { + ADX_ROUTES(1), + ADX_ROUTES(2), + ADX_ROUTES(3), + ADX_ROUTES(4), +}; + +#define TEGRA210_ADX_BYTE_MAP_CTRL(reg) \ + SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ + tegra210_adx_get_byte_map, \ + tegra210_adx_put_byte_map) + +static struct snd_kcontrol_new tegra210_adx_controls[] = { + TEGRA210_ADX_BYTE_MAP_CTRL(0), + TEGRA210_ADX_BYTE_MAP_CTRL(1), + TEGRA210_ADX_BYTE_MAP_CTRL(2), + TEGRA210_ADX_BYTE_MAP_CTRL(3), + TEGRA210_ADX_BYTE_MAP_CTRL(4), + TEGRA210_ADX_BYTE_MAP_CTRL(5), + TEGRA210_ADX_BYTE_MAP_CTRL(6), + TEGRA210_ADX_BYTE_MAP_CTRL(7), + TEGRA210_ADX_BYTE_MAP_CTRL(8), + TEGRA210_ADX_BYTE_MAP_CTRL(9), + TEGRA210_ADX_BYTE_MAP_CTRL(10), + TEGRA210_ADX_BYTE_MAP_CTRL(11), + TEGRA210_ADX_BYTE_MAP_CTRL(12), + TEGRA210_ADX_BYTE_MAP_CTRL(13), + TEGRA210_ADX_BYTE_MAP_CTRL(14), + TEGRA210_ADX_BYTE_MAP_CTRL(15), + TEGRA210_ADX_BYTE_MAP_CTRL(16), + TEGRA210_ADX_BYTE_MAP_CTRL(17), + TEGRA210_ADX_BYTE_MAP_CTRL(18), + TEGRA210_ADX_BYTE_MAP_CTRL(19), + TEGRA210_ADX_BYTE_MAP_CTRL(20), + TEGRA210_ADX_BYTE_MAP_CTRL(21), + TEGRA210_ADX_BYTE_MAP_CTRL(22), + TEGRA210_ADX_BYTE_MAP_CTRL(23), + TEGRA210_ADX_BYTE_MAP_CTRL(24), + TEGRA210_ADX_BYTE_MAP_CTRL(25), + TEGRA210_ADX_BYTE_MAP_CTRL(26), + TEGRA210_ADX_BYTE_MAP_CTRL(27), + TEGRA210_ADX_BYTE_MAP_CTRL(28), + TEGRA210_ADX_BYTE_MAP_CTRL(29), + TEGRA210_ADX_BYTE_MAP_CTRL(30), + TEGRA210_ADX_BYTE_MAP_CTRL(31), + TEGRA210_ADX_BYTE_MAP_CTRL(32), + TEGRA210_ADX_BYTE_MAP_CTRL(33), + TEGRA210_ADX_BYTE_MAP_CTRL(34), + TEGRA210_ADX_BYTE_MAP_CTRL(35), + TEGRA210_ADX_BYTE_MAP_CTRL(36), + TEGRA210_ADX_BYTE_MAP_CTRL(37), + TEGRA210_ADX_BYTE_MAP_CTRL(38), + TEGRA210_ADX_BYTE_MAP_CTRL(39), + TEGRA210_ADX_BYTE_MAP_CTRL(40), + TEGRA210_ADX_BYTE_MAP_CTRL(41), + TEGRA210_ADX_BYTE_MAP_CTRL(42), + TEGRA210_ADX_BYTE_MAP_CTRL(43), + TEGRA210_ADX_BYTE_MAP_CTRL(44), + TEGRA210_ADX_BYTE_MAP_CTRL(45), + TEGRA210_ADX_BYTE_MAP_CTRL(46), + TEGRA210_ADX_BYTE_MAP_CTRL(47), + TEGRA210_ADX_BYTE_MAP_CTRL(48), + TEGRA210_ADX_BYTE_MAP_CTRL(49), + TEGRA210_ADX_BYTE_MAP_CTRL(50), + TEGRA210_ADX_BYTE_MAP_CTRL(51), + TEGRA210_ADX_BYTE_MAP_CTRL(52), + TEGRA210_ADX_BYTE_MAP_CTRL(53), + TEGRA210_ADX_BYTE_MAP_CTRL(54), + TEGRA210_ADX_BYTE_MAP_CTRL(55), + TEGRA210_ADX_BYTE_MAP_CTRL(56), + TEGRA210_ADX_BYTE_MAP_CTRL(57), + TEGRA210_ADX_BYTE_MAP_CTRL(58), + TEGRA210_ADX_BYTE_MAP_CTRL(59), + TEGRA210_ADX_BYTE_MAP_CTRL(60), + TEGRA210_ADX_BYTE_MAP_CTRL(61), + TEGRA210_ADX_BYTE_MAP_CTRL(62), + TEGRA210_ADX_BYTE_MAP_CTRL(63), +}; + +static const struct snd_soc_component_driver tegra210_adx_cmpnt = { + .dapm_widgets = tegra210_adx_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), + .dapm_routes = tegra210_adx_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_adx_routes), + .controls = tegra210_adx_controls, + .num_controls = ARRAY_SIZE(tegra210_adx_controls), +}; + +static bool tegra210_adx_wr_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL: + case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL: + case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG: + case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1: + case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_adx_rd_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_adx_volatile_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS: + case TEGRA210_ADX_RX_INT_STATUS: + case TEGRA210_ADX_RX_INT_SET: + case TEGRA210_ADX_TX_STATUS: + case TEGRA210_ADX_TX_INT_STATUS: + case TEGRA210_ADX_TX_INT_SET: + case TEGRA210_ADX_SOFT_RESET: + case TEGRA210_ADX_STATUS: + case TEGRA210_ADX_INT_STATUS: + case TEGRA210_ADX_CFG_RAM_CTRL: + case TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + break; + } + + return false; +} + +static const struct regmap_config tegra210_adx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_ADX_CFG_RAM_DATA, + .writeable_reg = tegra210_adx_wr_reg, + .readable_reg = tegra210_adx_rd_reg, + .volatile_reg = tegra210_adx_volatile_reg, + .reg_defaults = tegra210_adx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_adx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_adx_of_match[] = { + { .compatible = "nvidia,tegra210-adx" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_adx_of_match); + +static int tegra210_adx_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_adx *adx; + void __iomem *regs; + int err; + + adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL); + if (!adx) + return -ENOMEM; + + dev_set_drvdata(dev, adx); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + adx->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_adx_regmap_config); + if (IS_ERR(adx->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(adx->regmap); + } + + regcache_cache_only(adx->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt, + tegra210_adx_dais, + ARRAY_SIZE(tegra210_adx_dais)); + if (err) { + dev_err(dev, "can't register ADX component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_adx_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_adx_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, + tegra210_adx_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_adx_driver = { + .driver = { + .name = "tegra210-adx", + .of_match_table = tegra210_adx_of_match, + .pm = &tegra210_adx_pm_ops, + }, + .probe = tegra210_adx_platform_probe, + .remove = tegra210_adx_platform_remove, +}; +module_platform_driver(tegra210_adx_driver); + +MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 ADX ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_adx.h b/sound/soc/tegra/tegra210_adx.h new file mode 100644 index 00000000000000..d7dcb649797856 --- /dev/null +++ b/sound/soc/tegra/tegra210_adx.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_adx.h - Definitions for Tegra210 ADX driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_ADX_H__ +#define __TEGRA210_ADX_H__ + +/* Register offsets from TEGRA210_ADX*_BASE */ +#define TEGRA210_ADX_RX_STATUS 0x0c +#define TEGRA210_ADX_RX_INT_STATUS 0x10 +#define TEGRA210_ADX_RX_INT_MASK 0x14 +#define TEGRA210_ADX_RX_INT_SET 0x18 +#define TEGRA210_ADX_RX_INT_CLEAR 0x1c +#define TEGRA210_ADX_RX_CIF_CTRL 0x20 +#define TEGRA210_ADX_TX_STATUS 0x4c +#define TEGRA210_ADX_TX_INT_STATUS 0x50 +#define TEGRA210_ADX_TX_INT_MASK 0x54 +#define TEGRA210_ADX_TX_INT_SET 0x58 +#define TEGRA210_ADX_TX_INT_CLEAR 0x5c +#define TEGRA210_ADX_TX1_CIF_CTRL 0x60 +#define TEGRA210_ADX_TX2_CIF_CTRL 0x64 +#define TEGRA210_ADX_TX3_CIF_CTRL 0x68 +#define TEGRA210_ADX_TX4_CIF_CTRL 0x6c +#define TEGRA210_ADX_ENABLE 0x80 +#define TEGRA210_ADX_SOFT_RESET 0x84 +#define TEGRA210_ADX_CG 0x88 +#define TEGRA210_ADX_STATUS 0x8c +#define TEGRA210_ADX_INT_STATUS 0x90 +#define TEGRA210_ADX_CTRL 0xa4 +#define TEGRA210_ADX_IN_BYTE_EN0 0xa8 +#define TEGRA210_ADX_IN_BYTE_EN1 0xac +#define TEGRA210_ADX_CFG_RAM_CTRL 0xb8 +#define TEGRA210_ADX_CFG_RAM_DATA 0xbc + +/* Fields in TEGRA210_ADX_ENABLE */ +#define TEGRA210_ADX_ENABLE_SHIFT 0 + +/* Fields in TEGRA210_ADX_CFG_RAM_CTRL */ +#define TEGRA210_ADX_CFG_RAM_CTRL_RAM_ADDR_SHIFT 0 + +#define TEGRA210_ADX_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_ADX_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +/* Fields in TEGRA210_ADX_SOFT_RESET */ +#define TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT 0 +#define TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK (1 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) +#define TEGRA210_ADX_SOFT_RESET_SOFT_EN (1 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) +#define TEGRA210_ADX_SOFT_RESET_SOFT_DEFAULT (0 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) + +#define TEGRA210_ADX_AUDIOCIF_CH_STRIDE 4 +#define TEGRA210_ADX_RAM_DEPTH 16 +#define TEGRA210_ADX_MAP_STREAM_NUMBER_SHIFT 6 +#define TEGRA210_ADX_MAP_WORD_NUMBER_SHIFT 2 +#define TEGRA210_ADX_MAP_BYTE_NUMBER_SHIFT 0 + +struct tegra210_adx { + struct regmap *regmap; + unsigned int map[TEGRA210_ADX_RAM_DEPTH]; + unsigned int byte_mask[2]; +}; + +#endif diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 66287a7c9865dc..a1989eae2b525a 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -105,14 +105,68 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = { DAI(ADMAIF8), DAI(ADMAIF9), DAI(ADMAIF10), + /* XBAR <-> I2S <-> Codec */ DAI(I2S1), DAI(I2S2), DAI(I2S3), DAI(I2S4), DAI(I2S5), + /* XBAR <- DMIC <- Codec */ DAI(DMIC1), DAI(DMIC2), DAI(DMIC3), + /* XBAR -> SFC -> XBAR */ + DAI(SFC1 RX), + DAI(SFC1 TX), + DAI(SFC2 RX), + DAI(SFC2 TX), + DAI(SFC3 RX), + DAI(SFC3 TX), + DAI(SFC4 RX), + DAI(SFC4 TX), + /* XBAR -> MVC -> XBAR */ + DAI(MVC1 RX), + DAI(MVC1 TX), + DAI(MVC2 RX), + DAI(MVC2 TX), + /* XBAR -> AMX(4:1) -> XBAR */ + DAI(AMX1 RX1), + DAI(AMX1 RX2), + DAI(AMX1 RX3), + DAI(AMX1 RX4), + DAI(AMX1), + DAI(AMX2 RX1), + DAI(AMX2 RX2), + DAI(AMX2 RX3), + DAI(AMX2 RX4), + DAI(AMX2), + /* XBAR -> ADX(1:4) -> XBAR */ + DAI(ADX1), + DAI(ADX1 TX1), + DAI(ADX1 TX2), + DAI(ADX1 TX3), + DAI(ADX1 TX4), + DAI(ADX2), + DAI(ADX2 TX1), + DAI(ADX2 TX2), + DAI(ADX2 TX3), + DAI(ADX2 TX4), + /* XBAR -> MIXER(10:5) -> XBAR */ + DAI(MIXER1 RX1), + DAI(MIXER1 RX2), + DAI(MIXER1 RX3), + DAI(MIXER1 RX4), + DAI(MIXER1 RX5), + DAI(MIXER1 RX6), + DAI(MIXER1 RX7), + DAI(MIXER1 RX8), + DAI(MIXER1 RX9), + DAI(MIXER1 RX10), + DAI(MIXER1 TX1), + DAI(MIXER1 TX2), + DAI(MIXER1 TX3), + DAI(MIXER1 TX4), + DAI(MIXER1 TX5), }; static struct snd_soc_dai_driver tegra186_ahub_dais[] = { @@ -136,18 +190,93 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = { DAI(ADMAIF18), DAI(ADMAIF19), DAI(ADMAIF20), + /* XBAR <-> I2S <-> Codec */ DAI(I2S1), DAI(I2S2), DAI(I2S3), DAI(I2S4), DAI(I2S5), DAI(I2S6), + /* XBAR <- DMIC <- Codec */ DAI(DMIC1), DAI(DMIC2), DAI(DMIC3), DAI(DMIC4), + /* XBAR -> DSPK -> Codec */ DAI(DSPK1), DAI(DSPK2), + /* XBAR -> SFC -> XBAR */ + DAI(SFC1 RX), + DAI(SFC1 TX), + DAI(SFC2 RX), + DAI(SFC2 TX), + DAI(SFC3 RX), + DAI(SFC3 TX), + DAI(SFC4 RX), + DAI(SFC4 TX), + /* XBAR -> MVC -> XBAR */ + DAI(MVC1 RX), + DAI(MVC1 TX), + DAI(MVC2 RX), + DAI(MVC2 TX), + /* XBAR -> AMX(4:1) -> XBAR */ + DAI(AMX1 RX1), + DAI(AMX1 RX2), + DAI(AMX1 RX3), + DAI(AMX1 RX4), + DAI(AMX1), + DAI(AMX2 RX1), + DAI(AMX2 RX2), + DAI(AMX2 RX3), + DAI(AMX2 RX4), + DAI(AMX2), + DAI(AMX3 RX1), + DAI(AMX3 RX2), + DAI(AMX3 RX3), + DAI(AMX3 RX4), + DAI(AMX3), + DAI(AMX4 RX1), + DAI(AMX4 RX2), + DAI(AMX4 RX3), + DAI(AMX4 RX4), + DAI(AMX4), + /* XBAR -> ADX(1:4) -> XBAR */ + DAI(ADX1), + DAI(ADX1 TX1), + DAI(ADX1 TX2), + DAI(ADX1 TX3), + DAI(ADX1 TX4), + DAI(ADX2), + DAI(ADX2 TX1), + DAI(ADX2 TX2), + DAI(ADX2 TX3), + DAI(ADX2 TX4), + DAI(ADX3), + DAI(ADX3 TX1), + DAI(ADX3 TX2), + DAI(ADX3 TX3), + DAI(ADX3 TX4), + DAI(ADX4), + DAI(ADX4 TX1), + DAI(ADX4 TX2), + DAI(ADX4 TX3), + DAI(ADX4 TX4), + /* XBAR -> MIXER1(10:5) -> XBAR */ + DAI(MIXER1 RX1), + DAI(MIXER1 RX2), + DAI(MIXER1 RX3), + DAI(MIXER1 RX4), + DAI(MIXER1 RX5), + DAI(MIXER1 RX6), + DAI(MIXER1 RX7), + DAI(MIXER1 RX8), + DAI(MIXER1 RX9), + DAI(MIXER1 RX10), + DAI(MIXER1 TX1), + DAI(MIXER1 TX2), + DAI(MIXER1 TX3), + DAI(MIXER1 TX4), + DAI(MIXER1 TX5), }; static const char * const tegra210_ahub_mux_texts[] = { @@ -170,6 +299,27 @@ static const char * const tegra210_ahub_mux_texts[] = { "DMIC1", "DMIC2", "DMIC3", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MVC1", + "MVC2", + "AMX1", + "AMX2", + "ADX1 TX1", + "ADX1 TX2", + "ADX1 TX3", + "ADX1 TX4", + "ADX2 TX1", + "ADX2 TX2", + "ADX2 TX3", + "ADX2 TX4", + "MIXER1 TX1", + "MIXER1 TX2", + "MIXER1 TX3", + "MIXER1 TX4", + "MIXER1 TX5", }; static const char * const tegra186_ahub_mux_texts[] = { @@ -204,10 +354,42 @@ static const char * const tegra186_ahub_mux_texts[] = { "DMIC2", "DMIC3", "DMIC4", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MVC1", + "MVC2", + "AMX1", + "AMX2", + "AMX3", + "AMX4", + "ADX1 TX1", + "ADX1 TX2", + "ADX1 TX3", + "ADX1 TX4", + "ADX2 TX1", + "ADX2 TX2", + "ADX2 TX3", + "ADX2 TX4", + "ADX3 TX1", + "ADX3 TX2", + "ADX3 TX3", + "ADX3 TX4", + "ADX4 TX1", + "ADX4 TX2", + "ADX4 TX3", + "ADX4 TX4", + "MIXER1 TX1", + "MIXER1 TX2", + "MIXER1 TX3", + "MIXER1 TX4", + "MIXER1 TX5", }; static const unsigned int tegra210_ahub_mux_values[] = { 0, + /* ADMAIF */ MUX_VALUE(0, 0), MUX_VALUE(0, 1), MUX_VALUE(0, 2), @@ -218,18 +400,47 @@ static const unsigned int tegra210_ahub_mux_values[] = { MUX_VALUE(0, 7), MUX_VALUE(0, 8), MUX_VALUE(0, 9), + /* I2S */ MUX_VALUE(0, 16), MUX_VALUE(0, 17), MUX_VALUE(0, 18), MUX_VALUE(0, 19), MUX_VALUE(0, 20), + /* DMIC */ MUX_VALUE(2, 18), MUX_VALUE(2, 19), MUX_VALUE(2, 20), + /* SFC */ + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + /* MVC */ + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + /* AMX */ + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + /* ADX */ + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + /* MIXER */ + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), }; static const unsigned int tegra186_ahub_mux_values[] = { 0, + /* ADMAIF */ MUX_VALUE(0, 0), MUX_VALUE(0, 1), MUX_VALUE(0, 2), @@ -246,20 +457,59 @@ static const unsigned int tegra186_ahub_mux_values[] = { MUX_VALUE(0, 13), MUX_VALUE(0, 14), MUX_VALUE(0, 15), + /* I2S */ MUX_VALUE(0, 16), MUX_VALUE(0, 17), MUX_VALUE(0, 18), MUX_VALUE(0, 19), MUX_VALUE(0, 20), MUX_VALUE(0, 21), + /* ADMAIF */ MUX_VALUE(3, 16), MUX_VALUE(3, 17), MUX_VALUE(3, 18), MUX_VALUE(3, 19), + /* DMIC */ MUX_VALUE(2, 18), MUX_VALUE(2, 19), MUX_VALUE(2, 20), MUX_VALUE(2, 21), + /* SFC */ + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + /* MVC */ + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + /* AMX */ + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + MUX_VALUE(1, 10), + MUX_VALUE(1, 11), + /* ADX */ + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + MUX_VALUE(3, 0), + MUX_VALUE(3, 1), + MUX_VALUE(3, 2), + MUX_VALUE(3, 3), + MUX_VALUE(3, 4), + MUX_VALUE(3, 5), + MUX_VALUE(3, 6), + MUX_VALUE(3, 7), + /* MIXER */ + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), }; /* Controls for t210 */ @@ -278,6 +528,32 @@ MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11); MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12); MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13); MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14); +MUX_ENUM_CTRL_DECL(t210_sfc1_tx, 0x18); +MUX_ENUM_CTRL_DECL(t210_sfc2_tx, 0x19); +MUX_ENUM_CTRL_DECL(t210_sfc3_tx, 0x1a); +MUX_ENUM_CTRL_DECL(t210_sfc4_tx, 0x1b); +MUX_ENUM_CTRL_DECL(t210_mvc1_tx, 0x48); +MUX_ENUM_CTRL_DECL(t210_mvc2_tx, 0x49); +MUX_ENUM_CTRL_DECL(t210_amx11_tx, 0x50); +MUX_ENUM_CTRL_DECL(t210_amx12_tx, 0x51); +MUX_ENUM_CTRL_DECL(t210_amx13_tx, 0x52); +MUX_ENUM_CTRL_DECL(t210_amx14_tx, 0x53); +MUX_ENUM_CTRL_DECL(t210_amx21_tx, 0x54); +MUX_ENUM_CTRL_DECL(t210_amx22_tx, 0x55); +MUX_ENUM_CTRL_DECL(t210_amx23_tx, 0x56); +MUX_ENUM_CTRL_DECL(t210_amx24_tx, 0x57); +MUX_ENUM_CTRL_DECL(t210_adx1_tx, 0x58); +MUX_ENUM_CTRL_DECL(t210_adx2_tx, 0x59); +MUX_ENUM_CTRL_DECL(t210_mixer11_tx, 0x20); +MUX_ENUM_CTRL_DECL(t210_mixer12_tx, 0x21); +MUX_ENUM_CTRL_DECL(t210_mixer13_tx, 0x22); +MUX_ENUM_CTRL_DECL(t210_mixer14_tx, 0x23); +MUX_ENUM_CTRL_DECL(t210_mixer15_tx, 0x24); +MUX_ENUM_CTRL_DECL(t210_mixer16_tx, 0x25); +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); /* Controls for t186 */ MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00); @@ -308,6 +584,42 @@ MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68); MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69); MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a); MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b); +MUX_ENUM_CTRL_DECL_186(t186_sfc1_tx, 0x18); +MUX_ENUM_CTRL_DECL_186(t186_sfc2_tx, 0x19); +MUX_ENUM_CTRL_DECL_186(t186_sfc3_tx, 0x1a); +MUX_ENUM_CTRL_DECL_186(t186_sfc4_tx, 0x1b); +MUX_ENUM_CTRL_DECL_186(t186_mvc1_tx, 0x48); +MUX_ENUM_CTRL_DECL_186(t186_mvc2_tx, 0x49); +MUX_ENUM_CTRL_DECL_186(t186_amx11_tx, 0x50); +MUX_ENUM_CTRL_DECL_186(t186_amx12_tx, 0x51); +MUX_ENUM_CTRL_DECL_186(t186_amx13_tx, 0x52); +MUX_ENUM_CTRL_DECL_186(t186_amx14_tx, 0x53); +MUX_ENUM_CTRL_DECL_186(t186_amx21_tx, 0x54); +MUX_ENUM_CTRL_DECL_186(t186_amx22_tx, 0x55); +MUX_ENUM_CTRL_DECL_186(t186_amx23_tx, 0x56); +MUX_ENUM_CTRL_DECL_186(t186_amx24_tx, 0x57); +MUX_ENUM_CTRL_DECL_186(t186_amx31_tx, 0x58); +MUX_ENUM_CTRL_DECL_186(t186_amx32_tx, 0x59); +MUX_ENUM_CTRL_DECL_186(t186_amx33_tx, 0x5a); +MUX_ENUM_CTRL_DECL_186(t186_amx34_tx, 0x5b); +MUX_ENUM_CTRL_DECL_186(t186_amx41_tx, 0x64); +MUX_ENUM_CTRL_DECL_186(t186_amx42_tx, 0x65); +MUX_ENUM_CTRL_DECL_186(t186_amx43_tx, 0x66); +MUX_ENUM_CTRL_DECL_186(t186_amx44_tx, 0x67); +MUX_ENUM_CTRL_DECL_186(t186_adx1_tx, 0x60); +MUX_ENUM_CTRL_DECL_186(t186_adx2_tx, 0x61); +MUX_ENUM_CTRL_DECL_186(t186_adx3_tx, 0x62); +MUX_ENUM_CTRL_DECL_186(t186_adx4_tx, 0x63); +MUX_ENUM_CTRL_DECL_186(t186_mixer11_tx, 0x20); +MUX_ENUM_CTRL_DECL_186(t186_mixer12_tx, 0x21); +MUX_ENUM_CTRL_DECL_186(t186_mixer13_tx, 0x22); +MUX_ENUM_CTRL_DECL_186(t186_mixer14_tx, 0x23); +MUX_ENUM_CTRL_DECL_186(t186_mixer15_tx, 0x24); +MUX_ENUM_CTRL_DECL_186(t186_mixer16_tx, 0x25); +MUX_ENUM_CTRL_DECL_186(t186_mixer17_tx, 0x26); +MUX_ENUM_CTRL_DECL_186(t186_mixer18_tx, 0x27); +MUX_ENUM_CTRL_DECL_186(t186_mixer19_tx, 0x28); +MUX_ENUM_CTRL_DECL_186(t186_mixer110_tx, 0x29); /* * The number of entries in, and order of, this array is closely tied to the @@ -333,6 +645,47 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = { TX_WIDGETS("DMIC1"), TX_WIDGETS("DMIC2"), TX_WIDGETS("DMIC3"), + WIDGETS("SFC1", t210_sfc1_tx), + WIDGETS("SFC2", t210_sfc2_tx), + WIDGETS("SFC3", t210_sfc3_tx), + WIDGETS("SFC4", t210_sfc4_tx), + WIDGETS("MVC1", t210_mvc1_tx), + WIDGETS("MVC2", t210_mvc2_tx), + WIDGETS("AMX1 RX1", t210_amx11_tx), + WIDGETS("AMX1 RX2", t210_amx12_tx), + WIDGETS("AMX1 RX3", t210_amx13_tx), + WIDGETS("AMX1 RX4", t210_amx14_tx), + WIDGETS("AMX2 RX1", t210_amx21_tx), + WIDGETS("AMX2 RX2", t210_amx22_tx), + WIDGETS("AMX2 RX3", t210_amx23_tx), + WIDGETS("AMX2 RX4", t210_amx24_tx), + TX_WIDGETS("AMX1"), + TX_WIDGETS("AMX2"), + WIDGETS("ADX1", t210_adx1_tx), + WIDGETS("ADX2", t210_adx2_tx), + TX_WIDGETS("ADX1 TX1"), + TX_WIDGETS("ADX1 TX2"), + TX_WIDGETS("ADX1 TX3"), + TX_WIDGETS("ADX1 TX4"), + TX_WIDGETS("ADX2 TX1"), + TX_WIDGETS("ADX2 TX2"), + TX_WIDGETS("ADX2 TX3"), + TX_WIDGETS("ADX2 TX4"), + WIDGETS("MIXER1 RX1", t210_mixer11_tx), + WIDGETS("MIXER1 RX2", t210_mixer12_tx), + WIDGETS("MIXER1 RX3", t210_mixer13_tx), + WIDGETS("MIXER1 RX4", t210_mixer14_tx), + WIDGETS("MIXER1 RX5", t210_mixer15_tx), + WIDGETS("MIXER1 RX6", t210_mixer16_tx), + WIDGETS("MIXER1 RX7", t210_mixer17_tx), + WIDGETS("MIXER1 RX8", t210_mixer18_tx), + WIDGETS("MIXER1 RX9", t210_mixer19_tx), + WIDGETS("MIXER1 RX10", t210_mixer110_tx), + TX_WIDGETS("MIXER1 TX1"), + TX_WIDGETS("MIXER1 TX2"), + TX_WIDGETS("MIXER1 TX3"), + TX_WIDGETS("MIXER1 TX4"), + TX_WIDGETS("MIXER1 TX5"), }; static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { @@ -368,6 +721,67 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { TX_WIDGETS("DMIC4"), WIDGETS("DSPK1", t186_dspk1_tx), WIDGETS("DSPK2", t186_dspk2_tx), + WIDGETS("SFC1", t186_sfc1_tx), + WIDGETS("SFC2", t186_sfc2_tx), + WIDGETS("SFC3", t186_sfc3_tx), + WIDGETS("SFC4", t186_sfc4_tx), + WIDGETS("MVC1", t186_mvc1_tx), + WIDGETS("MVC2", t186_mvc2_tx), + WIDGETS("AMX1 RX1", t186_amx11_tx), + WIDGETS("AMX1 RX2", t186_amx12_tx), + WIDGETS("AMX1 RX3", t186_amx13_tx), + WIDGETS("AMX1 RX4", t186_amx14_tx), + WIDGETS("AMX2 RX1", t186_amx21_tx), + WIDGETS("AMX2 RX2", t186_amx22_tx), + WIDGETS("AMX2 RX3", t186_amx23_tx), + WIDGETS("AMX2 RX4", t186_amx24_tx), + WIDGETS("AMX3 RX1", t186_amx31_tx), + WIDGETS("AMX3 RX2", t186_amx32_tx), + WIDGETS("AMX3 RX3", t186_amx33_tx), + WIDGETS("AMX3 RX4", t186_amx34_tx), + WIDGETS("AMX4 RX1", t186_amx41_tx), + WIDGETS("AMX4 RX2", t186_amx42_tx), + WIDGETS("AMX4 RX3", t186_amx43_tx), + WIDGETS("AMX4 RX4", t186_amx44_tx), + TX_WIDGETS("AMX1"), + TX_WIDGETS("AMX2"), + TX_WIDGETS("AMX3"), + TX_WIDGETS("AMX4"), + WIDGETS("ADX1", t186_adx1_tx), + WIDGETS("ADX2", t186_adx2_tx), + WIDGETS("ADX3", t186_adx3_tx), + WIDGETS("ADX4", t186_adx4_tx), + TX_WIDGETS("ADX1 TX1"), + TX_WIDGETS("ADX1 TX2"), + TX_WIDGETS("ADX1 TX3"), + TX_WIDGETS("ADX1 TX4"), + TX_WIDGETS("ADX2 TX1"), + TX_WIDGETS("ADX2 TX2"), + TX_WIDGETS("ADX2 TX3"), + TX_WIDGETS("ADX2 TX4"), + TX_WIDGETS("ADX3 TX1"), + TX_WIDGETS("ADX3 TX2"), + TX_WIDGETS("ADX3 TX3"), + TX_WIDGETS("ADX3 TX4"), + TX_WIDGETS("ADX4 TX1"), + TX_WIDGETS("ADX4 TX2"), + TX_WIDGETS("ADX4 TX3"), + TX_WIDGETS("ADX4 TX4"), + WIDGETS("MIXER1 RX1", t186_mixer11_tx), + WIDGETS("MIXER1 RX2", t186_mixer12_tx), + WIDGETS("MIXER1 RX3", t186_mixer13_tx), + WIDGETS("MIXER1 RX4", t186_mixer14_tx), + WIDGETS("MIXER1 RX5", t186_mixer15_tx), + WIDGETS("MIXER1 RX6", t186_mixer16_tx), + WIDGETS("MIXER1 RX7", t186_mixer17_tx), + WIDGETS("MIXER1 RX8", t186_mixer18_tx), + WIDGETS("MIXER1 RX9", t186_mixer19_tx), + WIDGETS("MIXER1 RX10", t186_mixer110_tx), + TX_WIDGETS("MIXER1 TX1"), + TX_WIDGETS("MIXER1 TX2"), + TX_WIDGETS("MIXER1 TX3"), + TX_WIDGETS("MIXER1 TX4"), + TX_WIDGETS("MIXER1 TX5"), }; #define TEGRA_COMMON_MUX_ROUTES(name) \ @@ -389,7 +803,28 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { { name " Mux", "I2S5", "I2S5 XBAR-RX" }, \ { name " Mux", "DMIC1", "DMIC1 XBAR-RX" }, \ { name " Mux", "DMIC2", "DMIC2 XBAR-RX" }, \ - { name " Mux", "DMIC3", "DMIC3 XBAR-RX" }, + { name " Mux", "DMIC3", "DMIC3 XBAR-RX" }, \ + { name " Mux", "SFC1", "SFC1 XBAR-RX" }, \ + { name " Mux", "SFC2", "SFC2 XBAR-RX" }, \ + { name " Mux", "SFC3", "SFC3 XBAR-RX" }, \ + { name " Mux", "SFC4", "SFC4 XBAR-RX" }, \ + { name " Mux", "MVC1", "MVC1 XBAR-RX" }, \ + { name " Mux", "MVC2", "MVC2 XBAR-RX" }, \ + { name " Mux", "AMX1", "AMX1 XBAR-RX" }, \ + { name " Mux", "AMX2", "AMX2 XBAR-RX" }, \ + { name " Mux", "ADX1 TX1", "ADX1 TX1 XBAR-RX" }, \ + { name " Mux", "ADX1 TX2", "ADX1 TX2 XBAR-RX" }, \ + { name " Mux", "ADX1 TX3", "ADX1 TX3 XBAR-RX" }, \ + { name " Mux", "ADX1 TX4", "ADX1 TX4 XBAR-RX" }, \ + { name " Mux", "ADX2 TX1", "ADX2 TX1 XBAR-RX" }, \ + { name " Mux", "ADX2 TX2", "ADX2 TX2 XBAR-RX" }, \ + { name " Mux", "ADX2 TX3", "ADX2 TX3 XBAR-RX" }, \ + { name " Mux", "ADX2 TX4", "ADX2 TX4 XBAR-RX" }, \ + { name " Mux", "MIXER1 TX1", "MIXER1 TX1 XBAR-RX" }, \ + { 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" }, #define TEGRA186_ONLY_MUX_ROUTES(name) \ { name " Mux", "ADMAIF11", "ADMAIF11 XBAR-RX" }, \ @@ -403,7 +838,17 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { { name " Mux", "ADMAIF19", "ADMAIF19 XBAR-RX" }, \ { name " Mux", "ADMAIF20", "ADMAIF20 XBAR-RX" }, \ { name " Mux", "I2S6", "I2S6 XBAR-RX" }, \ - { name " Mux", "DMIC4", "DMIC4 XBAR-RX" }, + { name " Mux", "DMIC4", "DMIC4 XBAR-RX" }, \ + { name " Mux", "AMX3", "AMX3 XBAR-RX" }, \ + { name " Mux", "AMX4", "AMX4 XBAR-RX" }, \ + { name " Mux", "ADX3 TX1", "ADX3 TX1 XBAR-RX" }, \ + { name " Mux", "ADX3 TX2", "ADX3 TX2 XBAR-RX" }, \ + { name " Mux", "ADX3 TX3", "ADX3 TX3 XBAR-RX" }, \ + { name " Mux", "ADX3 TX4", "ADX3 TX4 XBAR-RX" }, \ + { name " Mux", "ADX4 TX1", "ADX4 TX1 XBAR-RX" }, \ + { name " Mux", "ADX4 TX2", "ADX4 TX2 XBAR-RX" }, \ + { name " Mux", "ADX4 TX3", "ADX4 TX3 XBAR-RX" }, \ + { name " Mux", "ADX4 TX4", "ADX4 TX4 XBAR-RX" }, #define TEGRA210_MUX_ROUTES(name) \ TEGRA_COMMON_MUX_ROUTES(name) @@ -450,6 +895,32 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = { TEGRA210_MUX_ROUTES("I2S3") TEGRA210_MUX_ROUTES("I2S4") TEGRA210_MUX_ROUTES("I2S5") + TEGRA210_MUX_ROUTES("SFC1") + TEGRA210_MUX_ROUTES("SFC2") + TEGRA210_MUX_ROUTES("SFC3") + TEGRA210_MUX_ROUTES("SFC4") + TEGRA210_MUX_ROUTES("MVC1") + TEGRA210_MUX_ROUTES("MVC2") + TEGRA210_MUX_ROUTES("AMX1 RX1") + TEGRA210_MUX_ROUTES("AMX1 RX2") + TEGRA210_MUX_ROUTES("AMX1 RX3") + TEGRA210_MUX_ROUTES("AMX1 RX4") + TEGRA210_MUX_ROUTES("AMX2 RX1") + TEGRA210_MUX_ROUTES("AMX2 RX2") + TEGRA210_MUX_ROUTES("AMX2 RX3") + TEGRA210_MUX_ROUTES("AMX2 RX4") + TEGRA210_MUX_ROUTES("ADX1") + TEGRA210_MUX_ROUTES("ADX2") + TEGRA210_MUX_ROUTES("MIXER1 RX1") + TEGRA210_MUX_ROUTES("MIXER1 RX2") + TEGRA210_MUX_ROUTES("MIXER1 RX3") + TEGRA210_MUX_ROUTES("MIXER1 RX4") + TEGRA210_MUX_ROUTES("MIXER1 RX5") + TEGRA210_MUX_ROUTES("MIXER1 RX6") + TEGRA210_MUX_ROUTES("MIXER1 RX7") + TEGRA210_MUX_ROUTES("MIXER1 RX8") + TEGRA210_MUX_ROUTES("MIXER1 RX9") + TEGRA210_MUX_ROUTES("MIXER1 RX10") }; static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { @@ -501,6 +972,42 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { TEGRA186_MUX_ROUTES("I2S6") TEGRA186_MUX_ROUTES("DSPK1") TEGRA186_MUX_ROUTES("DSPK2") + TEGRA186_MUX_ROUTES("SFC1") + TEGRA186_MUX_ROUTES("SFC2") + TEGRA186_MUX_ROUTES("SFC3") + TEGRA186_MUX_ROUTES("SFC4") + TEGRA186_MUX_ROUTES("MVC1") + TEGRA186_MUX_ROUTES("MVC2") + TEGRA186_MUX_ROUTES("AMX1 RX1") + TEGRA186_MUX_ROUTES("AMX1 RX2") + TEGRA186_MUX_ROUTES("AMX1 RX3") + TEGRA186_MUX_ROUTES("AMX1 RX4") + TEGRA186_MUX_ROUTES("AMX2 RX1") + TEGRA186_MUX_ROUTES("AMX2 RX2") + TEGRA186_MUX_ROUTES("AMX2 RX3") + TEGRA186_MUX_ROUTES("AMX2 RX4") + TEGRA186_MUX_ROUTES("AMX3 RX1") + TEGRA186_MUX_ROUTES("AMX3 RX2") + TEGRA186_MUX_ROUTES("AMX3 RX3") + TEGRA186_MUX_ROUTES("AMX3 RX4") + TEGRA186_MUX_ROUTES("AMX4 RX1") + TEGRA186_MUX_ROUTES("AMX4 RX2") + TEGRA186_MUX_ROUTES("AMX4 RX3") + TEGRA186_MUX_ROUTES("AMX4 RX4") + TEGRA186_MUX_ROUTES("ADX1") + TEGRA186_MUX_ROUTES("ADX2") + TEGRA186_MUX_ROUTES("ADX3") + TEGRA186_MUX_ROUTES("ADX4") + TEGRA186_MUX_ROUTES("MIXER1 RX1") + TEGRA186_MUX_ROUTES("MIXER1 RX2") + TEGRA186_MUX_ROUTES("MIXER1 RX3") + TEGRA186_MUX_ROUTES("MIXER1 RX4") + TEGRA186_MUX_ROUTES("MIXER1 RX5") + TEGRA186_MUX_ROUTES("MIXER1 RX6") + TEGRA186_MUX_ROUTES("MIXER1 RX7") + TEGRA186_MUX_ROUTES("MIXER1 RX8") + TEGRA186_MUX_ROUTES("MIXER1 RX9") + TEGRA186_MUX_ROUTES("MIXER1 RX10") }; static const struct snd_soc_component_driver tegra210_ahub_component = { diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c new file mode 100644 index 00000000000000..af9bddfc312073 --- /dev/null +++ b/sound/soc/tegra/tegra210_amx.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_amx.c - Tegra210 AMX driver +// +// Copyright (c) 2021 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_amx.h" +#include "tegra_cif.h" + +/* + * The counter is in terms of AHUB clock cycles. If a frame is not + * received within these clock cycles, the AMX input channel gets + * automatically disabled. For now the counter is calculated as a + * function of sample rate (8 kHz) and AHUB clock (49.152 MHz). + * If later an accurate number is needed, the counter needs to be + * calculated at runtime. + * + * count = ahub_clk / sample_rate + */ +#define TEGRA194_MAX_FRAME_IDLE_COUNT 0x1800 + +#define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE)) + +static const struct reg_default tegra210_amx_reg_defaults[] = { + { TEGRA210_AMX_RX_INT_MASK, 0x0000000f}, + { TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_TX_INT_MASK, 0x00000001}, + { TEGRA210_AMX_TX_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_CG, 0x1}, + { TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000}, +}; + +static void tegra210_amx_write_map_ram(struct tegra210_amx *amx) +{ + int i; + + regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL, + TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_AMX_RAM_DEPTH; i++) + regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA, + amx->map[i]); + + regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN0, amx->byte_mask[0]); + regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN1, amx->byte_mask[1]); +} + +static int tegra210_amx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + unsigned int val; + int err; + + /* Ensure if AMX is disabled */ + err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val, + !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to stop AMX, err = %d\n", err); + return err; + } + + /* + * Soft Reset: Below performs module soft reset which clears + * all FSM logic, flushes flow control of FIFO and resets the + * state register. It also brings module back to disabled + * state (without flushing the data in the pipe). + */ + regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET, + TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK, + TEGRA210_AMX_SOFT_RESET_SOFT_EN); + + err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to reset AMX, err = %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev) +{ + struct tegra210_amx *amx = dev_get_drvdata(dev); + + regcache_cache_only(amx->regmap, true); + regcache_mark_dirty(amx->regmap); + + return 0; +} + +static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev) +{ + struct tegra210_amx *amx = dev_get_drvdata(dev); + + regcache_cache_only(amx->regmap, false); + regcache_sync(amx->regmap); + + regmap_update_bits(amx->regmap, + TEGRA210_AMX_CTRL, + TEGRA210_AMX_CTRL_RX_DEP_MASK, + TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT); + + tegra210_amx_write_map_ram(amx); + + return 0; +} + +static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + audio_bits = TEGRA_ACIF_BITS_8; + break; + 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(amx->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + + if (amx->soc_data->auto_disable) { + regmap_write(amx->regmap, + AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD), + TEGRA194_MAX_FRAME_IDLE_COUNT); + regmap_write(amx->regmap, TEGRA210_AMX_CYA, 1); + } + + return tegra210_amx_set_audio_cif(dai, params, + AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL)); +} + +static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_amx_set_audio_cif(dai, params, + TEGRA210_AMX_TX_CIF_CTRL); +} + +static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); + unsigned char *bytes_map = (unsigned char *)&amx->map; + int reg = mc->reg; + int enabled; + + if (reg > 31) + enabled = amx->byte_mask[1] & (1 << (reg - 32)); + else + enabled = amx->byte_mask[0] & (1 << reg); + + if (enabled) + ucontrol->value.integer.value[0] = bytes_map[reg]; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int tegra210_amx_put_byte_map(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_amx *amx = snd_soc_component_get_drvdata(cmpnt); + unsigned char *bytes_map = (unsigned char *)&amx->map; + int reg = mc->reg; + int value = ucontrol->value.integer.value[0]; + + if (value >= 0 && value <= 255) { + /* Update byte map and enable slot */ + bytes_map[reg] = value; + if (reg > 31) + amx->byte_mask[1] |= (1 << (reg - 32)); + else + amx->byte_mask[0] |= (1 << reg); + } else { + /* Reset byte map and disable slot */ + bytes_map[reg] = 0; + if (reg > 31) + amx->byte_mask[1] &= ~(1 << (reg - 32)); + else + amx->byte_mask[0] &= ~(1 << reg); + } + + return 1; +} + +static const struct snd_soc_dai_ops tegra210_amx_out_dai_ops = { + .hw_params = tegra210_amx_out_hw_params, + .startup = tegra210_amx_startup, +}; + +static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { + .hw_params = tegra210_amx_in_hw_params, +}; + +#define IN_DAI(id) \ + { \ + .name = "AMX-RX-CIF" #id, \ + .playback = { \ + .stream_name = "RX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 16, \ + .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" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_amx_in_dai_ops, \ + } + +#define OUT_DAI \ + { \ + .name = "AMX-TX-CIF", \ + .playback = { \ + .stream_name = "TX-CIF-Playback", \ + .channels_min = 1, \ + .channels_max = 16, \ + .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 = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_amx_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_amx_dais[] = { + IN_DAI(1), + IN_DAI(2), + IN_DAI(3), + IN_DAI(4), + OUT_DAI, +}; + +static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0), + SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0), + SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0), + SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0), + SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE, + TEGRA210_AMX_ENABLE_SHIFT, 0), +}; + +#define STREAM_ROUTES(id, sname) \ + { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ + { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname },\ + { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \ + { "TX", NULL, "RX" #id }, \ + { "TX-CIF-" sname, NULL, "TX" }, \ + { "XBAR-" sname, NULL, "TX-CIF-" sname }, \ + { "XBAR-RX", NULL, "XBAR-" sname } + +#define AMX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_amx_routes[] = { + AMX_ROUTES(1), + AMX_ROUTES(2), + AMX_ROUTES(3), + AMX_ROUTES(4), +}; + +#define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \ + SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ + tegra210_amx_get_byte_map, \ + tegra210_amx_put_byte_map) + +static struct snd_kcontrol_new tegra210_amx_controls[] = { + TEGRA210_AMX_BYTE_MAP_CTRL(0), + TEGRA210_AMX_BYTE_MAP_CTRL(1), + TEGRA210_AMX_BYTE_MAP_CTRL(2), + TEGRA210_AMX_BYTE_MAP_CTRL(3), + TEGRA210_AMX_BYTE_MAP_CTRL(4), + TEGRA210_AMX_BYTE_MAP_CTRL(5), + TEGRA210_AMX_BYTE_MAP_CTRL(6), + TEGRA210_AMX_BYTE_MAP_CTRL(7), + TEGRA210_AMX_BYTE_MAP_CTRL(8), + TEGRA210_AMX_BYTE_MAP_CTRL(9), + TEGRA210_AMX_BYTE_MAP_CTRL(10), + TEGRA210_AMX_BYTE_MAP_CTRL(11), + TEGRA210_AMX_BYTE_MAP_CTRL(12), + TEGRA210_AMX_BYTE_MAP_CTRL(13), + TEGRA210_AMX_BYTE_MAP_CTRL(14), + TEGRA210_AMX_BYTE_MAP_CTRL(15), + TEGRA210_AMX_BYTE_MAP_CTRL(16), + TEGRA210_AMX_BYTE_MAP_CTRL(17), + TEGRA210_AMX_BYTE_MAP_CTRL(18), + TEGRA210_AMX_BYTE_MAP_CTRL(19), + TEGRA210_AMX_BYTE_MAP_CTRL(20), + TEGRA210_AMX_BYTE_MAP_CTRL(21), + TEGRA210_AMX_BYTE_MAP_CTRL(22), + TEGRA210_AMX_BYTE_MAP_CTRL(23), + TEGRA210_AMX_BYTE_MAP_CTRL(24), + TEGRA210_AMX_BYTE_MAP_CTRL(25), + TEGRA210_AMX_BYTE_MAP_CTRL(26), + TEGRA210_AMX_BYTE_MAP_CTRL(27), + TEGRA210_AMX_BYTE_MAP_CTRL(28), + TEGRA210_AMX_BYTE_MAP_CTRL(29), + TEGRA210_AMX_BYTE_MAP_CTRL(30), + TEGRA210_AMX_BYTE_MAP_CTRL(31), + TEGRA210_AMX_BYTE_MAP_CTRL(32), + TEGRA210_AMX_BYTE_MAP_CTRL(33), + TEGRA210_AMX_BYTE_MAP_CTRL(34), + TEGRA210_AMX_BYTE_MAP_CTRL(35), + TEGRA210_AMX_BYTE_MAP_CTRL(36), + TEGRA210_AMX_BYTE_MAP_CTRL(37), + TEGRA210_AMX_BYTE_MAP_CTRL(38), + TEGRA210_AMX_BYTE_MAP_CTRL(39), + TEGRA210_AMX_BYTE_MAP_CTRL(40), + TEGRA210_AMX_BYTE_MAP_CTRL(41), + TEGRA210_AMX_BYTE_MAP_CTRL(42), + TEGRA210_AMX_BYTE_MAP_CTRL(43), + TEGRA210_AMX_BYTE_MAP_CTRL(44), + TEGRA210_AMX_BYTE_MAP_CTRL(45), + TEGRA210_AMX_BYTE_MAP_CTRL(46), + TEGRA210_AMX_BYTE_MAP_CTRL(47), + TEGRA210_AMX_BYTE_MAP_CTRL(48), + TEGRA210_AMX_BYTE_MAP_CTRL(49), + TEGRA210_AMX_BYTE_MAP_CTRL(50), + TEGRA210_AMX_BYTE_MAP_CTRL(51), + TEGRA210_AMX_BYTE_MAP_CTRL(52), + TEGRA210_AMX_BYTE_MAP_CTRL(53), + TEGRA210_AMX_BYTE_MAP_CTRL(54), + TEGRA210_AMX_BYTE_MAP_CTRL(55), + TEGRA210_AMX_BYTE_MAP_CTRL(56), + TEGRA210_AMX_BYTE_MAP_CTRL(57), + TEGRA210_AMX_BYTE_MAP_CTRL(58), + TEGRA210_AMX_BYTE_MAP_CTRL(59), + TEGRA210_AMX_BYTE_MAP_CTRL(60), + TEGRA210_AMX_BYTE_MAP_CTRL(61), + TEGRA210_AMX_BYTE_MAP_CTRL(62), + TEGRA210_AMX_BYTE_MAP_CTRL(63), +}; + +static const struct snd_soc_component_driver tegra210_amx_cmpnt = { + .dapm_widgets = tegra210_amx_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), + .dapm_routes = tegra210_amx_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes), + .controls = tegra210_amx_controls, + .num_controls = ARRAY_SIZE(tegra210_amx_controls), +}; + +static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL: + case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG: + case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA: + case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: + return true; + default: + return tegra210_amx_wr_reg(dev, reg); + } +} + +static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: + return true; + default: + return tegra210_amx_rd_reg(dev, reg); + } +} + +static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_STATUS: + case TEGRA210_AMX_RX_INT_STATUS: + case TEGRA210_AMX_RX_INT_SET: + case TEGRA210_AMX_TX_STATUS: + case TEGRA210_AMX_TX_INT_STATUS: + case TEGRA210_AMX_TX_INT_SET: + case TEGRA210_AMX_SOFT_RESET: + case TEGRA210_AMX_STATUS: + case TEGRA210_AMX_INT_STATUS: + case TEGRA210_AMX_CFG_RAM_CTRL: + case TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + break; + } + + return false; +} + +static const struct regmap_config tegra210_amx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_AMX_CFG_RAM_DATA, + .writeable_reg = tegra210_amx_wr_reg, + .readable_reg = tegra210_amx_rd_reg, + .volatile_reg = tegra210_amx_volatile_reg, + .reg_defaults = tegra210_amx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config tegra194_amx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA194_AMX_RX4_LAST_FRAME_PERIOD, + .writeable_reg = tegra194_amx_wr_reg, + .readable_reg = tegra194_amx_rd_reg, + .volatile_reg = tegra210_amx_volatile_reg, + .reg_defaults = tegra210_amx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct tegra210_amx_soc_data soc_data_tegra210 = { + .regmap_conf = &tegra210_amx_regmap_config, +}; + +static const struct tegra210_amx_soc_data soc_data_tegra194 = { + .regmap_conf = &tegra194_amx_regmap_config, + .auto_disable = true, +}; + +static const struct of_device_id tegra210_amx_of_match[] = { + { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 }, + { .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_amx_of_match); + +static int tegra210_amx_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_amx *amx; + void __iomem *regs; + int err; + const struct of_device_id *match; + struct tegra210_amx_soc_data *soc_data; + + match = of_match_device(tegra210_amx_of_match, dev); + + soc_data = (struct tegra210_amx_soc_data *)match->data; + + amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL); + if (!amx) + return -ENOMEM; + + amx->soc_data = soc_data; + + dev_set_drvdata(dev, amx); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + amx->regmap = devm_regmap_init_mmio(dev, regs, + soc_data->regmap_conf); + if (IS_ERR(amx->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(amx->regmap); + } + + regcache_cache_only(amx->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt, + tegra210_amx_dais, + ARRAY_SIZE(tegra210_amx_dais)); + if (err) { + dev_err(dev, "can't register AMX component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_amx_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_amx_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, + tegra210_amx_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_amx_driver = { + .driver = { + .name = "tegra210-amx", + .of_match_table = tegra210_amx_of_match, + .pm = &tegra210_amx_pm_ops, + }, + .probe = tegra210_amx_platform_probe, + .remove = tegra210_amx_platform_remove, +}; +module_platform_driver(tegra210_amx_driver); + +MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 AMX ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_amx.h b/sound/soc/tegra/tegra210_amx.h new file mode 100644 index 00000000000000..e277741e4258de --- /dev/null +++ b/sound/soc/tegra/tegra210_amx.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_amx.h - Definitions for Tegra210 AMX driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_AMX_H__ +#define __TEGRA210_AMX_H__ + +/* Register offsets from TEGRA210_AMX*_BASE */ +#define TEGRA210_AMX_RX_STATUS 0x0c +#define TEGRA210_AMX_RX_INT_STATUS 0x10 +#define TEGRA210_AMX_RX_INT_MASK 0x14 +#define TEGRA210_AMX_RX_INT_SET 0x18 +#define TEGRA210_AMX_RX_INT_CLEAR 0x1c +#define TEGRA210_AMX_RX1_CIF_CTRL 0x20 +#define TEGRA210_AMX_RX2_CIF_CTRL 0x24 +#define TEGRA210_AMX_RX3_CIF_CTRL 0x28 +#define TEGRA210_AMX_RX4_CIF_CTRL 0x2c +#define TEGRA210_AMX_TX_STATUS 0x4c +#define TEGRA210_AMX_TX_INT_STATUS 0x50 +#define TEGRA210_AMX_TX_INT_MASK 0x54 +#define TEGRA210_AMX_TX_INT_SET 0x58 +#define TEGRA210_AMX_TX_INT_CLEAR 0x5c +#define TEGRA210_AMX_TX_CIF_CTRL 0x60 +#define TEGRA210_AMX_ENABLE 0x80 +#define TEGRA210_AMX_SOFT_RESET 0x84 +#define TEGRA210_AMX_CG 0x88 +#define TEGRA210_AMX_STATUS 0x8c +#define TEGRA210_AMX_INT_STATUS 0x90 +#define TEGRA210_AMX_CTRL 0xa4 +#define TEGRA210_AMX_OUT_BYTE_EN0 0xa8 +#define TEGRA210_AMX_OUT_BYTE_EN1 0xac +#define TEGRA210_AMX_CYA 0xb0 +#define TEGRA210_AMX_CFG_RAM_CTRL 0xb8 +#define TEGRA210_AMX_CFG_RAM_DATA 0xbc + +#define TEGRA194_AMX_RX1_FRAME_PERIOD 0xc0 +#define TEGRA194_AMX_RX4_FRAME_PERIOD 0xcc +#define TEGRA194_AMX_RX4_LAST_FRAME_PERIOD 0xdc + +/* Fields in TEGRA210_AMX_ENABLE */ +#define TEGRA210_AMX_ENABLE_SHIFT 0 + +/* Fields in TEGRA210_AMX_CTRL */ +#define TEGRA210_AMX_CTRL_MSTR_RX_NUM_SHIFT 14 +#define TEGRA210_AMX_CTRL_MSTR_RX_NUM_MASK (3 << TEGRA210_AMX_CTRL_MSTR_RX_NUM_SHIFT) + +#define TEGRA210_AMX_CTRL_RX_DEP_SHIFT 12 +#define TEGRA210_AMX_CTRL_RX_DEP_MASK (3 << TEGRA210_AMX_CTRL_RX_DEP_SHIFT) + +/* Fields in TEGRA210_AMX_CFG_RAM_CTRL */ +#define TEGRA210_AMX_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_AMX_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_AMX_CFG_CTRL_RAM_ADDR_SHIFT 0 + +/* Fields in TEGRA210_AMX_SOFT_RESET */ +#define TEGRA210_AMX_SOFT_RESET_SOFT_EN 1 +#define TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK TEGRA210_AMX_SOFT_RESET_SOFT_EN + +#define TEGRA210_AMX_AUDIOCIF_CH_STRIDE 4 +#define TEGRA210_AMX_RAM_DEPTH 16 +#define TEGRA210_AMX_MAP_STREAM_NUM_SHIFT 6 +#define TEGRA210_AMX_MAP_WORD_NUM_SHIFT 2 +#define TEGRA210_AMX_MAP_BYTE_NUM_SHIFT 0 + +enum { + TEGRA210_AMX_WAIT_ON_ALL, + TEGRA210_AMX_WAIT_ON_ANY, +}; + +struct tegra210_amx_soc_data { + const struct regmap_config *regmap_conf; + bool auto_disable; +}; + +struct tegra210_amx { + const struct tegra210_amx_soc_data *soc_data; + unsigned int map[TEGRA210_AMX_RAM_DEPTH]; + struct regmap *regmap; + unsigned int byte_mask[2]; +}; + +#endif diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c new file mode 100644 index 00000000000000..55e61776c565ad --- /dev/null +++ b/sound/soc/tegra/tegra210_mixer.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_mixer.c - Tegra210 MIXER driver +// +// Copyright (c) 2021 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_mixer.h" +#include "tegra_cif.h" + +#define MIXER_REG(reg, id) ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE)) +#define MIXER_REG_BASE(reg) ((reg) % TEGRA210_MIXER_REG_STRIDE) + +#define MIXER_GAIN_CFG_RAM_ADDR(id) \ + (TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 + \ + ((id) * TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE)) + +#define MIXER_RX_REG_DEFAULTS(id) \ + { MIXER_REG(TEGRA210_MIXER_RX1_CIF_CTRL, id), 0x00007700}, \ + { MIXER_REG(TEGRA210_MIXER_RX1_CTRL, id), 0x00010823}, \ + { MIXER_REG(TEGRA210_MIXER_RX1_PEAK_CTRL, id), 0x000012c0} + +#define MIXER_TX_REG_DEFAULTS(id) \ + { MIXER_REG(TEGRA210_MIXER_TX1_INT_MASK, (id)), 0x00000001}, \ + { MIXER_REG(TEGRA210_MIXER_TX1_CIF_CTRL, (id)), 0x00007700} + +#define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i)) + +static const struct reg_default tegra210_mixer_reg_defaults[] = { + /* Inputs */ + MIXER_RX_REG_DEFAULTS(0), + MIXER_RX_REG_DEFAULTS(1), + MIXER_RX_REG_DEFAULTS(2), + MIXER_RX_REG_DEFAULTS(3), + MIXER_RX_REG_DEFAULTS(4), + MIXER_RX_REG_DEFAULTS(5), + MIXER_RX_REG_DEFAULTS(6), + MIXER_RX_REG_DEFAULTS(7), + MIXER_RX_REG_DEFAULTS(8), + MIXER_RX_REG_DEFAULTS(9), + /* Outputs */ + MIXER_TX_REG_DEFAULTS(0), + MIXER_TX_REG_DEFAULTS(1), + MIXER_TX_REG_DEFAULTS(2), + MIXER_TX_REG_DEFAULTS(3), + MIXER_TX_REG_DEFAULTS(4), + + { TEGRA210_MIXER_CG, 0x00000001}, + { TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000}, + { TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000}, + { TEGRA210_MIXER_ENABLE, 0x1 }, +}; + +/* Default gain parameters */ +static const struct tegra210_mixer_gain_params gain_params = { + /* Polynomial coefficients */ + { 0, 0, 0, 0, 0, 0, 0, 0x1000000, 0 }, + /* Gain value */ + 0x10000, + /* Duration Parameters */ + { 0, 0, 0x400, 0x8000000 }, +}; + +static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev) +{ + struct tegra210_mixer *mixer = dev_get_drvdata(dev); + + regcache_cache_only(mixer->regmap, true); + regcache_mark_dirty(mixer->regmap); + + return 0; +} + +static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev) +{ + struct tegra210_mixer *mixer = dev_get_drvdata(dev); + + regcache_cache_only(mixer->regmap, false); + regcache_sync(mixer->regmap); + + return 0; +} + +static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer, + unsigned int addr, + unsigned int coef) +{ + unsigned int reg, val; + int err; + + /* Check if busy */ + err = regmap_read_poll_timeout(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, + val, !(val & 0x80000000), 10, 10000); + if (err < 0) + return err; + + reg = (addr << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) & + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN; + + regmap_write(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, + reg); + regmap_write(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_DATA, + coef); + + return 0; +} + +static int tegra210_mixer_configure_gain(struct snd_soc_component *cmpnt, + unsigned int id, bool instant_gain) +{ + struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = MIXER_GAIN_CFG_RAM_ADDR(id); + int err, i; + + pm_runtime_get_sync(cmpnt->dev); + + /* Write default gain poly coefficients */ + for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) { + err = tegra210_mixer_write_ram(mixer, reg + i, + gain_params.poly_coeff[i]); + + if (err < 0) + goto rpm_put; + } + + /* Write stored gain value */ + err = tegra210_mixer_write_ram(mixer, reg + NUM_GAIN_POLY_COEFFS, + mixer->gain_value[id]); + if (err < 0) + goto rpm_put; + + /* Write duration parameters */ + for (i = 0; i < NUM_DURATION_PARMS; i++) { + int val; + + if (instant_gain) + val = 1; + else + val = gain_params.duration[i]; + + err = tegra210_mixer_write_ram(mixer, + REG_DURATION_PARAM(reg, i), + val); + if (err < 0) + goto rpm_put; + } + + /* Trigger to apply gain configurations */ + err = tegra210_mixer_write_ram(mixer, reg + REG_CFG_DONE_TRIGGER, + VAL_CFG_DONE_TRIGGER); + +rpm_put: + pm_runtime_put(cmpnt->dev); + + return err; +} + +static int tegra210_mixer_get_gain(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_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg; + unsigned int i; + + i = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) / + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE; + + ucontrol->value.integer.value[0] = mixer->gain_value[i]; + + return 0; +} + +static int tegra210_mixer_put_gain(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_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg, id; + bool instant_gain = false; + int err; + + if (strstr(kcontrol->id.name, "Instant Gain Volume")) + instant_gain = true; + + /* Save gain value for specific MIXER input */ + id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) / + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE; + + mixer->gain_value[id] = ucontrol->value.integer.value[0]; + + err = tegra210_mixer_configure_gain(cmpnt, id, instant_gain); + if (err) { + dev_err(cmpnt->dev, "Failed to apply gain\n"); + return err; + } + + return 1; +} + +static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, + struct snd_pcm_hw_params *params, + unsigned int reg, + unsigned int id) +{ + unsigned int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + 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(mixer->regmap, + reg + (id * TEGRA210_MIXER_REG_STRIDE), + &cif_conf); + + return 0; +} + +static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai); + int err; + + err = tegra210_mixer_set_audio_cif(mixer, params, + TEGRA210_MIXER_RX1_CIF_CTRL, + dai->id); + if (err < 0) + return err; + + return tegra210_mixer_configure_gain(dai->component, dai->id, false); +} + +static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai); + + return tegra210_mixer_set_audio_cif(mixer, params, + TEGRA210_MIXER_TX1_CIF_CTRL, + dai->id - TEGRA210_MIXER_RX_MAX); +} + +static const struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = { + .hw_params = tegra210_mixer_out_hw_params, +}; + +static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { + .hw_params = tegra210_mixer_in_hw_params, +}; + +#define IN_DAI(id) \ + { \ + .name = "MIXER-RX-CIF"#id, \ + .playback = { \ + .stream_name = "RX" #id "-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" #id "-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_mixer_in_dai_ops, \ + } + +#define OUT_DAI(id) \ + { \ + .name = "MIXER-TX-CIF" #id, \ + .playback = { \ + .stream_name = "TX" #id "-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" #id "-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_mixer_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_mixer_dais[] = { + /* Mixer Input */ + IN_DAI(1), + IN_DAI(2), + IN_DAI(3), + IN_DAI(4), + IN_DAI(5), + IN_DAI(6), + IN_DAI(7), + IN_DAI(8), + IN_DAI(9), + IN_DAI(10), + + /* Mixer Output */ + OUT_DAI(1), + OUT_DAI(2), + OUT_DAI(3), + OUT_DAI(4), + OUT_DAI(5), +}; + +#define ADDER_CTRL_DECL(name, reg) \ + static const struct snd_kcontrol_new name[] = { \ + SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0), \ + SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0), \ + SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0), \ + SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0), \ + SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0), \ + SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0), \ + SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0), \ + SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0), \ + SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0), \ + SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0), \ + } + +ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_TX1_ADDER_CONFIG); +ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_TX2_ADDER_CONFIG); +ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_TX3_ADDER_CONFIG); +ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_TX4_ADDER_CONFIG); +ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG); + +#define GAIN_CTRL(id) \ + SOC_SINGLE_EXT("RX" #id " Gain Volume", \ + MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \ + 0x20000, 0, tegra210_mixer_get_gain, \ + tegra210_mixer_put_gain), \ + SOC_SINGLE_EXT("RX" #id " Instant Gain Volume", \ + MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \ + 0x20000, 0, tegra210_mixer_get_gain, \ + tegra210_mixer_put_gain), + +/* Volume controls for all MIXER inputs */ +static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = { + GAIN_CTRL(1) + GAIN_CTRL(2) + GAIN_CTRL(3) + GAIN_CTRL(4) + GAIN_CTRL(5) + GAIN_CTRL(6) + GAIN_CTRL(7) + GAIN_CTRL(8) + GAIN_CTRL(9) + GAIN_CTRL(10) +}; + +static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_MIXER_TX1_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_MIXER_TX2_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_MIXER_TX3_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_MIXER_TX4_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0, TEGRA210_MIXER_TX5_ENABLE, 0, 0), + SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, adder1, + ARRAY_SIZE(adder1)), + SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, adder2, + ARRAY_SIZE(adder2)), + SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, adder3, + ARRAY_SIZE(adder3)), + SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, adder4, + ARRAY_SIZE(adder4)), + SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, adder5, + ARRAY_SIZE(adder5)), +}; + +#define RX_ROUTES(id, sname) \ + { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ + { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \ + { "RX" #id, NULL, "RX" #id "-CIF-" sname } + +#define MIXER_RX_ROUTES(id) \ + RX_ROUTES(id, "Playback"), \ + RX_ROUTES(id, "Capture") + +#define ADDER_ROUTES(id, sname) \ + { "Adder" #id, "RX1", "RX1" }, \ + { "Adder" #id, "RX2", "RX2" }, \ + { "Adder" #id, "RX3", "RX3" }, \ + { "Adder" #id, "RX4", "RX4" }, \ + { "Adder" #id, "RX5", "RX5" }, \ + { "Adder" #id, "RX6", "RX6" }, \ + { "Adder" #id, "RX7", "RX7" }, \ + { "Adder" #id, "RX8", "RX8" }, \ + { "Adder" #id, "RX9", "RX9" }, \ + { "Adder" #id, "RX10", "RX10" }, \ + { "TX" #id, NULL, "Adder" #id }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } \ + +#define TX_ROUTES(id, sname) \ + ADDER_ROUTES(1, sname), \ + ADDER_ROUTES(2, sname), \ + ADDER_ROUTES(3, sname), \ + ADDER_ROUTES(4, sname), \ + ADDER_ROUTES(5, sname) + +#define MIXER_TX_ROUTES(id) \ + TX_ROUTES(id, "Playback"), \ + TX_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_mixer_routes[] = { + /* Input */ + MIXER_RX_ROUTES(1), + MIXER_RX_ROUTES(2), + MIXER_RX_ROUTES(3), + MIXER_RX_ROUTES(4), + MIXER_RX_ROUTES(5), + MIXER_RX_ROUTES(6), + MIXER_RX_ROUTES(7), + MIXER_RX_ROUTES(8), + MIXER_RX_ROUTES(9), + MIXER_RX_ROUTES(10), + /* Output */ + MIXER_TX_ROUTES(1), + MIXER_TX_ROUTES(2), + MIXER_TX_ROUTES(3), + MIXER_TX_ROUTES(4), + MIXER_TX_ROUTES(5), +}; + +static const struct snd_soc_component_driver tegra210_mixer_cmpnt = { + .dapm_widgets = tegra210_mixer_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets), + .dapm_routes = tegra210_mixer_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_mixer_routes), + .controls = tegra210_mixer_gain_ctls, + .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls), +}; + +static bool tegra210_mixer_wr_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET: + case TEGRA210_MIXER_RX1_CIF_CTRL ... TEGRA210_MIXER_RX1_PEAK_CTRL: + + case TEGRA210_MIXER_TX1_ENABLE: + case TEGRA210_MIXER_TX1_SOFT_RESET: + case TEGRA210_MIXER_TX1_INT_MASK ... TEGRA210_MIXER_TX1_ADDER_CONFIG: + + case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CG: + case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL ... TEGRA210_MIXER_CTRL: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_rd_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET ... TEGRA210_MIXER_RX1_SAMPLE_COUNT: + case TEGRA210_MIXER_TX1_ENABLE ... TEGRA210_MIXER_TX1_ADDER_CONFIG: + case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CTRL: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_volatile_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET: + case TEGRA210_MIXER_RX1_STATUS: + + case TEGRA210_MIXER_TX1_SOFT_RESET: + case TEGRA210_MIXER_TX1_STATUS: + case TEGRA210_MIXER_TX1_INT_STATUS: + case TEGRA210_MIXER_TX1_INT_SET: + + case TEGRA210_MIXER_SOFT_RESET: + case TEGRA210_MIXER_STATUS: + case TEGRA210_MIXER_INT_STATUS: + case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL: + case TEGRA210_MIXER_GAIN_CFG_RAM_DATA: + case TEGRA210_MIXER_PEAKM_RAM_CTRL: + case TEGRA210_MIXER_PEAKM_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_precious_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_MIXER_GAIN_CFG_RAM_DATA: + case TEGRA210_MIXER_PEAKM_RAM_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_mixer_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_MIXER_CTRL, + .writeable_reg = tegra210_mixer_wr_reg, + .readable_reg = tegra210_mixer_rd_reg, + .volatile_reg = tegra210_mixer_volatile_reg, + .precious_reg = tegra210_mixer_precious_reg, + .reg_defaults = tegra210_mixer_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_mixer_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_mixer_of_match[] = { + { .compatible = "nvidia,tegra210-amixer" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match); + +static int tegra210_mixer_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_mixer *mixer; + void __iomem *regs; + int err, i; + + mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + + dev_set_drvdata(dev, mixer); + + /* Use default gain value for all MIXER inputs */ + for (i = 0; i < TEGRA210_MIXER_RX_MAX; i++) + mixer->gain_value[i] = gain_params.gain_value; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + mixer->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_mixer_regmap_config); + if (IS_ERR(mixer->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(mixer->regmap); + } + + regcache_cache_only(mixer->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt, + tegra210_mixer_dais, + ARRAY_SIZE(tegra210_mixer_dais)); + if (err) { + dev_err(dev, "can't register MIXER component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_mixer_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_mixer_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend, + tegra210_mixer_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_mixer_driver = { + .driver = { + .name = "tegra210_mixer", + .of_match_table = tegra210_mixer_of_match, + .pm = &tegra210_mixer_pm_ops, + }, + .probe = tegra210_mixer_platform_probe, + .remove = tegra210_mixer_platform_remove, +}; +module_platform_driver(tegra210_mixer_driver); + +MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_mixer.h b/sound/soc/tegra/tegra210_mixer.h new file mode 100644 index 00000000000000..a330530fbc613c --- /dev/null +++ b/sound/soc/tegra/tegra210_mixer.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_mixer.h - Definitions for Tegra210 MIXER driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_MIXER_H__ +#define __TEGRA210_MIXER_H__ + +/* XBAR_RX related MIXER offsets */ +#define TEGRA210_MIXER_RX1_SOFT_RESET 0x04 +#define TEGRA210_MIXER_RX1_STATUS 0x10 +#define TEGRA210_MIXER_RX1_CIF_CTRL 0x24 +#define TEGRA210_MIXER_RX1_CTRL 0x28 +#define TEGRA210_MIXER_RX1_PEAK_CTRL 0x2c +#define TEGRA210_MIXER_RX1_SAMPLE_COUNT 0x30 + +/* XBAR_TX related MIXER offsets */ +#define TEGRA210_MIXER_TX1_ENABLE 0x280 +#define TEGRA210_MIXER_TX1_SOFT_RESET 0x284 +#define TEGRA210_MIXER_TX1_STATUS 0x290 +#define TEGRA210_MIXER_TX1_INT_STATUS 0x294 +#define TEGRA210_MIXER_TX1_INT_MASK 0x298 +#define TEGRA210_MIXER_TX1_INT_SET 0x29c +#define TEGRA210_MIXER_TX1_INT_CLEAR 0x2a0 +#define TEGRA210_MIXER_TX1_CIF_CTRL 0x2a4 +#define TEGRA210_MIXER_TX1_ADDER_CONFIG 0x2a8 + +/* MIXER related offsets */ +#define TEGRA210_MIXER_ENABLE 0x400 +#define TEGRA210_MIXER_SOFT_RESET 0x404 +#define TEGRA210_MIXER_CG 0x408 +#define TEGRA210_MIXER_STATUS 0x410 +#define TEGRA210_MIXER_INT_STATUS 0x414 +#define TEGRA210_MIXER_GAIN_CFG_RAM_CTRL 0x42c +#define TEGRA210_MIXER_GAIN_CFG_RAM_DATA 0x430 +#define TEGRA210_MIXER_PEAKM_RAM_CTRL 0x434 +#define TEGRA210_MIXER_PEAKM_RAM_DATA 0x438 +#define TEGRA210_MIXER_CTRL 0x43c + +#define TEGRA210_MIXER_TX2_ADDER_CONFIG (TEGRA210_MIXER_TX1_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX3_ADDER_CONFIG (TEGRA210_MIXER_TX2_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX4_ADDER_CONFIG (TEGRA210_MIXER_TX3_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX5_ADDER_CONFIG (TEGRA210_MIXER_TX4_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) + +#define TEGRA210_MIXER_TX2_ENABLE (TEGRA210_MIXER_TX1_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX3_ENABLE (TEGRA210_MIXER_TX2_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX4_ENABLE (TEGRA210_MIXER_TX3_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX5_ENABLE (TEGRA210_MIXER_TX4_ENABLE + TEGRA210_MIXER_REG_STRIDE) + +/* Fields in TEGRA210_MIXER_ENABLE */ +#define TEGRA210_MIXER_ENABLE_SHIFT 0 +#define TEGRA210_MIXER_ENABLE_MASK (1 << TEGRA210_MIXER_ENABLE_SHIFT) +#define TEGRA210_MIXER_EN (1 << TEGRA210_MIXER_ENABLE_SHIFT) + +/* Fields in TEGRA210_MIXER_GAIN_CFG_RAM_CTRL */ +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 0x0 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE 0x10 + +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT 14 +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE (1 << TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN (1 << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN (1 << TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT 0 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK (0x1ff << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) + +#define TEGRA210_MIXER_REG_STRIDE 0x40 +#define TEGRA210_MIXER_RX_MAX 10 +#define TEGRA210_MIXER_RX_LIMIT (TEGRA210_MIXER_RX_MAX * TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX_MAX 5 +#define TEGRA210_MIXER_TX_LIMIT (TEGRA210_MIXER_RX_LIMIT + (TEGRA210_MIXER_TX_MAX * TEGRA210_MIXER_REG_STRIDE)) + +#define REG_CFG_DONE_TRIGGER 0xf +#define VAL_CFG_DONE_TRIGGER 0x1 + +#define NUM_GAIN_POLY_COEFFS 9 +#define NUM_DURATION_PARMS 4 + +struct tegra210_mixer_gain_params { + int poly_coeff[NUM_GAIN_POLY_COEFFS]; + int gain_value; + int duration[NUM_DURATION_PARMS]; +}; + +struct tegra210_mixer { + int gain_value[TEGRA210_MIXER_RX_MAX]; + struct regmap *regmap; +}; + +#endif diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c new file mode 100644 index 00000000000000..7b9c7006e4197e --- /dev/null +++ b/sound/soc/tegra/tegra210_mvc.c @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_mvc.c - Tegra210 MVC driver +// +// Copyright (c) 2021 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_mvc.h" +#include "tegra_cif.h" + +static const struct reg_default tegra210_mvc_reg_defaults[] = { + { TEGRA210_MVC_RX_INT_MASK, 0x00000001}, + { TEGRA210_MVC_RX_CIF_CTRL, 0x00007700}, + { TEGRA210_MVC_TX_INT_MASK, 0x00000001}, + { TEGRA210_MVC_TX_CIF_CTRL, 0x00007700}, + { TEGRA210_MVC_CG, 0x1}, + { TEGRA210_MVC_CTRL, TEGRA210_MVC_CTRL_DEFAULT}, + { TEGRA210_MVC_INIT_VOL, 0x00800000}, + { TEGRA210_MVC_TARGET_VOL, 0x00800000}, + { TEGRA210_MVC_DURATION, 0x000012c0}, + { TEGRA210_MVC_DURATION_INV, 0x0006d3a0}, + { TEGRA210_MVC_POLY_N1, 0x0000007d}, + { TEGRA210_MVC_POLY_N2, 0x00000271}, + { TEGRA210_MVC_PEAK_CTRL, 0x000012c0}, + { TEGRA210_MVC_CFG_RAM_CTRL, 0x00004000}, +}; + +static const struct tegra210_mvc_gain_params gain_params = { + .poly_coeff = { 23738319, 659403, -3680, + 15546680, 2530732, -120985, + 12048422, 5527252, -785042 }, + .poly_n1 = 16, + .poly_n2 = 63, + .duration = 150, + .duration_inv = 14316558, +}; + +static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev) +{ + struct tegra210_mvc *mvc = dev_get_drvdata(dev); + + regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &(mvc->ctrl_value)); + + regcache_cache_only(mvc->regmap, true); + regcache_mark_dirty(mvc->regmap); + + return 0; +} + +static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev) +{ + struct tegra210_mvc *mvc = dev_get_drvdata(dev); + + regcache_cache_only(mvc->regmap, false); + regcache_sync(mvc->regmap); + + regmap_write(mvc->regmap, TEGRA210_MVC_CTRL, mvc->ctrl_value); + regmap_update_bits(mvc->regmap, + TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + + return 0; +} + +static void tegra210_mvc_write_ram(struct regmap *regmap) +{ + int i; + + regmap_write(regmap, TEGRA210_MVC_CFG_RAM_CTRL, + TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE); + + for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) + regmap_write(regmap, TEGRA210_MVC_CFG_RAM_DATA, + gain_params.poly_coeff[i]); +} + +static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val) +{ + /* + * Volume control read from mixer control is with + * 100x scaling; for CURVE_POLY the reg range + * is 0-100 (linear, Q24) and for CURVE_LINEAR + * it is -120dB to +40dB (Q8) + */ + if (mvc->curve_type == CURVE_POLY) { + if (val > 10000) + val = 10000; + mvc->volume[chan] = ((val * (1<<8)) / 100) << 16; + } else { + val -= 12000; + mvc->volume[chan] = (val * (1<<8)) / 100; + } +} + +static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + u8 mute_mask; + u32 val; + + pm_runtime_get_sync(cmpnt->dev); + regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &val); + pm_runtime_put(cmpnt->dev); + + mute_mask = (val >> TEGRA210_MVC_MUTE_SHIFT) & + TEGRA210_MUTE_MASK_EN; + + ucontrol->value.integer.value[0] = mute_mask; + + return 0; +} + +static int tegra210_mvc_put_mute(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_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + unsigned int value; + u8 mute_mask; + int err; + + pm_runtime_get_sync(cmpnt->dev); + + /* Check if VOLUME_SWITCH is triggered */ + err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, + value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), + 10, 10000); + if (err < 0) + goto end; + + mute_mask = ucontrol->value.integer.value[0]; + + err = regmap_update_bits(mvc->regmap, mc->reg, + TEGRA210_MVC_MUTE_MASK, + mute_mask << TEGRA210_MVC_MUTE_SHIFT); + if (err < 0) + goto end; + + return 1; + +end: + pm_runtime_put(cmpnt->dev); + return err; +} + +static int tegra210_mvc_get_vol(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_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + u8 chan = (mc->reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; + s32 val = mvc->volume[chan]; + + if (mvc->curve_type == CURVE_POLY) { + val = ((val >> 16) * 100) >> 8; + } else { + val = (val * 100) >> 8; + val += 12000; + } + + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int tegra210_mvc_put_vol(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_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg; + unsigned int value; + u8 chan; + int err; + + pm_runtime_get_sync(cmpnt->dev); + + /* Check if VOLUME_SWITCH is triggered */ + err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, + value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), + 10, 10000); + if (err < 0) + goto end; + + chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; + + tegra210_mvc_conv_vol(mvc, chan, + ucontrol->value.integer.value[0]); + + /* Configure init volume same as target volume */ + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan), + mvc->volume[chan]); + + regmap_write(mvc->regmap, reg, mvc->volume[chan]); + + regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + + return 1; + +end: + pm_runtime_put(cmpnt->dev); + return err; +} + +static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc *mvc, + struct device *dev) +{ + int i; + + /* Change volume to default init for new curve type */ + if (mvc->curve_type == CURVE_POLY) { + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) + mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY; + } else { + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) + mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR; + } + + pm_runtime_get_sync(dev); + + /* Program curve type */ + regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, + TEGRA210_MVC_CURVE_TYPE_MASK, + mvc->curve_type << + TEGRA210_MVC_CURVE_TYPE_SHIFT); + + /* Init volume for all channels */ + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) { + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, i), + mvc->volume[i]); + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, i), + mvc->volume[i]); + } + + /* Trigger volume switch */ + regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + + pm_runtime_put(dev); +} + +static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = mvc->curve_type; + + return 0; +} + +static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + int value; + + regmap_read(mvc->regmap, TEGRA210_MVC_ENABLE, &value); + if (value & TEGRA210_MVC_EN) { + dev_err(cmpnt->dev, + "Curve type can't be set when MVC is running\n"); + return -EINVAL; + } + + if (mvc->curve_type == ucontrol->value.integer.value[0]) + return 0; + + mvc->curve_type = ucontrol->value.integer.value[0]; + + tegra210_mvc_reset_vol_settings(mvc, cmpnt->dev); + + return 1; +} + +static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + unsigned int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + 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(mvc->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_mvc_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_mvc *mvc = snd_soc_dai_get_drvdata(dai); + int err, val; + + /* + * Soft Reset: Below performs module soft reset which clears + * all FSM logic, flushes flow control of FIFO and resets the + * state register. It also brings module back to disabled + * state (without flushing the data in the pipe). + */ + regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1); + + err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SOFT_RESET, + val, !val, 10, 10000); + if (err < 0) { + dev_err(dev, "SW reset failed, err = %d\n", err); + return err; + } + + /* Set RX CIF */ + err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_RX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set MVC RX CIF: %d\n", err); + return err; + } + + /* Set TX CIF */ + err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_TX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set MVC TX CIF: %d\n", err); + return err; + } + + tegra210_mvc_write_ram(mvc->regmap); + + /* Program poly_n1, poly_n2, duration */ + regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, gain_params.poly_n1); + regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N2, gain_params.poly_n2); + regmap_write(mvc->regmap, TEGRA210_MVC_DURATION, gain_params.duration); + + /* Program duration_inv */ + regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV, + gain_params.duration_inv); + + return 0; +} + +static const struct snd_soc_dai_ops tegra210_mvc_dai_ops = { + .hw_params = tegra210_mvc_hw_params, +}; + +static const char * const tegra210_mvc_curve_type_text[] = { + "Poly", + "Linear", +}; + +static const struct soc_enum tegra210_mvc_curve_type_ctrl = + SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text); + +#define TEGRA210_MVC_VOL_CTRL(chan) \ + SOC_SINGLE_EXT("Channel" #chan " Volume", \ + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, \ + (chan - 1)), \ + 0, 16000, 0, tegra210_mvc_get_vol, \ + tegra210_mvc_put_vol) + +static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = { + /* Per channel volume control */ + TEGRA210_MVC_VOL_CTRL(1), + TEGRA210_MVC_VOL_CTRL(2), + TEGRA210_MVC_VOL_CTRL(3), + TEGRA210_MVC_VOL_CTRL(4), + TEGRA210_MVC_VOL_CTRL(5), + TEGRA210_MVC_VOL_CTRL(6), + TEGRA210_MVC_VOL_CTRL(7), + TEGRA210_MVC_VOL_CTRL(8), + + /* Per channel mute */ + SOC_SINGLE_EXT("Per Chan Mute Mask", + TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0, + tegra210_mvc_get_mute, tegra210_mvc_put_mute), + + SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl, + tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type), +}; + +static struct snd_soc_dai_driver tegra210_mvc_dais[] = { + /* Input */ + { + .name = "MVC-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, + }, + }, + + /* Output */ + { + .name = "MVC-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_mvc_dai_ops, + } +}; + +static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_MVC_ENABLE, + TEGRA210_MVC_EN_SHIFT, 0), +}; + +#define MVC_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_mvc_routes[] = { + { "TX", NULL, "RX" }, + MVC_ROUTES("Playback"), + MVC_ROUTES("Capture"), +}; + +static const struct snd_soc_component_driver tegra210_mvc_cmpnt = { + .dapm_widgets = tegra210_mvc_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets), + .dapm_routes = tegra210_mvc_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_mvc_routes), + .controls = tegra210_mvc_vol_ctrl, + .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl), +}; + +static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_STATUS ... TEGRA210_MVC_CONFIG_ERR_TYPE: + return true; + default: + return false; + }; +} + +static bool tegra210_mvc_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_INT_MASK ... TEGRA210_MVC_RX_CIF_CTRL: + case TEGRA210_MVC_TX_INT_MASK ... TEGRA210_MVC_TX_CIF_CTRL: + case TEGRA210_MVC_ENABLE ... TEGRA210_MVC_CG: + case TEGRA210_MVC_CTRL ... TEGRA210_MVC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_STATUS: + case TEGRA210_MVC_RX_INT_STATUS: + case TEGRA210_MVC_RX_INT_SET: + + case TEGRA210_MVC_TX_STATUS: + case TEGRA210_MVC_TX_INT_STATUS: + case TEGRA210_MVC_TX_INT_SET: + + case TEGRA210_MVC_SOFT_RESET: + case TEGRA210_MVC_STATUS: + case TEGRA210_MVC_INT_STATUS: + case TEGRA210_MVC_SWITCH: + case TEGRA210_MVC_CFG_RAM_CTRL: + case TEGRA210_MVC_CFG_RAM_DATA: + case TEGRA210_MVC_PEAK_VALUE: + case TEGRA210_MVC_CTRL: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_mvc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_MVC_CONFIG_ERR_TYPE, + .writeable_reg = tegra210_mvc_wr_reg, + .readable_reg = tegra210_mvc_rd_reg, + .volatile_reg = tegra210_mvc_volatile_reg, + .reg_defaults = tegra210_mvc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_mvc_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_mvc_of_match[] = { + { .compatible = "nvidia,tegra210-mvc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_mvc_of_match); + +static int tegra210_mvc_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_mvc *mvc; + void __iomem *regs; + int err; + + mvc = devm_kzalloc(dev, sizeof(*mvc), GFP_KERNEL); + if (!mvc) + return -ENOMEM; + + dev_set_drvdata(dev, mvc); + + mvc->curve_type = CURVE_LINEAR; + mvc->ctrl_value = TEGRA210_MVC_CTRL_DEFAULT; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + mvc->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_mvc_regmap_config); + if (IS_ERR(mvc->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(mvc->regmap); + } + + regcache_cache_only(mvc->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_mvc_cmpnt, + tegra210_mvc_dais, + ARRAY_SIZE(tegra210_mvc_dais)); + if (err) { + dev_err(dev, "can't register MVC component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + tegra210_mvc_reset_vol_settings(mvc, &pdev->dev); + + return 0; +} + +static int tegra210_mvc_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_mvc_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, + tegra210_mvc_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_mvc_driver = { + .driver = { + .name = "tegra210-mvc", + .of_match_table = tegra210_mvc_of_match, + .pm = &tegra210_mvc_pm_ops, + }, + .probe = tegra210_mvc_platform_probe, + .remove = tegra210_mvc_platform_remove, +}; +module_platform_driver(tegra210_mvc_driver) + +MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 MVC ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_mvc.h b/sound/soc/tegra/tegra210_mvc.h new file mode 100644 index 00000000000000..def29c4c72577d --- /dev/null +++ b/sound/soc/tegra/tegra210_mvc.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_mvc.h - Definitions for Tegra210 MVC driver + * + * Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_MVC_H__ +#define __TEGRA210_MVC_H__ + +/* + * MVC_RX registers are with respect to XBAR. + * The data comes from XBAR to MVC. + */ +#define TEGRA210_MVC_RX_STATUS 0x0c +#define TEGRA210_MVC_RX_INT_STATUS 0x10 +#define TEGRA210_MVC_RX_INT_MASK 0x14 +#define TEGRA210_MVC_RX_INT_SET 0x18 +#define TEGRA210_MVC_RX_INT_CLEAR 0x1c +#define TEGRA210_MVC_RX_CIF_CTRL 0x20 + +/* + * MVC_TX registers are with respect to XBAR. + * The data goes out of MVC. + */ +#define TEGRA210_MVC_TX_STATUS 0x4c +#define TEGRA210_MVC_TX_INT_STATUS 0x50 +#define TEGRA210_MVC_TX_INT_MASK 0x54 +#define TEGRA210_MVC_TX_INT_SET 0x58 +#define TEGRA210_MVC_TX_INT_CLEAR 0x5c +#define TEGRA210_MVC_TX_CIF_CTRL 0x60 + +/* Register offsets from TEGRA210_MVC*_BASE */ +#define TEGRA210_MVC_ENABLE 0x80 +#define TEGRA210_MVC_SOFT_RESET 0x84 +#define TEGRA210_MVC_CG 0x88 +#define TEGRA210_MVC_STATUS 0x90 +#define TEGRA210_MVC_INT_STATUS 0x94 +#define TEGRA210_MVC_CTRL 0xa8 +#define TEGRA210_MVC_SWITCH 0xac +#define TEGRA210_MVC_INIT_VOL 0xb0 +#define TEGRA210_MVC_TARGET_VOL 0xd0 +#define TEGRA210_MVC_DURATION 0xf0 +#define TEGRA210_MVC_DURATION_INV 0xf4 +#define TEGRA210_MVC_POLY_N1 0xf8 +#define TEGRA210_MVC_POLY_N2 0xfc +#define TEGRA210_MVC_PEAK_CTRL 0x100 +#define TEGRA210_MVC_CFG_RAM_CTRL 0x104 +#define TEGRA210_MVC_CFG_RAM_DATA 0x108 +#define TEGRA210_MVC_PEAK_VALUE 0x10c +#define TEGRA210_MVC_CONFIG_ERR_TYPE 0x12c + +/* Fields in TEGRA210_MVC_ENABLE */ +#define TEGRA210_MVC_EN_SHIFT 0 +#define TEGRA210_MVC_EN (1 << TEGRA210_MVC_EN_SHIFT) + +#define TEGRA210_MVC_MUTE_SHIFT 8 +#define TEGRA210_MUTE_MASK_EN 0xff +#define TEGRA210_MVC_MUTE_MASK (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) +#define TEGRA210_MVC_MUTE_EN (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) + +#define TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT 30 +#define TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT) +#define TEGRA210_MVC_PER_CHAN_CTRL_EN (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT) + +#define TEGRA210_MVC_CURVE_TYPE_SHIFT 1 +#define TEGRA210_MVC_CURVE_TYPE_MASK (1 << TEGRA210_MVC_CURVE_TYPE_SHIFT) + +#define TEGRA210_MVC_VOLUME_SWITCH_SHIFT 2 +#define TEGRA210_MVC_VOLUME_SWITCH_MASK (1 << TEGRA210_MVC_VOLUME_SWITCH_SHIFT) +#define TEGRA210_MVC_VOLUME_SWITCH_TRIGGER (1 << TEGRA210_MVC_VOLUME_SWITCH_SHIFT) +#define TEGRA210_MVC_CTRL_DEFAULT 0x40000003 + +#define TEGRA210_MVC_INIT_VOL_DEFAULT_POLY 0x01000000 +#define TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR 0x00000000 + +/* Fields in TEGRA210_MVC ram ctrl */ +#define TEGRA210_MVC_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_MVC_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_SHIFT 0 +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_MASK (0x1ff << TEGRA210_MVC_CFG_RAM_CTRL_ADDR_SHIFT) + +#define REG_SIZE 4 +#define TEGRA210_MVC_MAX_CHAN_COUNT 8 +#define TEGRA210_MVC_REG_OFFSET(reg, i) (reg + (REG_SIZE * i)) + +#define NUM_GAIN_POLY_COEFFS 9 + +enum { + CURVE_POLY, + CURVE_LINEAR, +}; + +struct tegra210_mvc_gain_params { + int poly_coeff[NUM_GAIN_POLY_COEFFS]; + int poly_n1; + int poly_n2; + int duration; + int duration_inv; +}; + +struct tegra210_mvc { + int volume[TEGRA210_MVC_MAX_CHAN_COUNT]; + unsigned int curve_type; + unsigned int ctrl_value; + struct regmap *regmap; +}; + +#endif diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c new file mode 100644 index 00000000000000..dc477ee1b82cd0 --- /dev/null +++ b/sound/soc/tegra/tegra210_sfc.c @@ -0,0 +1,3549 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_sfc.c - Tegra210 SFC driver +// +// Copyright (c) 2021 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_sfc.h" +#include "tegra_cif.h" + +#define UNSUPP_CONV ((void *)(-EOPNOTSUPP)) +#define BYPASS_CONV NULL + +static const struct reg_default tegra210_sfc_reg_defaults[] = { + { TEGRA210_SFC_RX_INT_MASK, 0x00000001}, + { TEGRA210_SFC_RX_CIF_CTRL, 0x00007700}, + { TEGRA210_SFC_TX_INT_MASK, 0x00000001}, + { TEGRA210_SFC_TX_CIF_CTRL, 0x00007700}, + { TEGRA210_SFC_CG, 0x1}, + { TEGRA210_SFC_CFG_RAM_CTRL, 0x00004000}, +}; + +static const int tegra210_sfc_rates[TEGRA210_SFC_NUM_RATES] = { + 8000, + 11025, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 88200, + 96000, + 176400, + 192000, +}; + +/* coeff RAM tables required for SFC */ +static u32 coef_8to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_8to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_8to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001//output gain +}; + +static u32 coef_8to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//header + 0x000005e1,//input gain + 0x00dca92f, 0xff45647a, 0x0046b59c, + 0x00429d1e, 0xff4fec62, 0x00516d30, + 0xffdea779, 0xff5e08ba, 0x0060185e, + 0xffafbab2, 0xff698d5a, 0x006ce3ae, + 0xff9a82d2, 0xff704674, 0x007633c5, + 0xff923433, 0xff721128, 0x007cff42, + 0x00000003//output gain +}; + +static u32 coef_8to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_8to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0156105,//interpolation + IIR filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//ouptut gain + 0x0021a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003,//Output gain + 0x00000204,//Farrow filter + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_8to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//interpolation + IIR Filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//ouptut gain + 0x0000a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003//output gain +}; + +static u32 coef_8to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0024a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_8to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0000a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003//output gain +}; + +static u32 coef_11to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_11to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_11to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_11to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_11to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_16to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000fa103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000003,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_16to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_16to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0015a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003,//output gain + 0x00005105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_16to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_16to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//interpolation + IIR filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//output gain + 0x0021a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003,//output gain + 0x002c0204,//Farrow Filter + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005101,//IIR Filter + Decimator + 0x0000203c,//input gain + 0x00f52d35, 0xff2e2162, 0x005a21e0, + 0x00c6f0f0, 0xff2ecd69, 0x006fa78d, + 0x00000001//output gain +}; + +static u32 coef_16to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//interpolation + IIR Filter + 0x00000784,//input gain + 0x00cc516e, 0xff2c9639, 0x005ad5b3, + 0x0013ad0d, 0xff3d4799, 0x0063ce75, + 0xffb6f398, 0xff5138d1, 0x006e9e1f, + 0xff9186e5, 0xff5f96a4, 0x0076a86e, + 0xff82089c, 0xff676b81, 0x007b9f8a, + 0xff7c48a5, 0xff6a31e7, 0x007ebb7b, + 0x00000003//output gain +}; + +static u32 coef_16to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0000a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003//output gain +}; + +static u32 coef_16to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0024a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0000a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003//output gain +}; + +static u32 coef_22to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000001//output gain +}; + +static u32 coef_22to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_22to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_22to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_22to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_24to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//header + 0x000005e1,//input gain + 0x00dca92f, 0xff45647a, 0x0046b59c, + 0x00429d1e, 0xff4fec62, 0x00516d30, + 0xffdea779, 0xff5e08ba, 0x0060185e, + 0xffafbab2, 0xff698d5a, 0x006ce3ae, + 0xff9a82d2, 0xff704674, 0x007633c5, + 0xff923433, 0xff721128, 0x007cff42, + 0x00000001//output gain +}; + +static u32 coef_24to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_24to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000002,//output gain + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_24to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000002,//output gain + 0x001b6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x00265204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_24to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_24to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001//output gain +}; + +static u32 coef_24to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_24to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x002f0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001//output gain +}; + +static u32 coef_24to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_24to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_24to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_32to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000ca102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000003,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x0000d102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_32to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000fa103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000003,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000ca102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000003,//output gain + 0x0000d102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_32to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_32to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0015a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003,//output gain + 0x00005105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_32to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001//output gain +}; + +static u32 coef_32to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003//output gain +}; + +static u32 coef_32to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_32to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0000a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003//output gain +}; + +static u32 coef_44to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00120104,//IIR Filter + 0x00000af2,//input gain + 0x0057eebe, 0xff1e9863, 0x00652604, + 0xff7206ea, 0xff22ad7e, 0x006d47e1, + 0xff42a4d7, 0xff26e722, 0x0075fd83, + 0xff352f66, 0xff29312b, 0x007b986b, + 0xff310a07, 0xff296f51, 0x007eca7c, + 0x00000001,//output gain + 0x001d9204,//Farrow Filter + decimation + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_44to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00126104,//IIR Filter + interpolation + 0x00000af2,//input gain + 0x0057eebe, 0xff1e9863, 0x00652604, + 0xff7206ea, 0xff22ad7e, 0x006d47e1, + 0xff42a4d7, 0xff26e722, 0x0075fd83, + 0xff352f66, 0xff29312b, 0x007b986b, + 0xff310a07, 0xff296f51, 0x007eca7c, + 0x00000002,//output gain + 0x001d9204,//Farrow Filter + decimation + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_44to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000001//output gain +}; + +static u32 coef_44to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_44to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_44to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_44to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_48to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//IIR Filter + Decimator + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000001,//output gain + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_48to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//IIR Filter + Decimator + 0x00000784,//input gain + 0x00cc516e, 0xff2c9639, 0x005ad5b3, + 0x0013ad0d, 0xff3d4799, 0x0063ce75, + 0xffb6f398, 0xff5138d1, 0x006e9e1f, + 0xff9186e5, 0xff5f96a4, 0x0076a86e, + 0xff82089c, 0xff676b81, 0x007b9f8a, + 0xff7c48a5, 0xff6a31e7, 0x007ebb7b, + 0x00000001//output gain +}; + +static u32 coef_48to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000002,//output gain + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_48to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000002,//output gain + 0x001b6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x00265204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001//output gain +}; + +static u32 coef_48to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_48to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x002f0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001//output gain +}; + +static u32 coef_48to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_88to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000057,//input gain + 0x00a8e717, 0xff1c748d, 0x0065b976, + 0xffcbccab, 0xff190aff, 0x006cc1cf, + 0xff871ce1, 0xff10d878, 0x0078cfc5, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_88to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_88to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00186102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_96to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_96to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_96to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001b6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00260204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001//output gain +}; + +static u32 coef_96to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002//output gain +}; + +static u32 coef_176to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000057,//input gain + 0x00a8e717, 0xff1c748d, 0x0065b976, + 0xffcbccab, 0xff190aff, 0x006cc1cf, + 0xff871ce1, 0xff10d878, 0x0078cfc5, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_176to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000001//output gain +}; + +static u32 coef_176to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_192to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_192to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000001//output gain +}; + +static u32 coef_192to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00170204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001//output gain +}; + +/* + * Coefficient table for various sample rate conversions. The sample + * rates available are as per tegra210_sfc_rates[]. + */ +static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { + /* Convertions from 8 kHz */ + { + BYPASS_CONV, + coef_8to11, + coef_8to16, + coef_8to22, + coef_8to24, + coef_8to32, + coef_8to44, + coef_8to48, + coef_8to88, + coef_8to96, + UNSUPP_CONV, + UNSUPP_CONV, + }, + /* Convertions from 11.025 kHz */ + { + coef_11to8, + BYPASS_CONV, + coef_11to16, + coef_11to22, + coef_11to24, + coef_11to32, + coef_11to44, + coef_11to48, + coef_11to88, + coef_11to96, + UNSUPP_CONV, + UNSUPP_CONV, + }, + /* Convertions from 16 kHz */ + { + coef_16to8, + coef_16to11, + BYPASS_CONV, + coef_16to22, + coef_16to24, + coef_16to32, + coef_16to44, + coef_16to48, + coef_16to88, + coef_16to96, + coef_16to176, + coef_16to192, + }, + /* Convertions from 22.05 kHz */ + { + coef_22to8, + coef_22to11, + coef_22to16, + BYPASS_CONV, + coef_22to24, + coef_22to32, + coef_22to44, + coef_22to48, + coef_22to88, + coef_22to96, + coef_22to176, + coef_22to192, + }, + /* Convertions from 24 kHz */ + { + coef_24to8, + coef_24to11, + coef_24to16, + coef_24to22, + BYPASS_CONV, + coef_24to32, + coef_24to44, + coef_24to48, + coef_24to88, + coef_24to96, + coef_24to176, + coef_24to192, + }, + /* Convertions from 32 kHz */ + { + coef_32to8, + coef_32to11, + coef_32to16, + coef_32to22, + coef_32to24, + BYPASS_CONV, + coef_32to44, + coef_32to48, + coef_32to88, + coef_32to96, + coef_32to176, + coef_32to192, + }, + /* Convertions from 44.1 kHz */ + { + coef_44to8, + coef_44to11, + coef_44to16, + coef_44to22, + coef_44to24, + coef_44to32, + BYPASS_CONV, + coef_44to48, + coef_44to88, + coef_44to96, + coef_44to176, + coef_44to192, + }, + /* Convertions from 48 kHz */ + { + coef_48to8, + coef_48to11, + coef_48to16, + coef_48to22, + coef_48to24, + coef_48to32, + coef_48to44, + BYPASS_CONV, + coef_48to88, + coef_48to96, + coef_48to176, + coef_48to192, + }, + /* Convertions from 88.2 kHz */ + { + coef_88to8, + coef_88to11, + coef_88to16, + coef_88to22, + coef_88to24, + coef_88to32, + coef_88to44, + coef_88to48, + BYPASS_CONV, + coef_88to96, + coef_88to176, + coef_88to192, + }, + /* Convertions from 96 kHz */ + { coef_96to8, + coef_96to11, + coef_96to16, + coef_96to22, + coef_96to24, + coef_96to32, + coef_96to44, + coef_96to48, + coef_96to88, + BYPASS_CONV, + coef_96to176, + coef_96to192, + }, + /* Convertions from 176.4 kHz */ + { + UNSUPP_CONV, + UNSUPP_CONV, + coef_176to16, + coef_176to22, + coef_176to24, + coef_176to32, + coef_176to44, + coef_176to48, + coef_176to88, + coef_176to96, + BYPASS_CONV, + coef_176to192, + }, + /* Convertions from 192 kHz */ + { + UNSUPP_CONV, + UNSUPP_CONV, + coef_192to16, + coef_192to22, + coef_192to24, + coef_192to32, + coef_192to44, + coef_192to48, + coef_192to88, + coef_192to96, + coef_192to176, + BYPASS_CONV, + }, +}; + +static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(dev); + + regcache_cache_only(sfc->regmap, true); + regcache_mark_dirty(sfc->regmap); + + return 0; +} + +static int __maybe_unused tegra210_sfc_runtime_resume(struct device *dev) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(dev); + + regcache_cache_only(sfc->regmap, false); + regcache_sync(sfc->regmap); + + return 0; +} + +static inline void tegra210_sfc_write_ram(struct regmap *regmap, + s32 *data) +{ + int i; + + regmap_write(regmap, TEGRA210_SFC_CFG_RAM_CTRL, + TEGRA210_SFC_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_SFC_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_SFC_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_SFC_COEF_RAM_DEPTH; i++) + regmap_write(regmap, TEGRA210_SFC_CFG_RAM_DATA, data[i]); +} + +static int tegra210_sfc_write_coeff_ram(struct snd_soc_component *cmpnt) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(cmpnt->dev); + s32 *coeff_ram; + + /* Bypass */ + if (sfc->srate_in == sfc->srate_out) + return 0; + + coeff_ram = coef_addr_table[sfc->srate_in][sfc->srate_out]; + if (IS_ERR_OR_NULL(coeff_ram)) { + dev_err(cmpnt->dev, + "Conversion from %d to %d Hz is not supported\n", + sfc->srate_in, sfc->srate_out); + + return PTR_ERR_OR_ZERO(coeff_ram); + } + + tegra210_sfc_write_ram(sfc->regmap, coeff_ram); + + regmap_update_bits(sfc->regmap, + TEGRA210_SFC_COEF_RAM, + TEGRA210_SFC_COEF_RAM_EN, + TEGRA210_SFC_COEF_RAM_EN); + + return 0; +} + +static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + unsigned int channels, audio_bits, path; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + 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 -EOPNOTSUPP; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = TEGRA_ACIF_BITS_32; + + if (reg == TEGRA210_SFC_RX_CIF_CTRL) + path = SFC_RX_PATH; + else + path = SFC_TX_PATH; + + cif_conf.stereo_conv = sfc->stereo_to_mono[path]; + cif_conf.mono_conv = sfc->mono_to_stereo[path]; + + tegra_set_cif(sfc->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_sfc_soft_reset(struct tegra210_sfc *sfc) +{ + u32 val; + + /* + * Soft Reset: Below performs module soft reset which clears + * all FSM logic, flushes flow control of FIFO and resets the + * state register. It also brings module back to disabled + * state (without flushing the data in the pipe). + */ + regmap_update_bits(sfc->regmap, TEGRA210_SFC_SOFT_RESET, + TEGRA210_SFC_SOFT_RESET_EN, 1); + + return regmap_read_poll_timeout(sfc->regmap, + TEGRA210_SFC_SOFT_RESET, + val, + !(val & TEGRA210_SFC_SOFT_RESET_EN), + 10, 10000); +} + +static int tegra210_sfc_rate_to_idx(struct device *dev, int rate, + int *rate_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tegra210_sfc_rates); i++) { + if (rate == tegra210_sfc_rates[i]) { + *rate_idx = i; + + return 0; + } + } + + dev_err(dev, "Sample rate %d Hz is not supported\n", rate); + + return -EOPNOTSUPP; +} + +static int tegra210_sfc_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + int err; + + regmap_update_bits(sfc->regmap, TEGRA210_SFC_COEF_RAM, + TEGRA210_SFC_COEF_RAM_EN, 0); + + err = tegra210_sfc_soft_reset(sfc); + if (err < 0) { + dev_err(dai->dev, "Failed to reset SFC in %s, err = %d\n", + __func__, err); + + return err; + } + + return 0; +} + +static int tegra210_sfc_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + struct device *dev = dai->dev; + int err; + + err = tegra210_sfc_rate_to_idx(dev, params_rate(params), + &sfc->srate_in); + if (err < 0) + return err; + + err = tegra210_sfc_set_audio_cif(sfc, params, TEGRA210_SFC_RX_CIF_CTRL); + if (err < 0) { + dev_err(dev, "Can't set SFC RX CIF: %d\n", err); + return err; + } + + regmap_write(sfc->regmap, TEGRA210_SFC_RX_FREQ, sfc->srate_in); + + return err; +} + +static int tegra210_sfc_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + struct device *dev = dai->dev; + int err; + + err = tegra210_sfc_rate_to_idx(dev, params_rate(params), + &sfc->srate_out); + if (err < 0) + return err; + + err = tegra210_sfc_set_audio_cif(sfc, params, TEGRA210_SFC_TX_CIF_CTRL); + if (err < 0) { + dev_err(dev, "Can't set SFC TX CIF: %d\n", err); + return err; + } + + regmap_write(sfc->regmap, TEGRA210_SFC_TX_FREQ, sfc->srate_out); + + return 0; +} + +static int tegra210_sfc_init(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + + return tegra210_sfc_write_coeff_ram(cmpnt); +} + +static int tegra210_sfc_get_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt); + + if (strstr(kcontrol->id.name, "Input Stereo To Mono")) + ucontrol->value.integer.value[0] = + sfc->stereo_to_mono[SFC_RX_PATH]; + else if (strstr(kcontrol->id.name, "Input Mono To Stereo")) + ucontrol->value.integer.value[0] = + sfc->mono_to_stereo[SFC_RX_PATH]; + else if (strstr(kcontrol->id.name, "Output Stereo To Mono")) + ucontrol->value.integer.value[0] = + sfc->stereo_to_mono[SFC_TX_PATH]; + else if (strstr(kcontrol->id.name, "Output Mono To Stereo")) + ucontrol->value.integer.value[0] = + sfc->mono_to_stereo[SFC_TX_PATH]; + + return 0; +} + +static int tegra210_sfc_put_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt); + int value = ucontrol->value.integer.value[0]; + + if (strstr(kcontrol->id.name, "Input Stereo To Mono")) + sfc->stereo_to_mono[SFC_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Input Mono To Stereo")) + sfc->mono_to_stereo[SFC_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Output Stereo To Mono")) + sfc->stereo_to_mono[SFC_TX_PATH] = value; + else if (strstr(kcontrol->id.name, "Output Mono To Stereo")) + sfc->mono_to_stereo[SFC_TX_PATH] = value; + else + return 0; + + return 1; +} + +static const struct snd_soc_dai_ops tegra210_sfc_in_dai_ops = { + .hw_params = tegra210_sfc_in_hw_params, + .startup = tegra210_sfc_startup, +}; + +static const struct snd_soc_dai_ops tegra210_sfc_out_dai_ops = { + .hw_params = tegra210_sfc_out_hw_params, +}; + +static struct snd_soc_dai_driver tegra210_sfc_dais[] = { + { + .name = "SFC-RX-CIF", + .playback = { + .stream_name = "RX-CIF-Playback", + .channels_min = 1, + .channels_max = 2, + .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 = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_sfc_in_dai_ops, + }, + { + .name = "SFC-TX-CIF", + .playback = { + .stream_name = "TX-CIF-Playback", + .channels_min = 1, + .channels_max = 2, + .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 = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_sfc_out_dai_ops, + }, +}; + +static const struct snd_soc_dapm_widget tegra210_sfc_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_SFC_ENABLE, + TEGRA210_SFC_EN_SHIFT, 0, + tegra210_sfc_init, SND_SOC_DAPM_PRE_PMU), +}; + +#define RESAMPLE_ROUTE(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_sfc_routes[] = { + { "TX", NULL, "RX" }, + RESAMPLE_ROUTE("Playback"), + RESAMPLE_ROUTE("Capture"), +}; + +static const char * const tegra210_sfc_stereo_conv_text[] = { + "CH0", "CH1", "AVG", +}; + +static const char * const tegra210_sfc_mono_conv_text[] = { + "Zero", "Copy", +}; + +static const struct soc_enum tegra210_sfc_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_stereo_conv_text), + tegra210_sfc_stereo_conv_text); + +static const struct soc_enum tegra210_sfc_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_mono_conv_text), + tegra210_sfc_mono_conv_text); + +static const struct snd_kcontrol_new tegra210_sfc_controls[] = { + SOC_ENUM_EXT("Input Stereo To Mono", tegra210_sfc_stereo_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Input Mono To Stereo", tegra210_sfc_mono_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Output Stereo To Mono", tegra210_sfc_stereo_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Output Mono To Stereo", tegra210_sfc_mono_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), +}; + +static const struct snd_soc_component_driver tegra210_sfc_cmpnt = { + .dapm_widgets = tegra210_sfc_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_sfc_widgets), + .dapm_routes = tegra210_sfc_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_sfc_routes), + .controls = tegra210_sfc_controls, + .num_controls = ARRAY_SIZE(tegra210_sfc_controls), +}; + +static bool tegra210_sfc_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_INT_MASK ... TEGRA210_SFC_RX_FREQ: + case TEGRA210_SFC_TX_INT_MASK ... TEGRA210_SFC_TX_FREQ: + case TEGRA210_SFC_ENABLE ... TEGRA210_SFC_CG: + case TEGRA210_SFC_COEF_RAM ... TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_STATUS ... TEGRA210_SFC_RX_FREQ: + case TEGRA210_SFC_TX_STATUS ... TEGRA210_SFC_TX_FREQ: + case TEGRA210_SFC_ENABLE ... TEGRA210_SFC_INT_STATUS: + case TEGRA210_SFC_COEF_RAM ... TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_STATUS: + case TEGRA210_SFC_RX_INT_STATUS: + case TEGRA210_SFC_RX_INT_SET: + + case TEGRA210_SFC_TX_STATUS: + case TEGRA210_SFC_TX_INT_STATUS: + case TEGRA210_SFC_TX_INT_SET: + + case TEGRA210_SFC_SOFT_RESET: + case TEGRA210_SFC_STATUS: + case TEGRA210_SFC_INT_STATUS: + case TEGRA210_SFC_CFG_RAM_CTRL: + case TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_sfc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_SFC_CFG_RAM_DATA, + .writeable_reg = tegra210_sfc_wr_reg, + .readable_reg = tegra210_sfc_rd_reg, + .volatile_reg = tegra210_sfc_volatile_reg, + .precious_reg = tegra210_sfc_precious_reg, + .reg_defaults = tegra210_sfc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_sfc_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_sfc_of_match[] = { + { .compatible = "nvidia,tegra210-sfc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_sfc_of_match); + +static int tegra210_sfc_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_sfc *sfc; + void __iomem *regs; + int err; + + sfc = devm_kzalloc(dev, sizeof(*sfc), GFP_KERNEL); + if (!sfc) + return -ENOMEM; + + dev_set_drvdata(dev, sfc); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + sfc->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_sfc_regmap_config); + if (IS_ERR(sfc->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(sfc->regmap); + } + + regcache_cache_only(sfc->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_sfc_cmpnt, + tegra210_sfc_dais, + ARRAY_SIZE(tegra210_sfc_dais)); + if (err) { + dev_err(dev, "can't register SFC component, err: %d\n", err); + return err; + } + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int tegra210_sfc_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_sfc_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend, + tegra210_sfc_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_sfc_driver = { + .driver = { + .name = "tegra210-sfc", + .of_match_table = tegra210_sfc_of_match, + .pm = &tegra210_sfc_pm_ops, + }, + .probe = tegra210_sfc_platform_probe, + .remove = tegra210_sfc_platform_remove, +}; +module_platform_driver(tegra210_sfc_driver) + +MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); +MODULE_DESCRIPTION("Tegra210 SFC ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_sfc.h b/sound/soc/tegra/tegra210_sfc.h new file mode 100644 index 00000000000000..5a6b66e297d8f3 --- /dev/null +++ b/sound/soc/tegra/tegra210_sfc.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_sfc.h - Definitions for Tegra210 SFC driver + * + * Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_SFC_H__ +#define __TEGRA210_SFC_H__ + +/* + * SFC_RX registers are with respect to XBAR. + * The data comes from XBAR to SFC. + */ +#define TEGRA210_SFC_RX_STATUS 0x0c +#define TEGRA210_SFC_RX_INT_STATUS 0x10 +#define TEGRA210_SFC_RX_INT_MASK 0x14 +#define TEGRA210_SFC_RX_INT_SET 0x18 +#define TEGRA210_SFC_RX_INT_CLEAR 0x1c +#define TEGRA210_SFC_RX_CIF_CTRL 0x20 +#define TEGRA210_SFC_RX_FREQ 0x24 + +/* + * SFC_TX registers are with respect to XBAR. + * The data goes out of SFC. + */ +#define TEGRA210_SFC_TX_STATUS 0x4c +#define TEGRA210_SFC_TX_INT_STATUS 0x50 +#define TEGRA210_SFC_TX_INT_MASK 0x54 +#define TEGRA210_SFC_TX_INT_SET 0x58 +#define TEGRA210_SFC_TX_INT_CLEAR 0x5c +#define TEGRA210_SFC_TX_CIF_CTRL 0x60 +#define TEGRA210_SFC_TX_FREQ 0x64 + +/* Register offsets from TEGRA210_SFC*_BASE */ +#define TEGRA210_SFC_ENABLE 0x80 +#define TEGRA210_SFC_SOFT_RESET 0x84 +#define TEGRA210_SFC_CG 0x88 +#define TEGRA210_SFC_STATUS 0x8c +#define TEGRA210_SFC_INT_STATUS 0x90 +#define TEGRA210_SFC_COEF_RAM 0xbc +#define TEGRA210_SFC_CFG_RAM_CTRL 0xc0 +#define TEGRA210_SFC_CFG_RAM_DATA 0xc4 + +/* Fields in TEGRA210_SFC_ENABLE */ +#define TEGRA210_SFC_EN_SHIFT 0 +#define TEGRA210_SFC_EN (1 << TEGRA210_SFC_EN_SHIFT) + +#define TEGRA210_SFC_NUM_RATES 12 + +/* Fields in TEGRA210_SFC_COEF_RAM */ +#define TEGRA210_SFC_COEF_RAM_EN BIT(0) + +#define TEGRA210_SFC_SOFT_RESET_EN BIT(0) + +/* Coefficients */ +#define TEGRA210_SFC_COEF_RAM_DEPTH 64 +#define TEGRA210_SFC_RAM_CTRL_RW_WRITE (1 << 14) +#define TEGRA210_SFC_RAM_CTRL_ADDR_INIT_EN (1 << 13) +#define TEGRA210_SFC_RAM_CTRL_SEQ_ACCESS_EN (1 << 12) + + +enum tegra210_sfc_path { + SFC_RX_PATH, + SFC_TX_PATH, + SFC_PATHS, +}; + +struct tegra210_sfc { + unsigned int mono_to_stereo[SFC_PATHS]; + unsigned int stereo_to_mono[SFC_PATHS]; + unsigned int srate_out; + unsigned int srate_in; + struct regmap *regmap; +}; + +#endif diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 1d9fe3fca193b3..40110e9a9e8ab3 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -212,7 +212,7 @@ config SND_SOC_DM365_VOICE_CODEC Say Y if you want to add support for SoC On-chip voice codec endchoice -config SND_SOC_DM365_VOICE_CODEC_MODULE +config SND_SOC_DM365_SELECT_VOICE_CODECS def_tristate y depends on SND_SOC_DM365_VOICE_CODEC && SND_SOC select MFD_DAVINCI_VOICECODEC diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index b043a0070d2015..68d69e32681add 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -73,7 +73,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops evm_ops = { +static const struct snd_soc_ops evm_ops = { .startup = evm_startup, .shutdown = evm_shutdown, .hw_params = evm_hw_params, diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c index 2e3d1eea77c164..da809c7f25a44e 100644 --- a/sound/soc/ti/omap-abe-twl6040.c +++ b/sound/soc/ti/omap-abe-twl6040.c @@ -96,7 +96,7 @@ static int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops omap_abe_dmic_ops = { +static const struct snd_soc_ops omap_abe_dmic_ops = { .hw_params = omap_abe_dmic_hw_params, }; diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 2c39c7a2fd7dc4..3e654e708f78a6 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -348,7 +348,7 @@ static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream) return 0; } -struct snd_soc_ops mop500_ab8500_ops[] = { +const struct snd_soc_ops mop500_ab8500_ops[] = { { .hw_params = mop500_ab8500_hw_params, .hw_free = mop500_ab8500_hw_free, diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h index 8138a4e9aaf56d..087ef246d87daf 100644 --- a/sound/soc/ux500/mop500_ab8500.h +++ b/sound/soc/ux500/mop500_ab8500.h @@ -11,7 +11,7 @@ #ifndef MOP500_AB8500_H #define MOP500_AB8500_H -extern struct snd_soc_ops mop500_ab8500_ops[]; +extern const struct snd_soc_ops mop500_ab8500_ops[]; int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd); void mop500_ab8500_remove(struct snd_soc_card *card); |