diff options
175 files changed, 10400 insertions, 1912 deletions
diff --git a/Documentation/devicetree/bindings/sound/ak4458.txt b/Documentation/devicetree/bindings/sound/ak4458.txt index e5820235e0d5..8f6c84f21468 100644 --- a/Documentation/devicetree/bindings/sound/ak4458.txt +++ b/Documentation/devicetree/bindings/sound/ak4458.txt @@ -10,6 +10,8 @@ Required properties: Optional properties: - reset-gpios: A GPIO specifier for the power down & reset pin - mute-gpios: A GPIO specifier for the soft mute pin +- AVDD-supply: Analog power supply +- DVDD-supply: Digital power supply Example: diff --git a/Documentation/devicetree/bindings/sound/ak5558.txt b/Documentation/devicetree/bindings/sound/ak5558.txt index 7d67ca6ced80..36934098170c 100644 --- a/Documentation/devicetree/bindings/sound/ak5558.txt +++ b/Documentation/devicetree/bindings/sound/ak5558.txt @@ -10,6 +10,8 @@ Required properties: Optional properties: - reset-gpios: A GPIO specifier for the power down & reset pin. +- AVDD-supply: Analog power supply +- DVDD-supply: Digital power supply Example: diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml index 55d28268d2f4..67405e6d8168 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml @@ -15,7 +15,11 @@ properties: const: 0 compatible: - const: allwinner,sun8i-a33-codec + oneOf: + - items: + - const: allwinner,sun50i-a64-codec + - const: allwinner,sun8i-a33-codec + - const: allwinner,sun8i-a33-codec reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt deleted file mode 100644 index e1365b0ee1e9..000000000000 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ /dev/null @@ -1,68 +0,0 @@ -Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller - -The Freescale S/PDIF audio block is a stereo transceiver that allows the -processor to receive and transmit digital audio via an coaxial cable or -a fibre cable. - -Required properties: - - - compatible : Compatible list, should contain one of the following - compatibles: - "fsl,imx35-spdif", - "fsl,vf610-spdif", - "fsl,imx6sx-spdif", - - - reg : Offset and length of the register set for the device. - - - interrupts : Contains the spdif interrupt. - - - dmas : Generic dma devicetree binding as described in - Documentation/devicetree/bindings/dma/dma.txt. - - - dma-names : Two dmas have to be defined, "tx" and "rx". - - - clocks : Contains an entry for each entry in clock-names. - - - clock-names : Includes the following entries: - "core" The core clock of spdif controller. - "rxtx<0-7>" Clock source list for tx and rx clock. - This clock list should be identical to the source - list connecting to the spdif clock mux in "SPDIF - Transceiver Clock Diagram" of SoC reference manual. - It can also be referred to TxClk_Source bit of - register SPDIF_STC. - "spba" The spba clock is required when SPDIF is placed as a - bus slave of the Shared Peripheral Bus and when two - or more bus masters (CPU, DMA or DSP) try to access - it. This property is optional depending on the SoC - design. - -Optional properties: - - - big-endian : If this property is absent, the native endian mode - will be in use as default, or the big endian mode - will be in use for all the device registers. - -Example: - -spdif: spdif@2004000 { - compatible = "fsl,imx35-spdif"; - reg = <0x02004000 0x4000>; - interrupts = <0 52 0x04>; - dmas = <&sdma 14 18 0>, - <&sdma 15 18 0>; - dma-names = "rx", "tx"; - - clocks = <&clks 197>, <&clks 3>, - <&clks 197>, <&clks 107>, - <&clks 0>, <&clks 118>, - <&clks 62>, <&clks 139>, - <&clks 0>; - clock-names = "core", "rxtx0", - "rxtx1", "rxtx2", - "rxtx3", "rxtx4", - "rxtx5", "rxtx6", - "rxtx7"; - - big-endian; -}; diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml new file mode 100644 index 000000000000..2ac671f5cb9b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,spdif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller + +maintainers: + - Shengjiu Wang <[email protected]> + +description: | + The Freescale S/PDIF audio block is a stereo transceiver that allows the + processor to receive and transmit digital audio via an coaxial cable or + a fibre cable. + +properties: + compatible: + enum: + - fsl,imx35-spdif + - fsl,vf610-spdif + - fsl,imx6sx-spdif + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + dmas: + items: + - description: DMA controller phandle and request line for RX + - description: DMA controller phandle and request line for TX + + dma-names: + items: + - const: rx + - const: tx + + clocks: + items: + - description: The core clock of spdif controller. + - description: Clock for tx0 and rx0. + - description: Clock for tx1 and rx1. + - description: Clock for tx2 and rx2. + - description: Clock for tx3 and rx3. + - description: Clock for tx4 and rx4. + - description: Clock for tx5 and rx5. + - description: Clock for tx6 and rx6. + - description: Clock for tx7 and rx7. + - description: The spba clock is required when SPDIF is placed as a bus + slave of the Shared Peripheral Bus and when two or more bus masters + (CPU, DMA or DSP) try to access it. This property is optional depending + on the SoC design. + minItems: 9 + + clock-names: + items: + - const: core + - const: rxtx0 + - const: rxtx1 + - const: rxtx2 + - const: rxtx3 + - const: rxtx4 + - const: rxtx5 + - const: rxtx6 + - const: rxtx7 + - const: spba + minItems: 9 + + big-endian: + $ref: /schemas/types.yaml#/definitions/flag + description: | + If this property is absent, the native endian mode will be in use + as default, or the big endian mode will be in use for all the device + registers. Set this flag for HCDs with big endian descriptors and big + endian registers. + +required: + - compatible + - reg + - interrupts + - dmas + - dma-names + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + spdif@2004000 { + compatible = "fsl,imx35-spdif"; + reg = <0x02004000 0x4000>; + interrupts = <0 52 0x04>; + dmas = <&sdma 14 18 0>, + <&sdma 15 18 0>; + dma-names = "rx", "tx"; + clocks = <&clks 197>, <&clks 3>, + <&clks 197>, <&clks 107>, + <&clks 0>, <&clks 118>, + <&clks 62>, <&clks 139>, + <&clks 0>; + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7"; + big-endian; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt index 63ebf52b43e8..f339be62e7e4 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -38,6 +38,8 @@ The compatible list for this generic sound card currently: "fsl,imx-audio-wm8524" + "fsl,imx-audio-tlv320aic32x4" + Required properties: - compatible : Contains one of entries in the compatible list. diff --git a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml index 2e0bbc1c868a..bf4632c0a9b6 100644 --- a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - intel,keembay-i2s + - intel,keembay-tdm "#sound-dai-cells": const: 0 diff --git a/Documentation/devicetree/bindings/sound/mt6359.yaml b/Documentation/devicetree/bindings/sound/mt6359.yaml new file mode 100644 index 000000000000..a54f466f769d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt6359.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mt6359.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek MT6359 Codec Device Tree Bindings + +maintainers: + - Eason Yen <[email protected]> + - Jiaxin Yu <[email protected]> + - Shane Chien <[email protected]> + +description: | + The communication between MT6359 and SoC is through Mediatek PMIC wrapper. + For more detail, please visit Mediatek PMIC wrapper documentation. + Must be a child node of PMIC wrapper. + +properties: + mediatek,dmic-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Indicates how many data pins are used to transmit two channels of PDM + signal. 0 means two wires, 1 means one wire. Default value is 0. + enum: + - 0 # one wire + - 1 # two wires + + mediatek,mic-type-0: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Specifies the type of mic type connected to adc0 + + enum: + - 0 # IDLE - mic in turn-off status + - 1 # ACC - analog mic with alternating coupling + - 2 # DMIC - digital mic + - 3 # DCC - analog mic with direct couping + - 4 # DCC_ECM_DIFF - analog electret condenser mic with differential mode + - 5 # DCC_ECM_SINGLE - analog electret condenser mic with single mode + + mediatek,mic-type-1: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Specifies the type of mic type connected to adc1 + + mediatek,mic-type-2: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Specifies the type of mic type connected to adc2 + +additionalProperties: false + +examples: + - | + mt6359codec: mt6359codec { + mediatek,dmic-mode = <0>; + mediatek,mic-type-0 = <2>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt index 84b28dbe9f15..23998262a0a7 100644 --- a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt +++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt @@ -34,6 +34,13 @@ Required properties: * DMIC * Ext Spk +Optional properties: + +- aux-devs : A list of phandles for auxiliary devices (e.g. analog + amplifiers) that do not appear directly within the DAI + links. Should be connected to another audio component + using "qcom,audio-routing". + Dai-link subnode properties and subnodes: Required dai-link subnodes: diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt index c814e867850f..e1b9fa8a5bf8 100644 --- a/Documentation/devicetree/bindings/sound/qcom,apq8096.txt +++ b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt @@ -55,6 +55,14 @@ This binding describes the APQ8096 sound card, which uses qdsp for audio. Value type: <stringlist> Definition: The user-visible name of this sound card. +- aux-devs + Usage: optional + Value type: <array of phandles> + Definition: A list of phandles for auxiliary devices (e.g. analog + amplifiers) that do not appear directly within the DAI + links. Should be connected to another audio component + using "audio-routing". + = dailinks Each subnode of sndcard represents either a dailink, and subnodes of each dailinks would be cpu/codec/platform dais. diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt deleted file mode 100644 index 32c2cdb3d32f..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt +++ /dev/null @@ -1,79 +0,0 @@ -* Qualcomm Technologies LPASS CPU DAI - -This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS). - -Required properties: - -- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu" -- clocks : Must contain an entry for each entry in clock-names. -- clock-names : A list which must include the following entries: - * "ahbix-clk" - * "mi2s-osr-clk" - * "mi2s-bit-clk" - : required clocks for "qcom,lpass-cpu-apq8016" - * "ahbix-clk" - * "mi2s-bit-clk0" - * "mi2s-bit-clk1" - * "mi2s-bit-clk2" - * "mi2s-bit-clk3" - * "pcnoc-mport-clk" - * "pcnoc-sway-clk" - -- interrupts : Must contain an entry for each entry in - interrupt-names. -- interrupt-names : A list which must include the following entries: - * "lpass-irq-lpaif" -- pinctrl-N : One property must exist for each entry in - pinctrl-names. See ../pinctrl/pinctrl-bindings.txt - for details of the property values. -- pinctrl-names : Must contain a "default" entry. -- reg : Must contain an address for each entry in reg-names. -- reg-names : A list which must include the following entries: - * "lpass-lpaif" -- #address-cells : Must be 1 -- #size-cells : Must be 0 - - - -Optional properties: - -- qcom,adsp : Phandle for the audio DSP node - -By default, the driver uses up to 4 MI2S SD lines, for a total of 8 channels. -The SD lines to use can be configured by adding subnodes for each of the DAIs. - -Required properties for each DAI (represented by a subnode): -- reg : Must be one of the DAI IDs - (usually part of dt-bindings header) -- qcom,playback-sd-lines: List of serial data lines to use for playback - Each SD line should be represented by a number from 0-3. -- qcom,capture-sd-lines : List of serial data lines to use for capture - Each SD line should be represented by a number from 0-3. - -Note that adding a subnode changes the default to "no lines configured", -so both playback and capture lines should be configured when a subnode is added. - -Example: - -lpass@28100000 { - compatible = "qcom,lpass-cpu"; - clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>; - clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk"; - interrupts = <0 85 1>; - interrupt-names = "lpass-irq-lpaif"; - pinctrl-names = "default", "idle"; - pinctrl-0 = <&mi2s_default>; - pinctrl-1 = <&mi2s_idle>; - reg = <0x28100000 0x10000>; - reg-names = "lpass-lpaif"; - qcom,adsp = <&adsp>; - - #address-cells = <1>; - #size-cells = <0>; - - /* Optional to set different MI2S SD lines */ - dai@3 { - reg = <MI2S_QUATERNARY>; - qcom,playback-sd-lines = <0 1>; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml new file mode 100644 index 000000000000..09c9bd27fda4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,lpass-cpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies Inc. LPASS CPU dai driver bindings + +maintainers: + - Srinivas Kandagatla <[email protected]> + - Rohit kumar <[email protected]> + +description: | + Qualcomm Technologies Inc. SOC Low-Power Audio SubSystem (LPASS) that consist + of MI2S interface for audio data transfer on external codecs. LPASS cpu driver + is a module to configure Low-Power Audio Interface(LPAIF) core registers + across different IP versions. + +properties: + compatible: + enum: + - qcom,lpass-cpu + - qcom,apq8016-lpass-cpu + - qcom,sc7180-lpass-cpu + + reg: + maxItems: 1 + description: LPAIF core registers + + clocks: + minItems: 3 + maxItems: 6 + + clock-names: + minItems: 3 + maxItems: 6 + + interrupts: + maxItems: 1 + description: LPAIF DMA buffer interrupt + + qcom,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle for the audio DSP node + + iommus: + maxItems: 1 + description: Phandle to apps_smmu node with sid mask + + power-domains: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "(^mi2s-[0-9a-f]$|mi2s)": + type: object + description: Required properties for each DAI + + properties: + reg: + maxItems: 1 + description: Must be one of the DAI ID + + qcom,playback-sd-lines: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: list of MI2S data lines for playback + + qcom,capture-sd-lines: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: list of MI2S data lines for capture + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - '#sound-dai-cells' + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: qcom,lpass-cpu + + then: + properties: + clock-names: + items: + - const: ahbix-clk + - const: mi2s-osr-clk + - const: mi2s-bit-clk + + - if: + properties: + compatible: + contains: + const: qcom,apq8016-lpass-cpu + + then: + properties: + clock-names: + items: + - const: ahbix-clk + - const: mi2s-bit-clk0 + - const: mi2s-bit-clk1 + - const: mi2s-bit-clk2 + - const: mi2s-bit-clk3 + - const: pcnoc-mport-clk + - const: pcnoc-sway-clk + + - if: + properties: + compatible: + contains: + const: qcom,sc7180-lpass-cpu + + then: + properties: + clock-names: + items: + - const: pcnoc-sway-clk + - const: audio-core + - const: mclk0 + - const: pcnoc-mport-clk + - const: mi2s-bit-clk0 + - const: mi2s-bit-clk1 + required: + - iommus + - power-domains + +examples: + - | + #include <dt-bindings/sound/sc7180-lpass.h> + + soc { + #address-cells = <2>; + #size-cells = <2>; + lpass@62f00000 { + compatible = "qcom,sc7180-lpass-cpu"; + + reg = <0 0x62f00000 0 0x29000>; + + iommus = <&apps_smmu 0x1020 0>; + power-domains = <&lpass_hm 0>; + + clocks = <&gcc 131>, + <&lpasscorecc 6>, + <&lpasscorecc 7>, + <&lpasscorecc 10>, + <&lpasscorecc 8>, + <&lpasscorecc 9>; + + clock-names = "pcnoc-sway-clk", "audio-core", + "mclk0", "pcnoc-mport-clk", + "mi2s-bit-clk0", "mi2s-bit-clk1"; + + interrupts = <0 160 1>; + + #sound-dai-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + /* Optional to set different MI2S SD lines */ + mi2s-primary@0 { + reg = <MI2S_PRIMARY>; + qcom,playback-sd-lines = <1>; + qcom,capture-sd-lines = <0>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt index ca8c89e88bfa..de4c604641da 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt +++ b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt @@ -24,6 +24,14 @@ This binding describes the SDM845 sound card, which uses qdsp for audio. Value type: <stringlist> Definition: The user-visible name of this sound card. +- aux-devs + Usage: optional + Value type: <array of phandles> + Definition: A list of phandles for auxiliary devices (e.g. analog + amplifiers) that do not appear directly within the DAI + links. Should be connected to another audio component + using "audio-routing". + = dailinks Each subnode of sndcard represents either a dailink, and subnodes of each dailinks would be cpu/codec/platform dais. diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml index 7bad6f16fe60..62a61b68dfef 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml @@ -27,6 +27,7 @@ properties: - enum: - rockchip,rk3188-spdif - rockchip,rk3288-spdif + - rockchip,rk3308-spdif - const: rockchip,rk3066-spdif reg: diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index 1c755de686f7..578928e67e5c 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -21,7 +21,8 @@ properties: type: object properties: sound-dai: - $ref: /schemas/types.yaml#/definitions/phandle + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 description: phandle to the I2S controller required: - sound-dai @@ -30,7 +31,8 @@ properties: type: object properties: sound-dai: - $ref: /schemas/types.yaml#/definitions/phandle + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 description: phandle to the WM1811 CODEC required: - sound-dai diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml index 8ff2d39e7d17..e8122bc87362 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml @@ -28,6 +28,11 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: The user-visible name of this sound complex. + assigned-clock-parents: true + assigned-clock-rates: true + assigned-clocks: true + clocks: true + cpu: type: object properties: diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml index b2ad093d94df..2e3628ef48df 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml @@ -41,6 +41,12 @@ properties: - samsung,exynos7-i2s - samsung,exynos7-i2s1 + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + reg: maxItems: 1 @@ -58,6 +64,9 @@ properties: - const: rx - const: tx-sec + assigned-clock-parents: true + assigned-clocks: true + clocks: minItems: 1 maxItems: 3 @@ -92,6 +101,9 @@ properties: - const: i2s_cdclk2 description: Names of the CDCLK I2S output clocks. + interrupts: + maxItems: 1 + samsung,idma-addr: $ref: /schemas/types.yaml#/definitions/uint32 description: | @@ -104,6 +116,9 @@ properties: pinctrl-names: const: default + power-domains: + maxItems: 1 + "#sound-dai-cells": const: 1 diff --git a/Documentation/devicetree/bindings/sound/tas2562.txt b/Documentation/devicetree/bindings/sound/tas2562.txt deleted file mode 100644 index dc6d7362ded7..000000000000 --- a/Documentation/devicetree/bindings/sound/tas2562.txt +++ /dev/null @@ -1,37 +0,0 @@ -Texas Instruments TAS2562 Smart PA - -The TAS2562 is a mono, digital input Class-D audio amplifier optimized for -efficiently driving high peak power into small loudspeakers. -Integrated speaker voltage and current sense provides for -real time monitoring of loudspeaker behavior. - -Required properties: - - #address-cells - Should be <1>. - - #size-cells - Should be <0>. - - compatible: - Should contain "ti,tas2562", "ti,tas2563". - - reg: - The i2c address. Should be 0x4c, 0x4d, 0x4e or 0x4f. - - ti,imon-slot-no:- TDM TX current sense time slot. - - ti,vmon-slot-no:- TDM TX voltage sense time slot. This slot must always be - greater then ti,imon-slot-no. - -Optional properties: -- interrupt-parent: phandle to the interrupt controller which provides - the interrupt. -- interrupts: (GPIO) interrupt to which the chip is connected. -- shut-down-gpio: GPIO used to control the state of the device. - -Examples: -tas2562@4c { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,tas2562"; - reg = <0x4c>; - - interrupt-parent = <&gpio1>; - interrupts = <14>; - - shut-down-gpio = <&gpio1 15 0>; - ti,imon-slot-no = <0>; - ti,vmon-slot-no = <1>; -}; - diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml index 8d75a798740b..c3b7e19a0d44 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/tas2562.yaml @@ -16,6 +16,10 @@ description: | Integrated speaker voltage and current sense provides for real time monitoring of loudspeaker behavior. + Specifications about the audio amplifier can be found at: + https://www.ti.com/lit/gpn/tas2562 + https://www.ti.com/lit/gpn/tas2563 + properties: compatible: enum: diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index 594901f3b8e5..526fd0933289 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/init.h> +#include <linux/gpio/machine.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> #include <linux/workqueue.h> @@ -474,6 +475,20 @@ static struct platform_device gta02_buttons_device = { }, }; +static struct gpiod_lookup_table gta02_audio_gpio_table = { + .dev_id = "neo1973-audio", + .table = { + GPIO_LOOKUP("GPIOJ", 2, "amp-shut", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOJ", 1, "hp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device gta02_audio = { + .name = "neo1973-audio", + .id = -1, +}; + static void __init gta02_map_io(void) { s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); @@ -498,6 +513,7 @@ static struct platform_device *gta02_devices[] __initdata = { >a02_buttons_device, &s3c_device_adc, &s3c_device_ts, + >a02_audio, }; static void gta02_poweroff(void) @@ -524,6 +540,7 @@ static void __init gta02_machine_init(void) i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs)); + gpiod_add_lookup_table(>a02_audio_gpio_table); platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices)); pm_power_off = gta02_poweroff; diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index f4710052843a..ecb84029e15c 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -475,6 +475,22 @@ static struct gpiod_lookup_table h1940_mmc_gpio_table = { }, }; +static struct gpiod_lookup_table h1940_audio_gpio_table = { + .dev_id = "h1940-audio", + .table = { + GPIO_LOOKUP("H1940_LATCH", + H1940_LATCH_AUDIO_POWER - H1940_LATCH_GPIO(0), + "speaker-power", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 4, "hp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device h1940_audio = { + .name = "h1940-audio", + .id = -1, +}; + static struct pwm_lookup h1940_pwm_lookup[] = { PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296, PWM_POLARITY_NORMAL), @@ -651,6 +667,7 @@ static struct platform_device *h1940_devices[] __initdata = { &s3c_device_ts, &power_supply, &h1940_battery, + &h1940_audio, }; static void __init h1940_map_io(void) @@ -690,6 +707,7 @@ static void __init h1940_init(void) s3c24xx_fb_set_platdata(&h1940_fb_info); gpiod_add_lookup_table(&h1940_mmc_gpio_table); + gpiod_add_lookup_table(&h1940_audio_gpio_table); s3c24xx_mci_set_platdata(&h1940_mmc_cfg); s3c24xx_udc_set_platdata(&h1940_udc_cfg); s3c24xx_ts_set_platdata(&h1940_ts_cfg); diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index fde98b175c75..e9806bf654b4 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -728,6 +728,20 @@ static struct i2c_board_info rx1950_i2c_devices[] = { }, }; +static struct gpiod_lookup_table rx1950_audio_gpio_table = { + .dev_id = "rx1950-audio", + .table = { + GPIO_LOOKUP("GPIOG", 12, "hp-gpio", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOA", 1, "speaker-power", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device rx1950_audio = { + .name = "rx1950-audio", + .id = -1, +}; + static struct platform_device *rx1950_devices[] __initdata = { &s3c2410_device_dclk, &s3c_device_lcd, @@ -746,6 +760,7 @@ static struct platform_device *rx1950_devices[] __initdata = { &power_supply, &rx1950_battery, &rx1950_leds, + &rx1950_audio, }; static void __init rx1950_map_io(void) @@ -813,6 +828,7 @@ static void __init rx1950_init_machine(void) gpio_direction_output(S3C2410_GPJ(6), 0); pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup)); + gpiod_add_lookup_table(&rx1950_audio_gpio_table); platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices)); i2c_register_board_info(0, rx1950_i2c_devices, diff --git a/include/dt-bindings/sound/sc7180-lpass.h b/include/dt-bindings/sound/sc7180-lpass.h new file mode 100644 index 000000000000..7d988f6346a5 --- /dev/null +++ b/include/dt-bindings/sound/sc7180-lpass.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_SC7180_LPASS_H +#define __DT_SC7180_LPASS_H + +#define MI2S_PRIMARY 0 +#define MI2S_SECONDARY 1 + +#define LPASS_MCLK0 0 + +#endif /* __DT_APQ8016_LPASS_H */ diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 057d2a2d0bd0..4f987b1f32f7 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -119,7 +119,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_VS_EM3U 0x103C #define AZX_REG_VS_EM4L 0x1040 #define AZX_REG_VS_EM4U 0x1044 -#define AZX_REG_VS_LTRC 0x1048 +#define AZX_REG_VS_LTRP 0x1048 #define AZX_REG_VS_D0I3C 0x104A #define AZX_REG_VS_PCE 0x104B #define AZX_REG_VS_L2MAGC 0x1050 diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index d2e9e3b4d7ea..b77b05c413a3 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -58,7 +58,7 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * snd_soc_acpi_mach_params: interface for machine driver configuration * * @acpi_ipc_irq_index: used for BYT-CR detection - * @platform: string used for HDaudio codec support + * @platform: string used for HDAudio codec support * @codec_mask: used for HDAudio support * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver * @link_mask: links enabled on the board diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 776a60529e70..8b693dade9c6 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -471,7 +471,8 @@ static inline int snd_soc_dai_set_sdw_stream(struct snd_soc_dai *dai, * This routine only retrieves that was previously configured * with snd_soc_dai_get_sdw_stream() * - * Returns pointer to stream or -ENOTSUPP if callback is not supported; + * Returns pointer to stream or an ERR_PTR value, e.g. + * ERR_PTR(-ENOTSUPP) if callback is not supported; */ static inline void *snd_soc_dai_get_sdw_stream(struct snd_soc_dai *dai, int direction) diff --git a/include/sound/soc.h b/include/sound/soc.h index 5e3919ffb00c..b94ebff12350 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1331,6 +1331,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); +int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, struct device_node **bitclkmaster, @@ -1361,6 +1362,8 @@ void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( const struct snd_soc_dai_link_component *dlc); +struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc); #include <sound/soc-dai.h> diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index 04359cda92dc..342e86e54db5 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -60,6 +60,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_FW_VERSION = 0, SOF_EXT_MAN_ELEM_WINDOW = SOF_IPC_EXT_WINDOW, SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, + SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, }; /* extended manifest element header */ @@ -92,4 +93,10 @@ struct sof_ext_man_cc_version { struct sof_ipc_cc_version cc_version; } __packed; +struct ext_man_dbg_abi { + struct sof_ext_man_elem_header hdr; + /* use sof_ipc struct because of code re-use */ + struct sof_ipc_user_abi_version dbg_abi; +} __packed; + #endif /* __SOF_FIRMWARE_EXT_MANIFEST_H__ */ diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index 5a55ba8b7e56..313e3e70c630 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -99,7 +99,7 @@ struct sof_ipc_window_elem { struct sof_ipc_window { struct sof_ipc_ext_data_hdr ext_hdr; uint32_t num_windows; - struct sof_ipc_window_elem window[]; + struct sof_ipc_window_elem window[SOF_IPC_MAX_ELEMS]; } __packed; struct sof_ipc_cc_version { diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index f56e80d09b32..d12736e14b69 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -57,8 +57,8 @@ struct sof_ipc_comp { uint32_t pipeline_id; uint32_t core; - /* reserved for future use */ - uint32_t reserved[1]; + /* extended data length, 0 if no extended data */ + uint32_t ext_data_length; } __packed; /* @@ -87,6 +87,9 @@ struct sof_ipc_comp { */ #define SOF_BUF_UNDERRUN_PERMITTED BIT(1) +/* the UUID size in bytes, shared between FW and host */ +#define SOF_UUID_SIZE 16 + /* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ struct sof_ipc_buffer { struct sof_ipc_comp comp; @@ -300,4 +303,9 @@ enum sof_event_types { SOF_KEYWORD_DETECT_DAPM_EVENT, }; +/* extended data struct for UUID components */ +struct sof_ipc_comp_ext { + uint8_t uuid[SOF_UUID_SIZE]; +} __packed; + #endif diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index d54be303090f..6af32f82fb99 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 16 +#define SOF_ABI_MINOR 17 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 5941e2eb1588..a642bf30c027 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -24,6 +24,9 @@ #define SOF_TPLG_KCTL_ENUM_ID 257 #define SOF_TPLG_KCTL_BYTES_ID 258 #define SOF_TPLG_KCTL_SWITCH_ID 259 +#define SOF_TPLG_KCTL_BYTES_VOLATILE_RO 260 +#define SOF_TPLG_KCTL_BYTES_VOLATILE_RW 261 +#define SOF_TPLG_KCTL_BYTES_WO_ID 262 /* * Tokens - must match values in topology configurations @@ -73,6 +76,8 @@ /* Token retired with ABI 3.2, do not use for new capabilities * #define SOF_TKN_COMP_PRELOAD_COUNT 403 */ +#define SOF_TKN_COMP_CORE_ID 404 +#define SOF_TKN_COMP_UUID 405 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 406526e79af3..1a4e8ca0f99c 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -472,12 +472,17 @@ static int acp3x_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "devm_snd_soc_register_card(%s) failed: %d\n", card->name, ret); - return ret; + else + dev_dbg(&pdev->dev, + "devm_snd_soc_register_card(%s) probe deferred: %d\n", + card->name, ret); } - return 0; + + return ret; } static const struct acpi_device_id acp3x_audio_acpi_match[] = { diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 946a70210f49..e6c71ca0cd9b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -127,6 +127,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ML26124 imply SND_SOC_MT6351 imply SND_SOC_MT6358 + imply SND_SOC_MT6359 imply SND_SOC_MT6660 imply SND_SOC_NAU8540 imply SND_SOC_NAU8810 @@ -1724,6 +1725,13 @@ config SND_SOC_MT6358 Enable support for the platform which uses MT6358 as external codec device. +config SND_SOC_MT6359 + tristate "MediaTek MT6359 Codec" + depends on MTK_PMIC_WRAP + help + Enable support for the platform which uses MT6359 as + external codec device. + config SND_SOC_MT6660 tristate "Mediatek MT6660 Speaker Amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0140c60db695..9a3f58c1069a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -126,6 +126,7 @@ snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o snd-soc-mt6358-objs := mt6358.o +snd-soc-mt6359-objs := mt6359.o snd-soc-mt6660-objs := mt6660.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o @@ -431,6 +432,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o +obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index cbe3c782e0ca..763e6839428f 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -12,6 +12,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/initval.h> #include <sound/pcm_params.h> @@ -21,6 +22,12 @@ #include "ak4458.h" +#define AK4458_NUM_SUPPLIES 2 +static const char *ak4458_supply_names[AK4458_NUM_SUPPLIES] = { + "DVDD", + "AVDD", +}; + struct ak4458_drvdata { struct snd_soc_dai_driver *dai_drv; const struct snd_soc_component_driver *comp_drv; @@ -28,6 +35,7 @@ struct ak4458_drvdata { /* AK4458 Codec Private Data */ struct ak4458_priv { + struct regulator_bulk_data supplies[AK4458_NUM_SUPPLIES]; struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpiod; @@ -587,12 +595,22 @@ static int __maybe_unused ak4458_runtime_suspend(struct device *dev) if (ak4458->mute_gpiod) gpiod_set_value_cansleep(ak4458->mute_gpiod, 0); + regulator_bulk_disable(ARRAY_SIZE(ak4458->supplies), + ak4458->supplies); return 0; } static int __maybe_unused ak4458_runtime_resume(struct device *dev) { struct ak4458_priv *ak4458 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ak4458->supplies), + ak4458->supplies); + if (ret != 0) { + dev_err(ak4458->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } if (ak4458->mute_gpiod) gpiod_set_value_cansleep(ak4458->mute_gpiod, 1); @@ -667,7 +685,7 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) { struct ak4458_priv *ak4458; const struct ak4458_drvdata *drvdata; - int ret; + int ret, i; ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL); if (!ak4458) @@ -692,6 +710,16 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) if (IS_ERR(ak4458->mute_gpiod)) return PTR_ERR(ak4458->mute_gpiod); + for (i = 0; i < ARRAY_SIZE(ak4458->supplies); i++) + ak4458->supplies[i].supply = ak4458_supply_names[i]; + + ret = devm_regulator_bulk_get(ak4458->dev, ARRAY_SIZE(ak4458->supplies), + ak4458->supplies); + if (ret != 0) { + dev_err(ak4458->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + ret = devm_snd_soc_register_component(ak4458->dev, drvdata->comp_drv, drvdata->dai_drv, 1); if (ret < 0) { @@ -700,6 +728,7 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) } pm_runtime_enable(&i2c->dev); + regcache_cache_only(ak4458->regmap, true); return 0; } diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 8179512129d3..2f076d5ee284 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/initval.h> @@ -22,8 +23,15 @@ #include "ak5558.h" +#define AK5558_NUM_SUPPLIES 2 +static const char *ak5558_supply_names[AK5558_NUM_SUPPLIES] = { + "DVDD", + "AVDD", +}; + /* AK5558 Codec Private Data */ struct ak5558_priv { + struct regulator_bulk_data supplies[AK5558_NUM_SUPPLIES]; struct snd_soc_component component; struct regmap *regmap; struct i2c_client *i2c; @@ -299,12 +307,22 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev) regcache_cache_only(ak5558->regmap, true); ak5558_power_off(ak5558); + regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies), + ak5558->supplies); return 0; } static int __maybe_unused ak5558_runtime_resume(struct device *dev) { struct ak5558_priv *ak5558 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ak5558->supplies), + ak5558->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } ak5558_power_off(ak5558); ak5558_power_on(ak5558); @@ -350,6 +368,7 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) { struct ak5558_priv *ak5558; int ret = 0; + int i; ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL); if (!ak5558) @@ -367,6 +386,16 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) if (IS_ERR(ak5558->reset_gpiod)) return PTR_ERR(ak5558->reset_gpiod); + for (i = 0; i < ARRAY_SIZE(ak5558->supplies); i++) + ak5558->supplies[i].supply = ak5558_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(ak5558->supplies), + ak5558->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_ak5558, &ak5558_dai, 1); @@ -374,6 +403,7 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) return ret; pm_runtime_enable(&i2c->dev); + regcache_cache_only(ak5558->regmap, true); return 0; } diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index b1dfd91609f7..48081d71c22c 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -460,7 +460,7 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) */ static enum da7219_aad_micbias_pulse_lvl - da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_component *component, u32 val) + da7219_aad_fw_micbias_pulse_lvl(struct device *dev, u32 val) { switch (val) { case 2800: @@ -468,13 +468,13 @@ static enum da7219_aad_micbias_pulse_lvl case 2900: return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V; default: - dev_warn(component->dev, "Invalid micbias pulse level"); + dev_warn(dev, "Invalid micbias pulse level"); return DA7219_AAD_MICBIAS_PULSE_LVL_OFF; } } static enum da7219_aad_btn_cfg - da7219_aad_fw_btn_cfg(struct snd_soc_component *component, u32 val) + da7219_aad_fw_btn_cfg(struct device *dev, u32 val) { switch (val) { case 2: @@ -492,13 +492,13 @@ static enum da7219_aad_btn_cfg case 500: return DA7219_AAD_BTN_CFG_500MS; default: - dev_warn(component->dev, "Invalid button config"); + dev_warn(dev, "Invalid button config"); return DA7219_AAD_BTN_CFG_10MS; } } static enum da7219_aad_mic_det_thr - da7219_aad_fw_mic_det_thr(struct snd_soc_component *component, u32 val) + da7219_aad_fw_mic_det_thr(struct device *dev, u32 val) { switch (val) { case 200: @@ -510,13 +510,13 @@ static enum da7219_aad_mic_det_thr case 1000: return DA7219_AAD_MIC_DET_THR_1000_OHMS; default: - dev_warn(component->dev, "Invalid mic detect threshold"); + dev_warn(dev, "Invalid mic detect threshold"); return DA7219_AAD_MIC_DET_THR_500_OHMS; } } static enum da7219_aad_jack_ins_deb - da7219_aad_fw_jack_ins_deb(struct snd_soc_component *component, u32 val) + da7219_aad_fw_jack_ins_deb(struct device *dev, u32 val) { switch (val) { case 5: @@ -536,13 +536,13 @@ static enum da7219_aad_jack_ins_deb case 1000: return DA7219_AAD_JACK_INS_DEB_1S; default: - dev_warn(component->dev, "Invalid jack insert debounce"); + dev_warn(dev, "Invalid jack insert debounce"); return DA7219_AAD_JACK_INS_DEB_20MS; } } static enum da7219_aad_jack_det_rate - da7219_aad_fw_jack_det_rate(struct snd_soc_component *component, const char *str) + da7219_aad_fw_jack_det_rate(struct device *dev, const char *str) { if (!strcmp(str, "32ms_64ms")) { return DA7219_AAD_JACK_DET_RATE_32_64MS; @@ -553,13 +553,13 @@ static enum da7219_aad_jack_det_rate } else if (!strcmp(str, "256ms_512ms")) { return DA7219_AAD_JACK_DET_RATE_256_512MS; } else { - dev_warn(component->dev, "Invalid jack detect rate"); + dev_warn(dev, "Invalid jack detect rate"); return DA7219_AAD_JACK_DET_RATE_256_512MS; } } static enum da7219_aad_jack_rem_deb - da7219_aad_fw_jack_rem_deb(struct snd_soc_component *component, u32 val) + da7219_aad_fw_jack_rem_deb(struct device *dev, u32 val) { switch (val) { case 1: @@ -571,13 +571,13 @@ static enum da7219_aad_jack_rem_deb case 20: return DA7219_AAD_JACK_REM_DEB_20MS; default: - dev_warn(component->dev, "Invalid jack removal debounce"); + dev_warn(dev, "Invalid jack removal debounce"); return DA7219_AAD_JACK_REM_DEB_1MS; } } static enum da7219_aad_btn_avg - da7219_aad_fw_btn_avg(struct snd_soc_component *component, u32 val) + da7219_aad_fw_btn_avg(struct device *dev, u32 val) { switch (val) { case 1: @@ -589,13 +589,13 @@ static enum da7219_aad_btn_avg case 8: return DA7219_AAD_BTN_AVG_8; default: - dev_warn(component->dev, "Invalid button average value"); + dev_warn(dev, "Invalid button average value"); return DA7219_AAD_BTN_AVG_2; } } static enum da7219_aad_adc_1bit_rpt - da7219_aad_fw_adc_1bit_rpt(struct snd_soc_component *component, u32 val) + da7219_aad_fw_adc_1bit_rpt(struct device *dev, u32 val) { switch (val) { case 1: @@ -607,14 +607,13 @@ static enum da7219_aad_adc_1bit_rpt case 8: return DA7219_AAD_ADC_1BIT_RPT_8; default: - dev_warn(component->dev, "Invalid ADC 1-bit repeat value"); + dev_warn(dev, "Invalid ADC 1-bit repeat value"); return DA7219_AAD_ADC_1BIT_RPT_1; } } -static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component *component) +static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev) { - struct device *dev = component->dev; struct i2c_client *i2c = to_i2c_client(dev); struct fwnode_handle *aad_np; struct da7219_aad_pdata *aad_pdata; @@ -634,7 +633,7 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", &fw_val32) >= 0) aad_pdata->micbias_pulse_lvl = - da7219_aad_fw_micbias_pulse_lvl(component, fw_val32); + da7219_aad_fw_micbias_pulse_lvl(dev, fw_val32); else aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; @@ -643,31 +642,31 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component aad_pdata->micbias_pulse_time = fw_val32; if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0) - aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(component, fw_val32); + aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(dev, fw_val32); else aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0) aad_pdata->mic_det_thr = - da7219_aad_fw_mic_det_thr(component, fw_val32); + da7219_aad_fw_mic_det_thr(dev, fw_val32); else aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS; if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0) aad_pdata->jack_ins_deb = - da7219_aad_fw_jack_ins_deb(component, fw_val32); + da7219_aad_fw_jack_ins_deb(dev, fw_val32); else aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str)) aad_pdata->jack_det_rate = - da7219_aad_fw_jack_det_rate(component, fw_str); + da7219_aad_fw_jack_det_rate(dev, fw_str); else aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0) aad_pdata->jack_rem_deb = - da7219_aad_fw_jack_rem_deb(component, fw_val32); + da7219_aad_fw_jack_rem_deb(dev, fw_val32); else aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; @@ -692,13 +691,13 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component aad_pdata->c_mic_btn_thr = 0x3E; if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0) - aad_pdata->btn_avg = da7219_aad_fw_btn_avg(component, fw_val32); + aad_pdata->btn_avg = da7219_aad_fw_btn_avg(dev, fw_val32); else aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0) aad_pdata->adc_1bit_rpt = - da7219_aad_fw_adc_1bit_rpt(component, fw_val32); + da7219_aad_fw_adc_1bit_rpt(dev, fw_val32); else aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; @@ -887,21 +886,13 @@ void da7219_aad_resume(struct snd_soc_component *component) int da7219_aad_init(struct snd_soc_component *component) { struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - struct da7219_aad_priv *da7219_aad; + struct da7219_aad_priv *da7219_aad = da7219->aad; u8 mask[DA7219_AAD_IRQ_REG_MAX]; int ret; - da7219_aad = devm_kzalloc(component->dev, sizeof(*da7219_aad), GFP_KERNEL); - if (!da7219_aad) - return -ENOMEM; - - da7219->aad = da7219_aad; da7219_aad->component = component; /* Handle any DT/ACPI/platform data */ - if (da7219->pdata && !da7219->pdata->aad_pdata) - da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(component); - da7219_aad_handle_pdata(component); /* Disable button detection */ @@ -947,6 +938,30 @@ void da7219_aad_exit(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(da7219_aad_exit); +/* + * AAD related I2C probe handling + */ + +int da7219_aad_probe(struct i2c_client *i2c) +{ + struct da7219_priv *da7219 = i2c_get_clientdata(i2c); + struct device *dev = &i2c->dev; + struct da7219_aad_priv *da7219_aad; + + da7219_aad = devm_kzalloc(dev, sizeof(*da7219_aad), GFP_KERNEL); + if (!da7219_aad) + return -ENOMEM; + + da7219->aad = da7219_aad; + + /* Retrieve any DT/ACPI/platform data */ + if (da7219->pdata && !da7219->pdata->aad_pdata) + da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(da7219_aad_probe); + MODULE_DESCRIPTION("ASoC DA7219 AAD Driver"); MODULE_AUTHOR("Adam Thomson <[email protected]>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h index cfa46fba2390..f48a12012ef3 100644 --- a/sound/soc/codecs/da7219-aad.h +++ b/sound/soc/codecs/da7219-aad.h @@ -212,4 +212,7 @@ void da7219_aad_resume(struct snd_soc_component *component); int da7219_aad_init(struct snd_soc_component *component); void da7219_aad_exit(struct snd_soc_component *component); +/* I2C Probe */ +int da7219_aad_probe(struct i2c_client *i2c); + #endif /* __DA7219_AAD_H */ diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 153ea30b5a8f..0b3b7909efc9 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1753,9 +1753,8 @@ static enum da7219_mic_amp_in_sel } } -static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *component) +static struct da7219_pdata *da7219_fw_to_pdata(struct device *dev) { - struct device *dev = component->dev; struct da7219_pdata *pdata; const char *of_str; u32 of_val32; @@ -1847,45 +1846,43 @@ static const char *da7219_supply_names[DA7219_NUM_SUPPLIES] = { [DA7219_SUPPLY_VDDIO] = "VDDIO", }; -static int da7219_handle_supplies(struct snd_soc_component *component) +static int da7219_handle_supplies(struct snd_soc_component *component, + u8 *io_voltage_lvl) { struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); struct regulator *vddio; - u8 io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V; int i, ret; /* Get required supplies */ for (i = 0; i < DA7219_NUM_SUPPLIES; ++i) da7219->supplies[i].supply = da7219_supply_names[i]; - ret = devm_regulator_bulk_get(component->dev, DA7219_NUM_SUPPLIES, - da7219->supplies); + ret = regulator_bulk_get(component->dev, DA7219_NUM_SUPPLIES, + da7219->supplies); if (ret) { dev_err(component->dev, "Failed to get supplies"); return ret; } + /* Default to upper range */ + *io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V; + /* Determine VDDIO voltage provided */ vddio = da7219->supplies[DA7219_SUPPLY_VDDIO].consumer; ret = regulator_get_voltage(vddio); if (ret < 1200000) dev_warn(component->dev, "Invalid VDDIO voltage\n"); else if (ret < 2800000) - io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V; + *io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V; /* Enable main supplies */ ret = regulator_bulk_enable(DA7219_NUM_SUPPLIES, da7219->supplies); if (ret) { dev_err(component->dev, "Failed to enable supplies"); + regulator_bulk_free(DA7219_NUM_SUPPLIES, da7219->supplies); return ret; } - /* Ensure device in active mode */ - snd_soc_component_write(component, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK); - - /* Update IO voltage level range */ - snd_soc_component_write(component, DA7219_IO_CTRL, io_voltage_lvl); - return 0; } @@ -2121,14 +2118,26 @@ static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = { static int da7219_register_dai_clks(struct snd_soc_component *component) { struct device *dev = component->dev; + struct device_node *np = dev->of_node; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); struct da7219_pdata *pdata = da7219->pdata; const char *parent_name; + struct clk_hw_onecell_data *clk_data; int i, ret; + /* For DT platforms allocate onecell data for clock registration */ + if (np) { + clk_data = kzalloc(struct_size(clk_data, hws, DA7219_DAI_NUM_CLKS), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = DA7219_DAI_NUM_CLKS; + da7219->clk_hw_data = clk_data; + } + for (i = 0; i < DA7219_DAI_NUM_CLKS; ++i) { struct clk_init_data init = {}; - struct clk *dai_clk; struct clk_lookup *dai_clk_lookup; struct clk_hw *dai_clk_hw = &da7219->dai_clks_hw[i]; @@ -2164,22 +2173,20 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; dai_clk_hw->init = &init; - dai_clk = devm_clk_register(dev, dai_clk_hw); - if (IS_ERR(dai_clk)) { - dev_warn(dev, "Failed to register %s: %ld\n", - init.name, PTR_ERR(dai_clk)); - ret = PTR_ERR(dai_clk); + ret = clk_hw_register(dev, dai_clk_hw); + if (ret) { + dev_warn(dev, "Failed to register %s: %d\n", init.name, + ret); goto err; } - da7219->dai_clks[i] = dai_clk; + da7219->dai_clks[i] = dai_clk_hw->clk; - /* If we're using DT, then register as provider accordingly */ - if (dev->of_node) { - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, - dai_clk_hw); + /* For DT setup onecell data, otherwise create lookup */ + if (np) { + da7219->clk_hw_data->hws[i] = dai_clk_hw; } else { - dai_clk_lookup = clkdev_create(dai_clk, init.name, - "%s", dev_name(dev)); + dai_clk_lookup = clkdev_hw_create(dai_clk_hw, init.name, + "%s", dev_name(dev)); if (!dai_clk_lookup) { ret = -ENOMEM; goto err; @@ -2189,21 +2196,58 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) } } + /* If we're using DT, then register as provider accordingly */ + if (np) { + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + da7219->clk_hw_data); + if (ret) { + dev_err(dev, "Failed to register clock provider\n"); + goto err; + } + } + return 0; err: do { if (da7219->dai_clks_lookup[i]) clkdev_drop(da7219->dai_clks_lookup[i]); + + clk_hw_unregister(&da7219->dai_clks_hw[i]); } while (i-- > 0); + if (np) + kfree(da7219->clk_hw_data); + return ret; } + +static void da7219_free_dai_clks(struct snd_soc_component *component) +{ + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + struct device_node *np = component->dev->of_node; + int i; + + if (np) + of_clk_del_provider(np); + + for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) { + if (da7219->dai_clks_lookup[i]) + clkdev_drop(da7219->dai_clks_lookup[i]); + + clk_hw_unregister(&da7219->dai_clks_hw[i]); + } + + if (np) + kfree(da7219->clk_hw_data); +} #else static inline int da7219_register_dai_clks(struct snd_soc_component *component) { return 0; } + +static void da7219_free_dai_clks(struct snd_soc_component *component) {} #endif /* CONFIG_COMMON_CLK */ static void da7219_handle_pdata(struct snd_soc_component *component) @@ -2251,6 +2295,142 @@ static void da7219_handle_pdata(struct snd_soc_component *component) } } + +/* + * Regmap configs + */ + +static struct reg_default da7219_reg_defaults[] = { + { DA7219_MIC_1_SELECT, 0x00 }, + { DA7219_CIF_TIMEOUT_CTRL, 0x01 }, + { DA7219_SR_24_48, 0x00 }, + { DA7219_SR, 0x0A }, + { DA7219_CIF_I2C_ADDR_CFG, 0x02 }, + { DA7219_PLL_CTRL, 0x10 }, + { DA7219_PLL_FRAC_TOP, 0x00 }, + { DA7219_PLL_FRAC_BOT, 0x00 }, + { DA7219_PLL_INTEGER, 0x20 }, + { DA7219_DIG_ROUTING_DAI, 0x10 }, + { DA7219_DAI_CLK_MODE, 0x01 }, + { DA7219_DAI_CTRL, 0x28 }, + { DA7219_DAI_TDM_CTRL, 0x40 }, + { DA7219_DIG_ROUTING_DAC, 0x32 }, + { DA7219_DAI_OFFSET_LOWER, 0x00 }, + { DA7219_DAI_OFFSET_UPPER, 0x00 }, + { DA7219_REFERENCES, 0x08 }, + { DA7219_MIXIN_L_SELECT, 0x00 }, + { DA7219_MIXIN_L_GAIN, 0x03 }, + { DA7219_ADC_L_GAIN, 0x6F }, + { DA7219_ADC_FILTERS1, 0x80 }, + { DA7219_MIC_1_GAIN, 0x01 }, + { DA7219_SIDETONE_CTRL, 0x40 }, + { DA7219_SIDETONE_GAIN, 0x0E }, + { DA7219_DROUTING_ST_OUTFILT_1L, 0x01 }, + { DA7219_DROUTING_ST_OUTFILT_1R, 0x02 }, + { DA7219_DAC_FILTERS5, 0x00 }, + { DA7219_DAC_FILTERS2, 0x88 }, + { DA7219_DAC_FILTERS3, 0x88 }, + { DA7219_DAC_FILTERS4, 0x08 }, + { DA7219_DAC_FILTERS1, 0x80 }, + { DA7219_DAC_L_GAIN, 0x6F }, + { DA7219_DAC_R_GAIN, 0x6F }, + { DA7219_CP_CTRL, 0x20 }, + { DA7219_HP_L_GAIN, 0x39 }, + { DA7219_HP_R_GAIN, 0x39 }, + { DA7219_MIXOUT_L_SELECT, 0x00 }, + { DA7219_MIXOUT_R_SELECT, 0x00 }, + { DA7219_MICBIAS_CTRL, 0x03 }, + { DA7219_MIC_1_CTRL, 0x40 }, + { DA7219_MIXIN_L_CTRL, 0x40 }, + { DA7219_ADC_L_CTRL, 0x40 }, + { DA7219_DAC_L_CTRL, 0x40 }, + { DA7219_DAC_R_CTRL, 0x40 }, + { DA7219_HP_L_CTRL, 0x40 }, + { DA7219_HP_R_CTRL, 0x40 }, + { DA7219_MIXOUT_L_CTRL, 0x10 }, + { DA7219_MIXOUT_R_CTRL, 0x10 }, + { DA7219_CHIP_ID1, 0x23 }, + { DA7219_CHIP_ID2, 0x93 }, + { DA7219_IO_CTRL, 0x00 }, + { DA7219_GAIN_RAMP_CTRL, 0x00 }, + { DA7219_PC_COUNT, 0x02 }, + { DA7219_CP_VOL_THRESHOLD1, 0x0E }, + { DA7219_DIG_CTRL, 0x00 }, + { DA7219_ALC_CTRL2, 0x00 }, + { DA7219_ALC_CTRL3, 0x00 }, + { DA7219_ALC_NOISE, 0x3F }, + { DA7219_ALC_TARGET_MIN, 0x3F }, + { DA7219_ALC_TARGET_MAX, 0x00 }, + { DA7219_ALC_GAIN_LIMITS, 0xFF }, + { DA7219_ALC_ANA_GAIN_LIMITS, 0x71 }, + { DA7219_ALC_ANTICLIP_CTRL, 0x00 }, + { DA7219_ALC_ANTICLIP_LEVEL, 0x00 }, + { DA7219_DAC_NG_SETUP_TIME, 0x00 }, + { DA7219_DAC_NG_OFF_THRESH, 0x00 }, + { DA7219_DAC_NG_ON_THRESH, 0x00 }, + { DA7219_DAC_NG_CTRL, 0x00 }, + { DA7219_TONE_GEN_CFG1, 0x00 }, + { DA7219_TONE_GEN_CFG2, 0x00 }, + { DA7219_TONE_GEN_CYCLES, 0x00 }, + { DA7219_TONE_GEN_FREQ1_L, 0x55 }, + { DA7219_TONE_GEN_FREQ1_U, 0x15 }, + { DA7219_TONE_GEN_FREQ2_L, 0x00 }, + { DA7219_TONE_GEN_FREQ2_U, 0x40 }, + { DA7219_TONE_GEN_ON_PER, 0x02 }, + { DA7219_TONE_GEN_OFF_PER, 0x01 }, + { DA7219_ACCDET_IRQ_MASK_A, 0x00 }, + { DA7219_ACCDET_IRQ_MASK_B, 0x00 }, + { DA7219_ACCDET_CONFIG_1, 0xD6 }, + { DA7219_ACCDET_CONFIG_2, 0x34 }, + { DA7219_ACCDET_CONFIG_3, 0x0A }, + { DA7219_ACCDET_CONFIG_4, 0x16 }, + { DA7219_ACCDET_CONFIG_5, 0x21 }, + { DA7219_ACCDET_CONFIG_6, 0x3E }, + { DA7219_ACCDET_CONFIG_7, 0x01 }, + { DA7219_SYSTEM_ACTIVE, 0x00 }, +}; + +static bool da7219_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7219_MIC_1_GAIN_STATUS: + case DA7219_MIXIN_L_GAIN_STATUS: + case DA7219_ADC_L_GAIN_STATUS: + case DA7219_DAC_L_GAIN_STATUS: + case DA7219_DAC_R_GAIN_STATUS: + case DA7219_HP_L_GAIN_STATUS: + case DA7219_HP_R_GAIN_STATUS: + case DA7219_CIF_CTRL: + case DA7219_PLL_SRM_STS: + case DA7219_ALC_CTRL1: + case DA7219_SYSTEM_MODES_INPUT: + case DA7219_SYSTEM_MODES_OUTPUT: + case DA7219_ALC_OFFSET_AUTO_M_L: + case DA7219_ALC_OFFSET_AUTO_U_L: + case DA7219_TONE_GEN_CFG1: + case DA7219_ACCDET_STATUS_A: + case DA7219_ACCDET_STATUS_B: + case DA7219_ACCDET_IRQ_EVENT_A: + case DA7219_ACCDET_IRQ_EVENT_B: + case DA7219_ACCDET_CONFIG_8: + case DA7219_SYSTEM_STATUS: + return true; + default: + return false; + } +} + +static const struct regmap_config da7219_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = DA7219_SYSTEM_ACTIVE, + .reg_defaults = da7219_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7219_reg_defaults), + .volatile_reg = da7219_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + static struct reg_sequence da7219_rev_aa_patch[] = { { DA7219_REFERENCES, 0x08 }, }; @@ -2258,18 +2438,56 @@ static struct reg_sequence da7219_rev_aa_patch[] = { static int da7219_probe(struct snd_soc_component *component) { struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - unsigned int rev; - int ret; + unsigned int system_active, system_status, rev; + u8 io_voltage_lvl; + int i, ret; da7219->component = component; mutex_init(&da7219->ctrl_lock); mutex_init(&da7219->pll_lock); /* Regulator configuration */ - ret = da7219_handle_supplies(component); + ret = da7219_handle_supplies(component, &io_voltage_lvl); if (ret) return ret; + regcache_cache_bypass(da7219->regmap, true); + + /* Disable audio paths if still active from previous start */ + regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active); + if (system_active) { + regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL, + DA7219_GAIN_RAMP_RATE_NOMINAL); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01); + + for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) { + regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS, + &system_status); + if (!system_status) + break; + + msleep(DA7219_SYS_STAT_CHECK_DELAY); + } + } + + /* Soft reset component */ + regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, 0); + regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL, + DA7219_CIF_REG_SOFT_RESET_MASK, + DA7219_CIF_REG_SOFT_RESET_MASK); + regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE, + DA7219_SYSTEM_ACTIVE_MASK, 0); + regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE, + DA7219_SYSTEM_ACTIVE_MASK, 1); + + regcache_cache_bypass(da7219->regmap, false); + regmap_reinit_cache(da7219->regmap, &da7219_regmap_config); + + /* Update IO voltage level range based on supply level */ + snd_soc_component_write(component, DA7219_IO_CTRL, io_voltage_lvl); + ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev); if (ret) { dev_err(component->dev, "Failed to read chip revision: %d\n", ret); @@ -2291,14 +2509,10 @@ static int da7219_probe(struct snd_soc_component *component) } /* Handle DT/ACPI/Platform data */ - da7219->pdata = dev_get_platdata(component->dev); - if (!da7219->pdata) - da7219->pdata = da7219_fw_to_pdata(component); - da7219_handle_pdata(component); /* Check if MCLK provided */ - da7219->mclk = devm_clk_get(component->dev, "mclk"); + da7219->mclk = clk_get(component->dev, "mclk"); if (IS_ERR(da7219->mclk)) { if (PTR_ERR(da7219->mclk) != -ENOENT) { ret = PTR_ERR(da7219->mclk); @@ -2311,7 +2525,7 @@ static int da7219_probe(struct snd_soc_component *component) /* Register CCF DAI clock control */ ret = da7219_register_dai_clks(component); if (ret) - return ret; + goto err_put_clk; /* Default PC counter to free-running */ snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, @@ -2348,12 +2562,19 @@ static int da7219_probe(struct snd_soc_component *component) /* Initialise AAD block */ ret = da7219_aad_init(component); if (ret) - goto err_disable_reg; + goto err_free_dai_clks; return 0; +err_free_dai_clks: + da7219_free_dai_clks(component); + +err_put_clk: + clk_put(da7219->mclk); + err_disable_reg: regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies); + regulator_bulk_free(DA7219_NUM_SUPPLIES, da7219->supplies); return ret; } @@ -2361,21 +2582,15 @@ err_disable_reg: static void da7219_remove(struct snd_soc_component *component) { struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -#ifdef CONFIG_COMMON_CLK - int i; -#endif da7219_aad_exit(component); -#ifdef CONFIG_COMMON_CLK - for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) { - if (da7219->dai_clks_lookup[i]) - clkdev_drop(da7219->dai_clks_lookup[i]); - } -#endif + da7219_free_dai_clks(component); + clk_put(da7219->mclk); /* Supplies */ regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies); + regulator_bulk_free(DA7219_NUM_SUPPLIES, da7219->supplies); } #ifdef CONFIG_PM @@ -2429,153 +2644,17 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = { /* - * Regmap configs - */ - -static struct reg_default da7219_reg_defaults[] = { - { DA7219_MIC_1_SELECT, 0x00 }, - { DA7219_CIF_TIMEOUT_CTRL, 0x01 }, - { DA7219_SR_24_48, 0x00 }, - { DA7219_SR, 0x0A }, - { DA7219_CIF_I2C_ADDR_CFG, 0x02 }, - { DA7219_PLL_CTRL, 0x10 }, - { DA7219_PLL_FRAC_TOP, 0x00 }, - { DA7219_PLL_FRAC_BOT, 0x00 }, - { DA7219_PLL_INTEGER, 0x20 }, - { DA7219_DIG_ROUTING_DAI, 0x10 }, - { DA7219_DAI_CLK_MODE, 0x01 }, - { DA7219_DAI_CTRL, 0x28 }, - { DA7219_DAI_TDM_CTRL, 0x40 }, - { DA7219_DIG_ROUTING_DAC, 0x32 }, - { DA7219_DAI_OFFSET_LOWER, 0x00 }, - { DA7219_DAI_OFFSET_UPPER, 0x00 }, - { DA7219_REFERENCES, 0x08 }, - { DA7219_MIXIN_L_SELECT, 0x00 }, - { DA7219_MIXIN_L_GAIN, 0x03 }, - { DA7219_ADC_L_GAIN, 0x6F }, - { DA7219_ADC_FILTERS1, 0x80 }, - { DA7219_MIC_1_GAIN, 0x01 }, - { DA7219_SIDETONE_CTRL, 0x40 }, - { DA7219_SIDETONE_GAIN, 0x0E }, - { DA7219_DROUTING_ST_OUTFILT_1L, 0x01 }, - { DA7219_DROUTING_ST_OUTFILT_1R, 0x02 }, - { DA7219_DAC_FILTERS5, 0x00 }, - { DA7219_DAC_FILTERS2, 0x88 }, - { DA7219_DAC_FILTERS3, 0x88 }, - { DA7219_DAC_FILTERS4, 0x08 }, - { DA7219_DAC_FILTERS1, 0x80 }, - { DA7219_DAC_L_GAIN, 0x6F }, - { DA7219_DAC_R_GAIN, 0x6F }, - { DA7219_CP_CTRL, 0x20 }, - { DA7219_HP_L_GAIN, 0x39 }, - { DA7219_HP_R_GAIN, 0x39 }, - { DA7219_MIXOUT_L_SELECT, 0x00 }, - { DA7219_MIXOUT_R_SELECT, 0x00 }, - { DA7219_MICBIAS_CTRL, 0x03 }, - { DA7219_MIC_1_CTRL, 0x40 }, - { DA7219_MIXIN_L_CTRL, 0x40 }, - { DA7219_ADC_L_CTRL, 0x40 }, - { DA7219_DAC_L_CTRL, 0x40 }, - { DA7219_DAC_R_CTRL, 0x40 }, - { DA7219_HP_L_CTRL, 0x40 }, - { DA7219_HP_R_CTRL, 0x40 }, - { DA7219_MIXOUT_L_CTRL, 0x10 }, - { DA7219_MIXOUT_R_CTRL, 0x10 }, - { DA7219_CHIP_ID1, 0x23 }, - { DA7219_CHIP_ID2, 0x93 }, - { DA7219_IO_CTRL, 0x00 }, - { DA7219_GAIN_RAMP_CTRL, 0x00 }, - { DA7219_PC_COUNT, 0x02 }, - { DA7219_CP_VOL_THRESHOLD1, 0x0E }, - { DA7219_DIG_CTRL, 0x00 }, - { DA7219_ALC_CTRL2, 0x00 }, - { DA7219_ALC_CTRL3, 0x00 }, - { DA7219_ALC_NOISE, 0x3F }, - { DA7219_ALC_TARGET_MIN, 0x3F }, - { DA7219_ALC_TARGET_MAX, 0x00 }, - { DA7219_ALC_GAIN_LIMITS, 0xFF }, - { DA7219_ALC_ANA_GAIN_LIMITS, 0x71 }, - { DA7219_ALC_ANTICLIP_CTRL, 0x00 }, - { DA7219_ALC_ANTICLIP_LEVEL, 0x00 }, - { DA7219_DAC_NG_SETUP_TIME, 0x00 }, - { DA7219_DAC_NG_OFF_THRESH, 0x00 }, - { DA7219_DAC_NG_ON_THRESH, 0x00 }, - { DA7219_DAC_NG_CTRL, 0x00 }, - { DA7219_TONE_GEN_CFG1, 0x00 }, - { DA7219_TONE_GEN_CFG2, 0x00 }, - { DA7219_TONE_GEN_CYCLES, 0x00 }, - { DA7219_TONE_GEN_FREQ1_L, 0x55 }, - { DA7219_TONE_GEN_FREQ1_U, 0x15 }, - { DA7219_TONE_GEN_FREQ2_L, 0x00 }, - { DA7219_TONE_GEN_FREQ2_U, 0x40 }, - { DA7219_TONE_GEN_ON_PER, 0x02 }, - { DA7219_TONE_GEN_OFF_PER, 0x01 }, - { DA7219_ACCDET_IRQ_MASK_A, 0x00 }, - { DA7219_ACCDET_IRQ_MASK_B, 0x00 }, - { DA7219_ACCDET_CONFIG_1, 0xD6 }, - { DA7219_ACCDET_CONFIG_2, 0x34 }, - { DA7219_ACCDET_CONFIG_3, 0x0A }, - { DA7219_ACCDET_CONFIG_4, 0x16 }, - { DA7219_ACCDET_CONFIG_5, 0x21 }, - { DA7219_ACCDET_CONFIG_6, 0x3E }, - { DA7219_ACCDET_CONFIG_7, 0x01 }, - { DA7219_SYSTEM_ACTIVE, 0x00 }, -}; - -static bool da7219_volatile_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case DA7219_MIC_1_GAIN_STATUS: - case DA7219_MIXIN_L_GAIN_STATUS: - case DA7219_ADC_L_GAIN_STATUS: - case DA7219_DAC_L_GAIN_STATUS: - case DA7219_DAC_R_GAIN_STATUS: - case DA7219_HP_L_GAIN_STATUS: - case DA7219_HP_R_GAIN_STATUS: - case DA7219_CIF_CTRL: - case DA7219_PLL_SRM_STS: - case DA7219_ALC_CTRL1: - case DA7219_SYSTEM_MODES_INPUT: - case DA7219_SYSTEM_MODES_OUTPUT: - case DA7219_ALC_OFFSET_AUTO_M_L: - case DA7219_ALC_OFFSET_AUTO_U_L: - case DA7219_TONE_GEN_CFG1: - case DA7219_ACCDET_STATUS_A: - case DA7219_ACCDET_STATUS_B: - case DA7219_ACCDET_IRQ_EVENT_A: - case DA7219_ACCDET_IRQ_EVENT_B: - case DA7219_ACCDET_CONFIG_8: - case DA7219_SYSTEM_STATUS: - return true; - default: - return false; - } -} - -static const struct regmap_config da7219_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = DA7219_SYSTEM_ACTIVE, - .reg_defaults = da7219_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(da7219_reg_defaults), - .volatile_reg = da7219_volatile_register, - .cache_type = REGCACHE_RBTREE, -}; - - -/* * I2C layer */ static int da7219_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct device *dev = &i2c->dev; struct da7219_priv *da7219; - unsigned int system_active, system_status; - int i, ret; + int ret; - da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv), + da7219 = devm_kzalloc(dev, sizeof(struct da7219_priv), GFP_KERNEL); if (!da7219) return -ENOMEM; @@ -2585,47 +2664,24 @@ static int da7219_i2c_probe(struct i2c_client *i2c, da7219->regmap = devm_regmap_init_i2c(i2c, &da7219_regmap_config); if (IS_ERR(da7219->regmap)) { ret = PTR_ERR(da7219->regmap); - dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + dev_err(dev, "regmap_init() failed: %d\n", ret); return ret; } - regcache_cache_bypass(da7219->regmap, true); - - /* Disable audio paths if still active from previous start */ - regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active); - if (system_active) { - regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL, - DA7219_GAIN_RAMP_RATE_NOMINAL); - regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00); - regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01); - - for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) { - regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS, - &system_status); - if (!system_status) - break; - - msleep(DA7219_SYS_STAT_CHECK_DELAY); - } - } - - /* Soft reset component */ - regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1, - DA7219_ACCDET_EN_MASK, 0); - regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL, - DA7219_CIF_REG_SOFT_RESET_MASK, - DA7219_CIF_REG_SOFT_RESET_MASK); - regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE, - DA7219_SYSTEM_ACTIVE_MASK, 0); + /* Retrieve DT/ACPI/Platform data */ + da7219->pdata = dev_get_platdata(dev); + if (!da7219->pdata) + da7219->pdata = da7219_fw_to_pdata(dev); - regcache_cache_bypass(da7219->regmap, false); + /* AAD */ + ret = da7219_aad_probe(i2c); + if (ret) + return ret; - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_da7219, - &da7219_dai, 1); + ret = devm_snd_soc_register_component(dev, &soc_component_dev_da7219, + &da7219_dai, 1); if (ret < 0) { - dev_err(&i2c->dev, "Failed to register da7219 component: %d\n", - ret); + dev_err(dev, "Failed to register da7219 component: %d\n", ret); } return ret; } diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 88b67fedd01b..94af88f52589 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -817,6 +817,7 @@ struct da7219_priv { #ifdef CONFIG_COMMON_CLK struct clk_hw dai_clks_hw[DA7219_DAI_NUM_CLKS]; + struct clk_hw_onecell_data *clk_hw_data; #endif struct clk_lookup *dai_clks_lookup[DA7219_DAI_NUM_CLKS]; struct clk *dai_clks[DA7219_DAI_NUM_CLKS]; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f26b77faed59..c61cce53f513 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -9,6 +9,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + #include <linux/init.h> #include <linux/delay.h> #include <linux/module.h> @@ -107,6 +108,7 @@ struct hdac_hdmi_pcm { unsigned char chmap[8]; /* ALSA API channel-map */ struct mutex lock; int jack_event; + struct snd_kcontrol *eld_ctl; }; struct hdac_hdmi_dai_port_map { @@ -1248,6 +1250,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_pcm *pcm; int size = 0; int port_id = -1; + bool eld_valid, eld_changed; if (!hdmi) return; @@ -1273,6 +1276,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, size = -EINVAL; } + eld_valid = port->eld.eld_valid; + if (size > 0) { port->eld.eld_valid = true; port->eld.eld_size = size; @@ -1281,6 +1286,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, port->eld.eld_size = 0; } + eld_changed = (eld_valid != port->eld.eld_valid); + pcm = hdac_hdmi_get_pcm(hdev, port); if (!port->eld.monitor_present || !port->eld.eld_valid) { @@ -1313,6 +1320,12 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, } mutex_unlock(&hdmi->pin_mutex); + + if (eld_changed && pcm) + snd_ctl_notify(hdmi->card, + SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, + &pcm->eld_ctl->id); } static int hdac_hdmi_add_ports(struct hdac_device *hdev, @@ -1411,6 +1424,122 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev) } +static int hdac_hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); + struct hdac_hdmi_pcm *pcm; + struct hdac_hdmi_port *port; + struct hdac_hdmi_eld *eld; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 0; + + pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); + if (!pcm) { + dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, + kcontrol->id.device); + return 0; + } + + if (list_empty(&pcm->port_list)) { + dev_dbg(component->dev, "%s: empty port list, device %d\n", + __func__, kcontrol->id.device); + return 0; + } + + mutex_lock(&hdmi->pin_mutex); + + list_for_each_entry(port, &pcm->port_list, head) { + eld = &port->eld; + + if (eld->eld_valid) { + uinfo->count = eld->eld_size; + break; + } + } + + mutex_unlock(&hdmi->pin_mutex); + + return 0; +} + +static int hdac_hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component); + struct hdac_hdmi_pcm *pcm; + struct hdac_hdmi_port *port; + struct hdac_hdmi_eld *eld; + + memset(ucontrol->value.bytes.data, 0, sizeof(ucontrol->value.bytes.data)); + + pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device); + if (!pcm) { + dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__, + kcontrol->id.device); + return 0; + } + + if (list_empty(&pcm->port_list)) { + dev_dbg(component->dev, "%s: empty port list, device %d\n", + __func__, kcontrol->id.device); + return 0; + } + + mutex_lock(&hdmi->pin_mutex); + + list_for_each_entry(port, &pcm->port_list, head) { + eld = &port->eld; + + if (!eld->eld_valid) + continue; + + if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || + eld->eld_size > ELD_MAX_SIZE) { + mutex_unlock(&hdmi->pin_mutex); + + dev_err(component->dev, "%s: buffer too small, device %d eld_size %d\n", + __func__, kcontrol->id.device, eld->eld_size); + snd_BUG(); + return -EINVAL; + } + + memcpy(ucontrol->value.bytes.data, eld->eld_buffer, + eld->eld_size); + break; + } + + mutex_unlock(&hdmi->pin_mutex); + + return 0; +} + +static int hdac_hdmi_create_eld_ctl(struct snd_soc_component *component, struct hdac_hdmi_pcm *pcm) +{ + struct snd_kcontrol *kctl; + struct snd_kcontrol_new hdmi_eld_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = hdac_hdmi_eld_ctl_info, + .get = hdac_hdmi_eld_ctl_get, + .device = pcm->pcm_id, + }; + + /* add ELD ctl with the device number corresponding to the PCM stream */ + kctl = snd_ctl_new1(&hdmi_eld_ctl, component); + if (!kctl) + return -ENOMEM; + + pcm->eld_ctl = kctl; + + return snd_ctl_add(component->card->snd_card, kctl); +} + static const struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, @@ -1784,6 +1913,15 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, } } + /* add control for ELD Bytes */ + err = hdac_hdmi_create_eld_ctl(component, pcm); + if (err < 0) { + dev_err(&hdev->dev, + "eld control add failed with err: %d for pcm: %d\n", + err, device); + return err; + } + list_add_tail(&pcm->head, &hdmi->pcm_list); return 0; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 5fe724728e84..6469612c42cb 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -256,6 +256,9 @@ static __maybe_unused int max98373_resume(struct device *dev) struct max98373_priv *max98373 = dev_get_drvdata(dev); unsigned long time; + if (!max98373->hw_init) + return 0; + if (!slave->unattach_request) goto regmap_sync; diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index fcb31144d69c..aef2746bfb94 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -15,6 +15,14 @@ #include <sound/tlv.h> #include "max9867.h" +struct max9867_priv { + struct regmap *regmap; + const struct snd_pcm_hw_constraint_list *constraints; + unsigned int sysclk, pclk; + bool master, dsp_a; + unsigned int adc_dac_active; +}; + static const char *const max9867_spmode[] = { "Stereo Diff", "Mono Diff", "Stereo Cap", "Mono Cap", @@ -32,8 +40,102 @@ static const char *const max9867_adc_dac_filter_text[] = { "Butterworth/8-24" }; -static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, - max9867_filter_text); +enum max9867_adc_dac { + MAX9867_ADC_LEFT, + MAX9867_ADC_RIGHT, + MAX9867_DAC_LEFT, + MAX9867_DAC_RIGHT, +}; + +static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); + enum max9867_adc_dac adc_dac; + + if (!strcmp(w->name, "ADCL")) + adc_dac = MAX9867_ADC_LEFT; + else if (!strcmp(w->name, "ADCR")) + adc_dac = MAX9867_ADC_RIGHT; + else if (!strcmp(w->name, "DACL")) + adc_dac = MAX9867_DAC_LEFT; + else if (!strcmp(w->name, "DACR")) + adc_dac = MAX9867_DAC_RIGHT; + else + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) + max9867->adc_dac_active |= BIT(adc_dac); + else if (SND_SOC_DAPM_EVENT_OFF(event)) + max9867->adc_dac_active &= ~BIT(adc_dac); + + return 0; +} + +static int max9867_filter_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); + unsigned int reg; + int ret; + + ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, ®); + if (ret) + return -EINVAL; + + if (reg & MAX9867_CODECFLTR_MODE) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 0; + + return 0; +} + +static int max9867_filter_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); + unsigned int reg, mode = ucontrol->value.enumerated.item[0]; + int ret; + + if (mode > 1) + return -EINVAL; + + /* don't allow change if ADC/DAC active */ + if (max9867->adc_dac_active) + return -EBUSY; + + /* read current filter mode */ + ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, ®); + if (ret) + return -EINVAL; + + if (mode) + mode = MAX9867_CODECFLTR_MODE; + + /* check if change is needed */ + if ((reg & MAX9867_CODECFLTR_MODE) == mode) + return 0; + + /* shutdown codec before switching filter mode */ + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_PWRMAN_SHDN, 0); + + /* switch filter mode */ + regmap_update_bits(max9867->regmap, MAX9867_CODECFLTR, + MAX9867_CODECFLTR_MODE, mode); + + /* out of shutdown now */ + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_PWRMAN_SHDN, MAX9867_PWRMAN_SHDN); + + return 0; +} + +static SOC_ENUM_SINGLE_EXT_DECL(max9867_filter, max9867_filter_text); static SOC_ENUM_SINGLE_DECL(max9867_dac_filter, MAX9867_CODECFLTR, 0, max9867_adc_dac_filter_text); static SOC_ENUM_SINGLE_DECL(max9867_adc_filter, MAX9867_CODECFLTR, 4, @@ -76,7 +178,7 @@ static const struct snd_kcontrol_new max9867_snd_controls[] = { SOC_ENUM("Speaker Mode", max9867_spkmode), SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0), - SOC_ENUM("DSP Filter", max9867_filter), + SOC_ENUM_EXT("DSP Filter", max9867_filter, max9867_filter_get, max9867_filter_set), SOC_ENUM("ADC Filter", max9867_adc_filter), SOC_ENUM("DAC Filter", max9867_dac_filter), SOC_SINGLE("Mono Playback Switch", MAX9867_IFC1B, 3, 1, 0), @@ -134,8 +236,12 @@ static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { &max9867_left_dmic_mux), SND_SOC_DAPM_MUX("DMICR Mux", SND_SOC_NOPM, 0, 0, &max9867_right_dmic_mux), - SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC_E("ADCL", "HiFi Capture", SND_SOC_NOPM, 0, 0, + max9867_adc_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADCR", "HiFi Capture", SND_SOC_NOPM, 0, 0, + max9867_adc_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0, max9867_sidetone_mixer_controls, @@ -143,8 +249,12 @@ static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0, max9867_output_mixer_controls, ARRAY_SIZE(max9867_output_mixer_controls)), - SND_SOC_DAPM_DAC("DACL", "HiFi Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DACR", "HiFi Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("DACL", "HiFi Playback", SND_SOC_NOPM, 0, 0, + max9867_adc_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("DACR", "HiFi Playback", SND_SOC_NOPM, 0, 0, + max9867_adc_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0, &max9867_line_out_control), SND_SOC_DAPM_OUTPUT("LOUT"), @@ -197,13 +307,6 @@ static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { .count = ARRAY_SIZE(max9867_rates_48k), }; -struct max9867_priv { - struct regmap *regmap; - const struct snd_pcm_hw_constraint_list *constraints; - unsigned int sysclk, pclk; - bool master, dsp_a; -}; - static int max9867_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h index 3092c3b99075..b6b880631b13 100644 --- a/sound/soc/codecs/max9867.h +++ b/sound/soc/codecs/max9867.h @@ -44,7 +44,8 @@ #define MAX9867_IFC1B_PCLK_4 0x05 #define MAX9867_IFC1B_PCLK_8 0x06 #define MAX9867_IFC1B_PCLK_16 0x07 -#define MAX9867_CODECFLTR 0x0a +#define MAX9867_CODECFLTR 0x0a +#define MAX9867_CODECFLTR_MODE (1<<7) #define MAX9867_SIDETONE 0x0b #define MAX9867_DACLEVEL 0x0c #define MAX9867_ADCLEVEL 0x0d @@ -58,6 +59,7 @@ #define MAX9867_MICCONFIG 0x15 #define MAX9867_MODECONFIG 0x16 #define MAX9867_PWRMAN 0x17 +#define MAX9867_PWRMAN_SHDN (1<<7) #define MAX9867_REVISION 0xff #define MAX9867_CACHEREGNUM 10 diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c new file mode 100644 index 000000000000..81aafb553bdd --- /dev/null +++ b/sound/soc/codecs/mt6359.c @@ -0,0 +1,2758 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt6359.c -- mt6359 ALSA SoC audio codec driver +// +// Copyright (c) 2020 MediaTek Inc. +// Author: KaiChieh Chuang <[email protected]> + +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/mfd/mt6397/core.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/sched.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "mt6359.h" + +static void mt6359_set_playback_gpio(struct mt6359_priv *priv) +{ + /* set gpio mosi mode, clk / data mosi */ + regmap_write(priv->regmap, MT6359_GPIO_MODE2_CLR, 0x0ffe); + regmap_write(priv->regmap, MT6359_GPIO_MODE2_SET, 0x0249); + + /* sync mosi */ + regmap_write(priv->regmap, MT6359_GPIO_MODE3_CLR, 0x6); + regmap_write(priv->regmap, MT6359_GPIO_MODE3_SET, 0x1); +} + +static void mt6359_reset_playback_gpio(struct mt6359_priv *priv) +{ + /* set pad_aud_*_mosi to GPIO mode and dir input + * reason: + * pad_aud_dat_mosi*, because the pin is used as boot strap + * don't clean clk/sync, for mtkaif protocol 2 + */ + regmap_write(priv->regmap, MT6359_GPIO_MODE2_CLR, 0x0ff8); + regmap_update_bits(priv->regmap, MT6359_GPIO_DIR0, 0x7 << 9, 0x0); +} + +static void mt6359_set_capture_gpio(struct mt6359_priv *priv) +{ + /* set gpio miso mode */ + regmap_write(priv->regmap, MT6359_GPIO_MODE3_CLR, 0x0e00); + regmap_write(priv->regmap, MT6359_GPIO_MODE3_SET, 0x0200); + + regmap_write(priv->regmap, MT6359_GPIO_MODE4_CLR, 0x003f); + regmap_write(priv->regmap, MT6359_GPIO_MODE4_SET, 0x0009); +} + +static void mt6359_reset_capture_gpio(struct mt6359_priv *priv) +{ + /* set pad_aud_*_miso to GPIO mode and dir input + * reason: + * pad_aud_clk_miso, because when playback only the miso_clk + * will also have 26m, so will have power leak + * pad_aud_dat_miso*, because the pin is used as boot strap + */ + regmap_write(priv->regmap, MT6359_GPIO_MODE3_CLR, 0x0e00); + + regmap_write(priv->regmap, MT6359_GPIO_MODE4_CLR, 0x003f); + + regmap_update_bits(priv->regmap, MT6359_GPIO_DIR0, + 0x7 << 13, 0x0); + regmap_update_bits(priv->regmap, MT6359_GPIO_DIR1, + 0x3 << 0, 0x0); +} + +static void mt6359_set_decoder_clk(struct mt6359_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13, + RG_RSTB_DECODER_VA32_MASK_SFT, + (enable ? 1 : 0) << RG_RSTB_DECODER_VA32_SFT); +} + +static void mt6359_mtkaif_tx_enable(struct mt6359_priv *priv) +{ + switch (priv->mtkaif_protocol) { + case MT6359_MTKAIF_PROTOCOL_2_CLK_P2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6359_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0210); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6359_AFE_AUD_PAD_TOP, + 0xff00, 0x3800); + regmap_update_bits(priv->regmap, + MT6359_AFE_AUD_PAD_TOP, + 0xff00, 0x3900); + break; + case MT6359_MTKAIF_PROTOCOL_2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6359_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0210); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6359_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + case MT6359_MTKAIF_PROTOCOL_1: + default: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6359_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0000); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6359_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + } +} + +static void mt6359_mtkaif_tx_disable(struct mt6359_priv *priv) +{ + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6359_AFE_AUD_PAD_TOP, + 0xff00, 0x3000); +} + +static void zcd_disable(struct mt6359_priv *priv) +{ + regmap_write(priv->regmap, MT6359_ZCD_CON0, 0x0000); +} + +static void hp_main_output_ramp(struct mt6359_priv *priv, bool up) +{ + int i = 0, stage = 0; + int target = 7; + + /* Enable/Reduce HPL/R main output stage step by step */ + for (i = 0; i <= target; i++) { + stage = up ? i : target - i; + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, + RG_HPLOUTSTGCTRL_VAUDP32_MASK_SFT, + stage << RG_HPLOUTSTGCTRL_VAUDP32_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, + RG_HPROUTSTGCTRL_VAUDP32_MASK_SFT, + stage << RG_HPROUTSTGCTRL_VAUDP32_SFT); + usleep_range(600, 650); + } +} + +static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up) +{ + int i = 0, stage = 0; + int target = 0xf; + + /* Enable/Reduce HP aux feedback loop gain step by step */ + for (i = 0; i <= target; i++) { + stage = up ? i : target - i; + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON9, + 0xf << 12, stage << 12); + usleep_range(600, 650); + } +} + +static void hp_in_pair_current(struct mt6359_priv *priv, bool increase) +{ + int i = 0, stage = 0; + int target = 0x3; + + /* Set input diff pair bias select (Hi-Fi mode) */ + if (priv->hp_hifi_mode) { + /* Reduce HP aux feedback loop gain step by step */ + for (i = 0; i <= target; i++) { + stage = increase ? i : target - i; + regmap_update_bits(priv->regmap, + MT6359_AUDDEC_ANA_CON10, + 0x3 << 3, stage << 3); + usleep_range(100, 150); + } + } +} + +static void hp_pull_down(struct mt6359_priv *priv, bool enable) +{ + int i; + + if (enable) { + for (i = 0x0; i <= 0x7; i++) { + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON2, + RG_HPPSHORT2VCM_VAUDP32_MASK_SFT, + i << RG_HPPSHORT2VCM_VAUDP32_SFT); + usleep_range(100, 150); + } + } else { + for (i = 0x7; i >= 0x0; i--) { + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON2, + RG_HPPSHORT2VCM_VAUDP32_MASK_SFT, + i << RG_HPPSHORT2VCM_VAUDP32_SFT); + usleep_range(100, 150); + } + } +} + +static bool is_valid_hp_pga_idx(int reg_idx) +{ + return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_22DB) || + reg_idx == DL_GAIN_N_40DB; +} + +static void headset_volume_ramp(struct mt6359_priv *priv, + int from, int to) +{ + int offset = 0, count = 1, reg_idx; + + if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) { + dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n", + __func__, from, to); + return; + } + + dev_dbg(priv->dev, "%s(), from %d, to %d\n", __func__, from, to); + + if (to > from) + offset = to - from; + else + offset = from - to; + + while (offset > 0) { + if (to > from) + reg_idx = from + count; + else + reg_idx = from - count; + + if (is_valid_hp_pga_idx(reg_idx)) { + regmap_update_bits(priv->regmap, + MT6359_ZCD_CON2, + DL_GAIN_REG_MASK, + (reg_idx << 7) | reg_idx); + usleep_range(600, 650); + } + offset--; + count++; + } +} + +static int mt6359_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg; + int index = ucontrol->value.integer.value[0]; + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret < 0) + return ret; + + switch (mc->reg) { + case MT6359_ZCD_CON2: + regmap_read(priv->regmap, MT6359_ZCD_CON2, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = + (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK; + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = + (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK; + break; + case MT6359_ZCD_CON1: + regmap_read(priv->regmap, MT6359_ZCD_CON1, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] = + (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK; + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = + (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK; + break; + case MT6359_ZCD_CON3: + regmap_read(priv->regmap, MT6359_ZCD_CON3, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] = + (reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK; + break; + case MT6359_AUDENC_ANA_CON0: + regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON0, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = + (reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK; + break; + case MT6359_AUDENC_ANA_CON1: + regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON1, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = + (reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_MASK; + break; + case MT6359_AUDENC_ANA_CON2: + regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON2, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] = + (reg >> RG_AUDPREAMP3GAIN_SFT) & RG_AUDPREAMP3GAIN_MASK; + break; + } + + dev_dbg(priv->dev, "%s(), name %s, reg(0x%x) = 0x%x, set index = %x\n", + __func__, kcontrol->id.name, mc->reg, reg, index); + + return ret; +} + +/* MUX */ + +/* LOL MUX */ +static const char * const lo_in_mux_map[] = { + "Open", "Playback_L_DAC", "Playback", "Test Mode" +}; + +static SOC_ENUM_SINGLE_DECL(lo_in_mux_map_enum, SND_SOC_NOPM, 0, lo_in_mux_map); + +static const struct snd_kcontrol_new lo_in_mux_control = + SOC_DAPM_ENUM("LO Select", lo_in_mux_map_enum); + +/*HP MUX */ +static const char * const hp_in_mux_map[] = { + "Open", + "LoudSPK Playback", + "Audio Playback", + "Test Mode", + "HP Impedance", +}; + +static SOC_ENUM_SINGLE_DECL(hp_in_mux_map_enum, + SND_SOC_NOPM, + 0, + hp_in_mux_map); + +static const struct snd_kcontrol_new hp_in_mux_control = + SOC_DAPM_ENUM("HP Select", hp_in_mux_map_enum); + +/* RCV MUX */ +static const char * const rcv_in_mux_map[] = { + "Open", "Mute", "Voice Playback", "Test Mode" +}; + +static SOC_ENUM_SINGLE_DECL(rcv_in_mux_map_enum, + SND_SOC_NOPM, + 0, + rcv_in_mux_map); + +static const struct snd_kcontrol_new rcv_in_mux_control = + SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum); + +/* DAC In MUX */ +static const char * const dac_in_mux_map[] = { + "Normal Path", "Sgen" +}; + +static int dac_in_mux_map_value[] = { + 0x0, 0x1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum, + MT6359_AFE_TOP_CON0, + DL_SINE_ON_SFT, + DL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new dac_in_mux_control = + SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum); + +/* AIF Out MUX */ +static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum, + MT6359_AFE_TOP_CON0, + UL_SINE_ON_SFT, + UL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new aif_out_mux_control = + SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(aif2_out_mux_map_enum, + MT6359_AFE_TOP_CON0, + ADDA6_UL_SINE_ON_SFT, + ADDA6_UL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new aif2_out_mux_control = + SOC_DAPM_ENUM("AIF Out Select", aif2_out_mux_map_enum); + +static const char * const ul_src_mux_map[] = { + "AMIC", + "DMIC", +}; + +static int ul_src_mux_map_value[] = { + UL_SRC_MUX_AMIC, + UL_SRC_MUX_DMIC, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(ul_src_mux_map_enum, + MT6359_AFE_UL_SRC_CON0_L, + UL_SDM_3_LEVEL_CTL_SFT, + UL_SDM_3_LEVEL_CTL_MASK, + ul_src_mux_map, + ul_src_mux_map_value); + +static const struct snd_kcontrol_new ul_src_mux_control = + SOC_DAPM_ENUM("UL_SRC_MUX Select", ul_src_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(ul2_src_mux_map_enum, + MT6359_AFE_ADDA6_UL_SRC_CON0_L, + ADDA6_UL_SDM_3_LEVEL_CTL_SFT, + ADDA6_UL_SDM_3_LEVEL_CTL_MASK, + ul_src_mux_map, + ul_src_mux_map_value); + +static const struct snd_kcontrol_new ul2_src_mux_control = + SOC_DAPM_ENUM("UL_SRC_MUX Select", ul2_src_mux_map_enum); + +static const char * const miso_mux_map[] = { + "UL1_CH1", + "UL1_CH2", + "UL2_CH1", + "UL2_CH2", +}; + +static int miso_mux_map_value[] = { + MISO_MUX_UL1_CH1, + MISO_MUX_UL1_CH2, + MISO_MUX_UL2_CH1, + MISO_MUX_UL2_CH2, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(miso0_mux_map_enum, + MT6359_AFE_MTKAIF_MUX_CFG, + RG_ADDA_CH1_SEL_SFT, + RG_ADDA_CH1_SEL_MASK, + miso_mux_map, + miso_mux_map_value); + +static const struct snd_kcontrol_new miso0_mux_control = + SOC_DAPM_ENUM("MISO_MUX Select", miso0_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(miso1_mux_map_enum, + MT6359_AFE_MTKAIF_MUX_CFG, + RG_ADDA_CH2_SEL_SFT, + RG_ADDA_CH2_SEL_MASK, + miso_mux_map, + miso_mux_map_value); + +static const struct snd_kcontrol_new miso1_mux_control = + SOC_DAPM_ENUM("MISO_MUX Select", miso1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(miso2_mux_map_enum, + MT6359_AFE_MTKAIF_MUX_CFG, + RG_ADDA6_CH1_SEL_SFT, + RG_ADDA6_CH1_SEL_MASK, + miso_mux_map, + miso_mux_map_value); + +static const struct snd_kcontrol_new miso2_mux_control = + SOC_DAPM_ENUM("MISO_MUX Select", miso2_mux_map_enum); + +static const char * const dmic_mux_map[] = { + "DMIC_DATA0", + "DMIC_DATA1_L", + "DMIC_DATA1_L_1", + "DMIC_DATA1_R", +}; + +static int dmic_mux_map_value[] = { + DMIC_MUX_DMIC_DATA0, + DMIC_MUX_DMIC_DATA1_L, + DMIC_MUX_DMIC_DATA1_L_1, + DMIC_MUX_DMIC_DATA1_R, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(dmic0_mux_map_enum, + MT6359_AFE_MIC_ARRAY_CFG, + RG_DMIC_ADC1_SOURCE_SEL_SFT, + RG_DMIC_ADC1_SOURCE_SEL_MASK, + dmic_mux_map, + dmic_mux_map_value); + +static const struct snd_kcontrol_new dmic0_mux_control = + SOC_DAPM_ENUM("DMIC_MUX Select", dmic0_mux_map_enum); + +/* ul1 ch2 use RG_DMIC_ADC3_SOURCE_SEL */ +static SOC_VALUE_ENUM_SINGLE_DECL(dmic1_mux_map_enum, + MT6359_AFE_MIC_ARRAY_CFG, + RG_DMIC_ADC3_SOURCE_SEL_SFT, + RG_DMIC_ADC3_SOURCE_SEL_MASK, + dmic_mux_map, + dmic_mux_map_value); + +static const struct snd_kcontrol_new dmic1_mux_control = + SOC_DAPM_ENUM("DMIC_MUX Select", dmic1_mux_map_enum); + +/* ul2 ch1 use RG_DMIC_ADC2_SOURCE_SEL */ +static SOC_VALUE_ENUM_SINGLE_DECL(dmic2_mux_map_enum, + MT6359_AFE_MIC_ARRAY_CFG, + RG_DMIC_ADC2_SOURCE_SEL_SFT, + RG_DMIC_ADC2_SOURCE_SEL_MASK, + dmic_mux_map, + dmic_mux_map_value); + +static const struct snd_kcontrol_new dmic2_mux_control = + SOC_DAPM_ENUM("DMIC_MUX Select", dmic2_mux_map_enum); + +/* ADC L MUX */ +static const char * const adc_left_mux_map[] = { + "Idle", "AIN0", "Left Preamplifier", "Idle_1" +}; + +static int adc_mux_map_value[] = { + ADC_MUX_IDLE, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum, + MT6359_AUDENC_ANA_CON0, + RG_AUDADCLINPUTSEL_SFT, + RG_AUDADCLINPUTSEL_MASK, + adc_left_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_left_mux_control = + SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum); + +/* ADC R MUX */ +static const char * const adc_right_mux_map[] = { + "Idle", "AIN0", "Right Preamplifier", "Idle_1" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum, + MT6359_AUDENC_ANA_CON1, + RG_AUDADCRINPUTSEL_SFT, + RG_AUDADCRINPUTSEL_MASK, + adc_right_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_right_mux_control = + SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum); + +/* ADC 3 MUX */ +static const char * const adc_3_mux_map[] = { + "Idle", "AIN0", "Preamplifier", "Idle_1" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_3_mux_map_enum, + MT6359_AUDENC_ANA_CON2, + RG_AUDADC3INPUTSEL_SFT, + RG_AUDADC3INPUTSEL_MASK, + adc_3_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_3_mux_control = + SOC_DAPM_ENUM("ADC 3 Select", adc_3_mux_map_enum); + +static const char * const pga_l_mux_map[] = { + "None", "AIN0", "AIN1" +}; + +static int pga_l_mux_map_value[] = { + PGA_L_MUX_NONE, + PGA_L_MUX_AIN0, + PGA_L_MUX_AIN1 +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum, + MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLINPUTSEL_SFT, + RG_AUDPREAMPLINPUTSEL_MASK, + pga_l_mux_map, + pga_l_mux_map_value); + +static const struct snd_kcontrol_new pga_left_mux_control = + SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum); + +static const char * const pga_r_mux_map[] = { + "None", "AIN2", "AIN3", "AIN0" +}; + +static int pga_r_mux_map_value[] = { + PGA_R_MUX_NONE, + PGA_R_MUX_AIN2, + PGA_R_MUX_AIN3, + PGA_R_MUX_AIN0 +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum, + MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRINPUTSEL_SFT, + RG_AUDPREAMPRINPUTSEL_MASK, + pga_r_mux_map, + pga_r_mux_map_value); + +static const struct snd_kcontrol_new pga_right_mux_control = + SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum); + +static const char * const pga_3_mux_map[] = { + "None", "AIN3", "AIN2" +}; + +static int pga_3_mux_map_value[] = { + PGA_3_MUX_NONE, + PGA_3_MUX_AIN3, + PGA_3_MUX_AIN2 +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pga_3_mux_map_enum, + MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3INPUTSEL_SFT, + RG_AUDPREAMP3INPUTSEL_MASK, + pga_3_mux_map, + pga_3_mux_map_value); + +static const struct snd_kcontrol_new pga_3_mux_control = + SOC_DAPM_ENUM("PGA 3 Select", pga_3_mux_map_enum); + +static int mt_sgen_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON2, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON0, 0xcba1); + /* sdm power on */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON2, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON2, 0x000b); + + regmap_update_bits(priv->regmap, MT6359_AFE_SGEN_CFG0, + 0xff3f, + 0x0000); + regmap_update_bits(priv->regmap, MT6359_AFE_SGEN_CFG1, + 0xffff, + 0x0001); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON2, 0x0000); + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON0, 0xcba0); + break; + default: + break; + } + + return 0; +} + +static void mtk_hp_enable(struct mt6359_priv *priv) +{ + if (priv->hp_hifi_mode) { + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON11, + DRBIAS_HP_MASK_SFT, + DRBIAS_6UA << DRBIAS_HP_SFT); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_ZCD_MASK_SFT, + IBIAS_ZCD_4UA << IBIAS_ZCD_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_HP_MASK_SFT, + IBIAS_5UA << IBIAS_HP_SFT); + } else { + /* Set HP DR bias current optimization, 001: 5uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON11, + DRBIAS_HP_MASK_SFT, + DRBIAS_5UA << DRBIAS_HP_SFT); + /* Set HP & ZCD bias current optimization */ + /* 00: ZCD: 3uA, HP/HS/LO: 4uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_ZCD_MASK_SFT, + IBIAS_ZCD_3UA << IBIAS_ZCD_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_HP_MASK_SFT, + IBIAS_4UA << IBIAS_HP_SFT); + } + + /* HP damp circuit enable */ + /* Enable HPRN/HPLN output 4K to VCM */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON10, 0x0087); + + /* HP Feedback Cap select 2'b00: 15pF */ + /* for >= 96KHz sampling rate: 2'b01: 10.5pF */ + if (priv->dl_rate[MT6359_AIF_1] >= 96000) + regmap_update_bits(priv->regmap, + MT6359_AUDDEC_ANA_CON4, + RG_AUDHPHFCOMPBUFGAINSEL_VAUDP32_MASK_SFT, + 0x1 << RG_AUDHPHFCOMPBUFGAINSEL_VAUDP32_SFT); + else + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON4, 0x0000); + + /* Set HPP/N STB enhance circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON2, 0xf133); + + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x000c); + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x003c); + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0c00); + /* Enable HP driver bias circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x30c0); + /* Enable HP driver core circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x30f0); + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x00fc); + + /* Increase HP input pair current to HPM step by step */ + hp_in_pair_current(priv, true); + + /* Enable HP main CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0e00); + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0200); + + /* Enable HP main output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x00ff); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, true); + /* Disable HP aux feedback loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x77cf); + + /* apply volume setting */ + headset_volume_ramp(priv, + DL_GAIN_N_22DB, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]); + + /* Disable HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x77c3); + /* Unshort HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x7703); + usleep_range(100, 120); + + /* Enable AUD_CLK */ + mt6359_set_decoder_clk(priv, true); + + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x30ff); + if (priv->hp_hifi_mode) { + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0xf201); + } else { + /* Disable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0xf200); + } + usleep_range(100, 120); + + /* Switch HPL MUX to audio DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x32ff); + /* Switch HPR MUX to audio DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x3aff); + + /* Disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); +} + +static void mtk_hp_disable(struct mt6359_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + + /* HPR/HPL mux to open */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x0f00, 0x0000); + + /* Disable low-noise mode of DAC */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON9, + 0x0001, 0x0000); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + mt6359_set_decoder_clk(priv, false); + + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x77c3); + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x77cf); + + /* decrease HPL/R gain to normal gain step by step */ + headset_volume_ramp(priv, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL], + DL_GAIN_N_22DB); + + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x77ff); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, 0x3, 0x0); + + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0e01); + + /* Disable HP main CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0c01); + + /* Decrease HP input pair current to 2'b00 step by step */ + hp_in_pair_current(priv, false); + + /* Unshort HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, + 0x3 << 6, 0x0); + + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x3 << 4, 0x0); + + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x3 << 6, 0x0); + + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x201); + + /* Disable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, + 0x3 << 4, 0x0); + + /* Disable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON1, + 0x3 << 2, 0x0); +} + +static int mt_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + int device = DEVICE_HP; + + dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n", + __func__, event, priv->dev_counter[device], mux); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->dev_counter[device]++; + if (mux == HP_MUX_HP) + mtk_hp_enable(priv); + break; + case SND_SOC_DAPM_PRE_PMD: + priv->dev_counter[device]--; + if (mux == HP_MUX_HP) + mtk_hp_disable(priv); + break; + default: + break; + } + + return 0; +} + +static int mt_rcv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, event, dapm_kcontrol_get_value(w->kcontrols[0])); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disable handset short-circuit protection */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON6, 0x0010); + + /* Set RCV DR bias current optimization, 010: 6uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON11, + DRBIAS_HS_MASK_SFT, + DRBIAS_6UA << DRBIAS_HS_SFT); + /* Set RCV & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_ZCD_MASK_SFT, + IBIAS_ZCD_4UA << IBIAS_ZCD_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_HS_MASK_SFT, + IBIAS_5UA << IBIAS_HS_SFT); + + /* Set HS STB enhance circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON6, 0x0090); + + /* Set HS output stage (3'b111 = 8x) */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON10, 0x7000); + + /* Enable HS driver bias circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON6, 0x0092); + /* Enable HS driver core circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON6, 0x0093); + + /* Set HS gain to normal gain step by step */ + regmap_write(priv->regmap, MT6359_ZCD_CON3, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]); + + /* Enable AUD_CLK */ + mt6359_set_decoder_clk(priv, true); + + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x0009); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0001); + /* Switch HS MUX to audio DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON6, 0x009b); + break; + case SND_SOC_DAPM_PRE_PMD: + /* HS mux to open */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON6, + RG_AUDHSMUXINPUTSEL_VAUDP32_MASK_SFT, + RCV_MUX_OPEN); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + mt6359_set_decoder_clk(priv, false); + + /* decrease HS gain to minimum gain step by step */ + regmap_write(priv->regmap, MT6359_ZCD_CON3, DL_GAIN_N_40DB); + + /* Disable HS driver core circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON6, + RG_AUDHSPWRUP_VAUDP32_MASK_SFT, 0x0); + + /* Disable HS driver bias circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON6, + RG_AUDHSPWRUP_IBIAS_VAUDP32_MASK_SFT, 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_lo_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, event, dapm_kcontrol_get_value(w->kcontrols[0])); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disable handset short-circuit protection */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0010); + + /* Set LO DR bias current optimization, 010: 6uA */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON11, + DRBIAS_LO_MASK_SFT, + DRBIAS_6UA << DRBIAS_LO_SFT); + /* Set LO & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + if (priv->dev_counter[DEVICE_HP] == 0) + regmap_update_bits(priv->regmap, + MT6359_AUDDEC_ANA_CON12, + IBIAS_ZCD_MASK_SFT, + IBIAS_ZCD_4UA << IBIAS_ZCD_SFT); + + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON12, + IBIAS_LO_MASK_SFT, + IBIAS_5UA << IBIAS_LO_SFT); + + /* Set LO STB enhance circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0110); + + /* Enable LO driver bias circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0112); + /* Enable LO driver core circuits */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0113); + + /* Set LO gain to normal gain step by step */ + regmap_write(priv->regmap, MT6359_ZCD_CON1, + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]); + + /* Enable AUD_CLK */ + mt6359_set_decoder_clk(priv, true); + + /* Enable Audio DAC (3rd DAC) */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x3113); + /* Enable low-noise mode of DAC */ + if (priv->dev_counter[DEVICE_HP] == 0) + regmap_write(priv->regmap, + MT6359_AUDDEC_ANA_CON9, 0x0001); + /* Switch LOL MUX to audio 3rd DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x311b); + break; + case SND_SOC_DAPM_PRE_PMD: + /* Switch LOL MUX to open */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON7, + RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK_SFT, + LO_MUX_OPEN); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + mt6359_set_decoder_clk(priv, false); + + /* decrease LO gain to minimum gain step by step */ + regmap_write(priv->regmap, MT6359_ZCD_CON1, DL_GAIN_N_40DB); + + /* Disable LO driver core circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON7, + RG_AUDLOLPWRUP_VAUDP32_MASK_SFT, 0x0); + + /* Disable LO driver bias circuits */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON7, + RG_AUDLOLPWRUP_IBIAS_VAUDP32_MASK_SFT, 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_clk_gen_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* ADC CLK from CLKGEN (6.5MHz) */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKRSTB_MASK_SFT, + 0x1 << RG_AUDADCCLKRSTB_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKSOURCE_MASK_SFT, 0x0); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKSEL_MASK_SFT, 0x0); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKGENMODE_MASK_SFT, + 0x1 << RG_AUDADCCLKGENMODE_SFT); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKSOURCE_MASK_SFT, 0x0); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKSEL_MASK_SFT, 0x0); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKGENMODE_MASK_SFT, 0x0); + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON5, + RG_AUDADCCLKRSTB_MASK_SFT, 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_dcc_clk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* DCC 50k CLK (from 26M) */ + /* MT6359_AFE_DCCLK_CFG0, bit 3 for dm ck swap */ + regmap_update_bits(priv->regmap, MT6359_AFE_DCCLK_CFG0, + 0xfff7, 0x2062); + regmap_update_bits(priv->regmap, MT6359_AFE_DCCLK_CFG0, + 0xfff7, 0x2060); + regmap_update_bits(priv->regmap, MT6359_AFE_DCCLK_CFG0, + 0xfff7, 0x2061); + + regmap_write(priv->regmap, MT6359_AFE_DCCLK_CFG1, 0x0100); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(priv->regmap, MT6359_AFE_DCCLK_CFG0, + 0xfff7, 0x2060); + regmap_update_bits(priv->regmap, MT6359_AFE_DCCLK_CFG0, + 0xfff7, 0x2062); + break; + default: + break; + } + + return 0; +} + +static int mt_mic_bias_0_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE_0]; + + dev_dbg(priv->dev, "%s(), event 0x%x, mic_type %d\n", + __func__, event, mic_type); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mic_type) { + case MIC_TYPE_MUX_DCC_ECM_DIFF: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON15, + 0xff00, 0x7700); + break; + case MIC_TYPE_MUX_DCC_ECM_SINGLE: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON15, + 0xff00, 0x1100); + break; + default: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON15, + 0xff00, 0x0000); + break; + } + + /* DMIC enable */ + regmap_write(priv->regmap, + MT6359_AUDENC_ANA_CON14, 0x0004); + /* MISBIAS0 = 1P9V */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON15, + RG_AUDMICBIAS0VREF_MASK_SFT, + MIC_BIAS_1P9 << RG_AUDMICBIAS0VREF_SFT); + /* normal power select */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON15, + RG_AUDMICBIAS0LOWPEN_MASK_SFT, + 0 << RG_AUDMICBIAS0LOWPEN_SFT); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable MICBIAS0, MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6359_AUDENC_ANA_CON15, 0x0000); + break; + default: + break; + } + + return 0; +} + +static int mt_mic_bias_1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE_1]; + + dev_dbg(priv->dev, "%s(), event 0x%x, mic_type %d\n", + __func__, event, mic_type); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* MISBIAS1 = 2P6V */ + if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE) + regmap_write(priv->regmap, + MT6359_AUDENC_ANA_CON16, 0x0160); + else + regmap_write(priv->regmap, + MT6359_AUDENC_ANA_CON16, 0x0060); + + /* normal power select */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON16, + RG_AUDMICBIAS1LOWPEN_MASK_SFT, + 0 << RG_AUDMICBIAS1LOWPEN_SFT); + break; + default: + break; + } + + return 0; +} + +static int mt_mic_bias_2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE_2]; + + dev_dbg(priv->dev, "%s(), event 0x%x, mic_type %d\n", + __func__, event, mic_type); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mic_type) { + case MIC_TYPE_MUX_DCC_ECM_DIFF: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON17, + 0xff00, 0x7700); + break; + case MIC_TYPE_MUX_DCC_ECM_SINGLE: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON17, + 0xff00, 0x1100); + break; + default: + regmap_update_bits(priv->regmap, + MT6359_AUDENC_ANA_CON17, + 0xff00, 0x0000); + break; + } + + /* MISBIAS2 = 1P9V */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON17, + RG_AUDMICBIAS2VREF_MASK_SFT, + MIC_BIAS_1P9 << RG_AUDMICBIAS2VREF_SFT); + /* normal power select */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON17, + RG_AUDMICBIAS2LOWPEN_MASK_SFT, + 0 << RG_AUDMICBIAS2LOWPEN_SFT); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable MICBIAS2, MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6359_AUDENC_ANA_CON17, 0x0000); + break; + default: + break; + } + + return 0; +} + +static int mt_mtkaif_tx_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt6359_mtkaif_tx_enable(priv); + break; + case SND_SOC_DAPM_POST_PMD: + mt6359_mtkaif_tx_disable(priv); + break; + default: + break; + } + + return 0; +} + +static int mt_ul_src_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* UL dmic setting */ + if (priv->dmic_one_wire_mode) + regmap_write(priv->regmap, MT6359_AFE_UL_SRC_CON0_H, + 0x0400); + else + regmap_write(priv->regmap, MT6359_AFE_UL_SRC_CON0_H, + 0x0080); + /* default one wire, 3.25M */ + regmap_update_bits(priv->regmap, MT6359_AFE_UL_SRC_CON0_L, + 0xfffc, 0x0000); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_write(priv->regmap, + MT6359_AFE_UL_SRC_CON0_H, 0x0000); + break; + default: + break; + } + + return 0; +} + +static int mt_ul_src_34_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* default two wire, 3.25M */ + regmap_write(priv->regmap, + MT6359_AFE_ADDA6_L_SRC_CON0_H, 0x0080); + regmap_update_bits(priv->regmap, MT6359_AFE_ADDA6_UL_SRC_CON0_L, + 0xfffc, 0x0000); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_write(priv->regmap, + MT6359_AFE_ADDA6_L_SRC_CON0_H, 0x0000); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_l_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(100, 120); + /* Audio L preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, + 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_r_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(100, 120); + /* Audio R preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCPRECHARGE_MASK_SFT, + 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_3_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(100, 120); + /* Audio R preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3DCPRECHARGE_MASK_SFT, + 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_pga_l_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux); + priv->mux_select[MUX_PGA_L] = mux >> RG_AUDPREAMPLINPUTSEL_SFT; + return 0; +} + +static int mt_pga_r_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux); + priv->mux_select[MUX_PGA_R] = mux >> RG_AUDPREAMPRINPUTSEL_SFT; + return 0; +} + +static int mt_pga_3_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux); + priv->mux_select[MUX_PGA_3] = mux >> RG_AUDPREAMP3INPUTSEL_SFT; + return 0; +} + +static int mt_pga_l_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int mic_gain_l = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1]; + unsigned int mux_pga = priv->mux_select[MUX_PGA_L]; + unsigned int mic_type; + + switch (mux_pga) { + case PGA_L_MUX_AIN0: + mic_type = priv->mux_select[MUX_MIC_TYPE_0]; + break; + case PGA_L_MUX_AIN1: + mic_type = priv->mux_select[MUX_MIC_TYPE_1]; + break; + default: + dev_err(priv->dev, "%s(), invalid pga mux %d\n", + __func__, mux_pga); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (IS_DCC_BASE(mic_type)) { + /* Audio L preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, + 0x1 << RG_AUDPREAMPLDCPRECHARGE_SFT); + } + break; + case SND_SOC_DAPM_POST_PMU: + /* set mic pga gain */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLGAIN_MASK_SFT, + mic_gain_l << RG_AUDPREAMPLGAIN_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPLDCCEN_SFT); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCCEN_MASK_SFT, + 0x0 << RG_AUDPREAMPLDCCEN_SFT); + break; + default: + break; + } + + return 0; +} + +static int mt_pga_r_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int mic_gain_r = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2]; + unsigned int mux_pga = priv->mux_select[MUX_PGA_R]; + unsigned int mic_type; + + switch (mux_pga) { + case PGA_R_MUX_AIN0: + mic_type = priv->mux_select[MUX_MIC_TYPE_0]; + break; + case PGA_R_MUX_AIN2: + case PGA_R_MUX_AIN3: + mic_type = priv->mux_select[MUX_MIC_TYPE_2]; + break; + default: + dev_err(priv->dev, "%s(), invalid pga mux %d\n", + __func__, mux_pga); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (IS_DCC_BASE(mic_type)) { + /* Audio R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCPRECHARGE_MASK_SFT, + 0x1 << RG_AUDPREAMPRDCPRECHARGE_SFT); + } + break; + case SND_SOC_DAPM_POST_PMU: + /* set mic pga gain */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRGAIN_MASK_SFT, + mic_gain_r << RG_AUDPREAMPRGAIN_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPRDCCEN_SFT); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCCEN_MASK_SFT, + 0x0 << RG_AUDPREAMPRDCCEN_SFT); + break; + default: + break; + } + + return 0; +} + +static int mt_pga_3_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int mic_gain_3 = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3]; + unsigned int mux_pga = priv->mux_select[MUX_PGA_3]; + unsigned int mic_type; + + switch (mux_pga) { + case PGA_3_MUX_AIN2: + case PGA_3_MUX_AIN3: + mic_type = priv->mux_select[MUX_MIC_TYPE_2]; + break; + default: + dev_err(priv->dev, "%s(), invalid pga mux %d\n", + __func__, mux_pga); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (IS_DCC_BASE(mic_type)) { + /* Audio 3 preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3DCPRECHARGE_MASK_SFT, + 0x1 << RG_AUDPREAMP3DCPRECHARGE_SFT); + } + break; + case SND_SOC_DAPM_POST_PMU: + /* set mic pga gain */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3GAIN_MASK_SFT, + mic_gain_3 << RG_AUDPREAMP3GAIN_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* 3 preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3DCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMP3DCCEN_SFT); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* 3 preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3DCCEN_MASK_SFT, + 0x0 << RG_AUDPREAMP3DCCEN_SFT); + break; + default: + break; + } + + return 0; +} + +/* It is based on hw's control sequenece to add some delay when PMU/PMD */ +static int mt_delay_250_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMD: + usleep_range(250, 270); + break; + default: + break; + } + + return 0; +} + +static int mt_delay_100_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_PRE_PMD: + usleep_range(100, 120); + break; + default: + break; + } + + return 0; +} + +static int mt_hp_pull_down_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hp_pull_down(priv, true); + break; + case SND_SOC_DAPM_POST_PMD: + hp_pull_down(priv, false); + break; + default: + break; + } + + return 0; +} + +static int mt_hp_mute_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Set HPR/HPL gain to -22dB */ + regmap_write(priv->regmap, MT6359_ZCD_CON2, DL_GAIN_N_22DB_REG); + break; + case SND_SOC_DAPM_POST_PMD: + /* Set HPL/HPR gain to mute */ + regmap_write(priv->regmap, MT6359_ZCD_CON2, DL_GAIN_N_40DB_REG); + break; + default: + break; + } + + return 0; +} + +static int mt_hp_damp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* Disable HP damping circuit & HPN 4K load */ + /* reset CMFB PW level */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON10, 0x0000); + break; + default: + break; + } + + return 0; +} + +static int mt_esd_resist_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reduce ESD resistance of AU_REFN */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON2, + RG_AUDREFN_DERES_EN_VAUDP32_MASK_SFT, + 0x1 << RG_AUDREFN_DERES_EN_VAUDP32_SFT); + usleep_range(250, 270); + break; + case SND_SOC_DAPM_POST_PMD: + /* Increase ESD resistance of AU_REFN */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON2, + RG_AUDREFN_DERES_EN_VAUDP32_MASK_SFT, 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_sdm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* sdm audio fifo clock power on */ + regmap_update_bits(priv->regmap, MT6359_AFUNC_AUD_CON2, + 0xfffd, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON0, 0xcba1); + /* sdm power on */ + regmap_update_bits(priv->regmap, MT6359_AFUNC_AUD_CON2, + 0xfffd, 0x0003); + /* sdm fifo enable */ + regmap_update_bits(priv->regmap, MT6359_AFUNC_AUD_CON2, + 0xfffd, 0x000B); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_update_bits(priv->regmap, MT6359_AFUNC_AUD_CON2, + 0xfffd, 0x0000); + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON0, 0xcba0); + break; + default: + break; + } + + return 0; +} + +static int mt_sdm_3rd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON11, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON9, 0xcba1); + /* sdm power on */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON11, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON11, 0x000b); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON11, 0x0000); + regmap_write(priv->regmap, MT6359_AFUNC_AUD_CON9, 0xcba0); + break; + default: + break; + } + + return 0; +} + +static int mt_ncp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_write(priv->regmap, MT6359_AFE_NCP_CFG0, 0xc800); + break; + default: + break; + } + + return 0; +} + +/* DAPM Widgets */ +static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = { + /* Global Supply*/ + SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, + MT6359_DCXO_CW12, + RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO_VAUD18", SUPPLY_SEQ_LDO_VAUD18, + MT6359_LDO_VAUD18_CON0, + RG_LDO_VAUD18_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, + MT6359_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA32_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ, + MT6359_AUDENC_ANA_CON23, + RG_CLKSQ_EN_SFT, 0, NULL, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK, + MT6359_AUD_TOP_CKPDN_CON0, + RG_AUDNCP_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK, + MT6359_AUD_TOP_CKPDN_CON0, + RG_ZCD13M_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST, + MT6359_AUD_TOP_CKPDN_CON0, + RG_AUD_CK_PDN_SFT, 1, mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, + MT6359_AUD_TOP_CKPDN_CON0, + RG_AUDIF_CK_PDN_SFT, 1, NULL, 0), + /* Digital Clock */ + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, + MT6359_AUDIO_TOP_CON0, + PDN_AFE_CTL_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_DAC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_ADC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADDA6_ADC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_ADDA6_ADC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_I2S_DL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PWR_CLK_DIS_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP, + MT6359_AUDIO_TOP_CON0, + PDN_RESERVED_SFT, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("SDM", SUPPLY_SEQ_DL_SDM, + SND_SOC_NOPM, 0, 0, + mt_sdm_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("SDM_3RD", SUPPLY_SEQ_DL_SDM, + SND_SOC_NOPM, 0, 0, + mt_sdm_3rd_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* ch123 share SDM FIFO CLK */ + SND_SOC_DAPM_SUPPLY_S("SDM_FIFO_CLK", SUPPLY_SEQ_DL_SDM_FIFO_CLK, + MT6359_AFUNC_AUD_CON2, + CCI_AFIFO_CLK_PWDB_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("NCP", SUPPLY_SEQ_DL_NCP, + MT6359_AFE_NCP_CFG0, + RG_NCP_ON_SFT, 0, + mt_ncp_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DL Digital Clock CH_1_2", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DL Digital Clock CH_3", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* AFE ON */ + SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE, + MT6359_AFE_UL_DL_CON0, AFE_ON_SFT, 0, + NULL, 0), + + /* AIF Rx*/ + SND_SOC_DAPM_AIF_IN("AIF_RX", "AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("AIF2_RX", "AIF2 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY_S("AFE_DL_SRC", SUPPLY_SEQ_DL_SRC, + MT6359_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + NULL, 0), + + /* DL Supply */ + SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM, + 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ESD_RESIST", SUPPLY_SEQ_DL_ESD_RESIST, + SND_SOC_NOPM, + 0, 0, + mt_esd_resist_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("LDO", SUPPLY_SEQ_DL_LDO, + MT6359_AUDDEC_ANA_CON14, + RG_LCLDO_DEC_EN_VA32_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO_REMOTE", SUPPLY_SEQ_DL_LDO_REMOTE_SENSE, + MT6359_AUDDEC_ANA_CON14, + RG_LCLDO_DEC_REMOTE_SENSE_VA18_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("NV_REGULATOR", SUPPLY_SEQ_DL_NV, + MT6359_AUDDEC_ANA_CON14, + RG_NVREG_EN_VAUDP32_SFT, 0, + mt_delay_100_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY_S("IBIST", SUPPLY_SEQ_DL_IBIST, + MT6359_AUDDEC_ANA_CON12, + RG_AUDIBIASPWRDN_VAUDP32_SFT, 1, + NULL, 0), + + /* DAC */ + SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control), + + SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("DAC_3RD", NULL, SND_SOC_NOPM, 0, 0), + + /* Headphone */ + SND_SOC_DAPM_MUX_E("HP Mux", SND_SOC_NOPM, 0, 0, + &hp_in_mux_control, + mt_hp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("HP_Supply", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("HP_PULL_DOWN", SUPPLY_SEQ_HP_PULL_DOWN, + SND_SOC_NOPM, + 0, 0, + mt_hp_pull_down_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("HP_MUTE", SUPPLY_SEQ_HP_MUTE, + SND_SOC_NOPM, + 0, 0, + mt_hp_mute_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("HP_DAMP", SUPPLY_SEQ_HP_DAMPING_OFF_RESET_CMFB, + SND_SOC_NOPM, + 0, 0, + mt_hp_damp_event, + SND_SOC_DAPM_POST_PMD), + + /* Receiver */ + SND_SOC_DAPM_MUX_E("RCV Mux", SND_SOC_NOPM, 0, 0, + &rcv_in_mux_control, + mt_rcv_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + /* LOL */ + SND_SOC_DAPM_MUX_E("LOL Mux", SND_SOC_NOPM, 0, 0, + &lo_in_mux_control, + mt_lo_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("Receiver"), + SND_SOC_DAPM_OUTPUT("Headphone L"), + SND_SOC_DAPM_OUTPUT("Headphone R"), + SND_SOC_DAPM_OUTPUT("Headphone L Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("Headphone R Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("LINEOUT L"), + + /* SGEN */ + SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6359_AFE_SGEN_CFG0, + SGEN_DAC_EN_CTL_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6359_AFE_SGEN_CFG0, + SGEN_MUTE_SW_CTL_SFT, 1, + mt_sgen_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6359_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0), + + SND_SOC_DAPM_INPUT("SGEN DL"), + + /* Uplinks */ + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY_S("ADC_CLKGEN", SUPPLY_SEQ_ADC_CLKGEN, + SND_SOC_NOPM, 0, 0, + mt_adc_clk_gen_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY_S("DCC_CLK", SUPPLY_SEQ_DCC_CLK, + SND_SOC_NOPM, 0, 0, + mt_dcc_clk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Uplinks MUX */ + SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0, + &aif_out_mux_control), + + SND_SOC_DAPM_MUX("AIF2 Out Mux", SND_SOC_NOPM, 0, 0, + &aif2_out_mux_control), + + SND_SOC_DAPM_SUPPLY("AIFTX_Supply", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("MTKAIF_TX", SUPPLY_SEQ_UL_MTKAIF, + SND_SOC_NOPM, 0, 0, + mt_mtkaif_tx_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("UL_SRC", SUPPLY_SEQ_UL_SRC, + MT6359_AFE_UL_SRC_CON0_L, + UL_SRC_ON_TMP_CTL_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("UL_SRC_DMIC", SUPPLY_SEQ_UL_SRC_DMIC, + SND_SOC_NOPM, 0, 0, + mt_ul_src_dmic_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("UL_SRC_34", SUPPLY_SEQ_UL_SRC, + MT6359_AFE_ADDA6_UL_SRC_CON0_L, + ADDA6_UL_SRC_ON_TMP_CTL_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("UL_SRC_34_DMIC", SUPPLY_SEQ_UL_SRC_DMIC, + SND_SOC_NOPM, 0, 0, + mt_ul_src_34_dmic_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("MISO0_MUX", SND_SOC_NOPM, 0, 0, &miso0_mux_control), + SND_SOC_DAPM_MUX("MISO1_MUX", SND_SOC_NOPM, 0, 0, &miso1_mux_control), + SND_SOC_DAPM_MUX("MISO2_MUX", SND_SOC_NOPM, 0, 0, &miso2_mux_control), + + SND_SOC_DAPM_MUX("UL_SRC_MUX", SND_SOC_NOPM, 0, 0, + &ul_src_mux_control), + SND_SOC_DAPM_MUX("UL2_SRC_MUX", SND_SOC_NOPM, 0, 0, + &ul2_src_mux_control), + + SND_SOC_DAPM_MUX("DMIC0_MUX", SND_SOC_NOPM, 0, 0, &dmic0_mux_control), + SND_SOC_DAPM_MUX("DMIC1_MUX", SND_SOC_NOPM, 0, 0, &dmic1_mux_control), + SND_SOC_DAPM_MUX("DMIC2_MUX", SND_SOC_NOPM, 0, 0, &dmic2_mux_control), + + SND_SOC_DAPM_MUX_E("ADC_L_Mux", SND_SOC_NOPM, 0, 0, + &adc_left_mux_control, NULL, 0), + SND_SOC_DAPM_MUX_E("ADC_R_Mux", SND_SOC_NOPM, 0, 0, + &adc_right_mux_control, NULL, 0), + SND_SOC_DAPM_MUX_E("ADC_3_Mux", SND_SOC_NOPM, 0, 0, + &adc_3_mux_control, NULL, 0), + + SND_SOC_DAPM_ADC("ADC_L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC_R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC_3", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY_S("ADC_L_EN", SUPPLY_SEQ_UL_ADC, + MT6359_AUDENC_ANA_CON0, + RG_AUDADCLPWRUP_SFT, 0, + mt_adc_l_event, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY_S("ADC_R_EN", SUPPLY_SEQ_UL_ADC, + MT6359_AUDENC_ANA_CON1, + RG_AUDADCRPWRUP_SFT, 0, + mt_adc_r_event, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY_S("ADC_3_EN", SUPPLY_SEQ_UL_ADC, + MT6359_AUDENC_ANA_CON2, + RG_AUDADC3PWRUP_SFT, 0, + mt_adc_3_event, + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("PGA_L_Mux", SND_SOC_NOPM, 0, 0, + &pga_left_mux_control, + mt_pga_l_mux_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("PGA_R_Mux", SND_SOC_NOPM, 0, 0, + &pga_right_mux_control, + mt_pga_r_mux_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("PGA_3_Mux", SND_SOC_NOPM, 0, 0, + &pga_3_mux_control, + mt_pga_3_mux_event, + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_PGA("PGA_L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA_R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA_3", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("PGA_L_EN", SUPPLY_SEQ_UL_PGA, + MT6359_AUDENC_ANA_CON0, + RG_AUDPREAMPLON_SFT, 0, + mt_pga_l_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("PGA_R_EN", SUPPLY_SEQ_UL_PGA, + MT6359_AUDENC_ANA_CON1, + RG_AUDPREAMPRON_SFT, 0, + mt_pga_r_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("PGA_3_EN", SUPPLY_SEQ_UL_PGA, + MT6359_AUDENC_ANA_CON2, + RG_AUDPREAMP3ON_SFT, 0, + mt_pga_3_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* UL input */ + SND_SOC_DAPM_INPUT("AIN0"), + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + SND_SOC_DAPM_INPUT("AIN3"), + + SND_SOC_DAPM_INPUT("AIN0_DMIC"), + SND_SOC_DAPM_INPUT("AIN2_DMIC"), + SND_SOC_DAPM_INPUT("AIN3_DMIC"), + + /* mic bias */ + SND_SOC_DAPM_SUPPLY_S("MIC_BIAS_0", SUPPLY_SEQ_MIC_BIAS, + MT6359_AUDENC_ANA_CON15, + RG_AUDPWDBMICBIAS0_SFT, 0, + mt_mic_bias_0_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("MIC_BIAS_1", SUPPLY_SEQ_MIC_BIAS, + MT6359_AUDENC_ANA_CON16, + RG_AUDPWDBMICBIAS1_SFT, 0, + mt_mic_bias_1_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("MIC_BIAS_2", SUPPLY_SEQ_MIC_BIAS, + MT6359_AUDENC_ANA_CON17, + RG_AUDPWDBMICBIAS2_SFT, 0, + mt_mic_bias_2_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* dmic */ + SND_SOC_DAPM_SUPPLY_S("DMIC_0", SUPPLY_SEQ_DMIC, + MT6359_AUDENC_ANA_CON13, + RG_AUDDIGMICEN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC_1", SUPPLY_SEQ_DMIC, + MT6359_AUDENC_ANA_CON14, + RG_AUDDIGMIC1EN_SFT, 0, + NULL, 0), +}; + +static int mt_dcc_clk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + if (IS_DCC_BASE(priv->mux_select[MUX_MIC_TYPE_0]) || + IS_DCC_BASE(priv->mux_select[MUX_MIC_TYPE_1]) || + IS_DCC_BASE(priv->mux_select[MUX_MIC_TYPE_2])) + return 1; + else + return 0; +} + +static const struct snd_soc_dapm_route mt6359_dapm_routes[] = { + /* Capture */ + {"AIFTX_Supply", NULL, "CLK_BUF"}, + {"AIFTX_Supply", NULL, "LDO_VAUD18"}, + {"AIFTX_Supply", NULL, "AUDGLB"}, + {"AIFTX_Supply", NULL, "CLKSQ Audio"}, + {"AIFTX_Supply", NULL, "AUD_CK"}, + {"AIFTX_Supply", NULL, "AUDIF_CK"}, + {"AIFTX_Supply", NULL, "AUDIO_TOP_AFE_CTL"}, + {"AIFTX_Supply", NULL, "AUDIO_TOP_PWR_CLK"}, + {"AIFTX_Supply", NULL, "AUDIO_TOP_PDN_RESERVED"}, + {"AIFTX_Supply", NULL, "AUDIO_TOP_I2S_DL"}, + /* + * *_ADC_CTL should enable only if UL_SRC in use, + * but dm ck may be needed even UL_SRC_x not in use + */ + {"AIFTX_Supply", NULL, "AUDIO_TOP_ADC_CTL"}, + {"AIFTX_Supply", NULL, "AUDIO_TOP_ADDA6_ADC_CTL"}, + {"AIFTX_Supply", NULL, "AFE_ON"}, + + /* ul ch 12 */ + {"AIF1TX", NULL, "AIF Out Mux"}, + {"AIF1TX", NULL, "AIFTX_Supply"}, + {"AIF1TX", NULL, "MTKAIF_TX"}, + + {"AIF2TX", NULL, "AIF2 Out Mux"}, + {"AIF2TX", NULL, "AIFTX_Supply"}, + {"AIF2TX", NULL, "MTKAIF_TX"}, + + {"AIF Out Mux", "Normal Path", "MISO0_MUX"}, + {"AIF Out Mux", "Normal Path", "MISO1_MUX"}, + {"AIF2 Out Mux", "Normal Path", "MISO2_MUX"}, + + {"MISO0_MUX", "UL1_CH1", "UL_SRC_MUX"}, + {"MISO0_MUX", "UL1_CH2", "UL_SRC_MUX"}, + {"MISO0_MUX", "UL2_CH1", "UL2_SRC_MUX"}, + {"MISO0_MUX", "UL2_CH2", "UL2_SRC_MUX"}, + + {"MISO1_MUX", "UL1_CH1", "UL_SRC_MUX"}, + {"MISO1_MUX", "UL1_CH2", "UL_SRC_MUX"}, + {"MISO1_MUX", "UL2_CH1", "UL2_SRC_MUX"}, + {"MISO1_MUX", "UL2_CH2", "UL2_SRC_MUX"}, + + {"MISO2_MUX", "UL1_CH1", "UL_SRC_MUX"}, + {"MISO2_MUX", "UL1_CH2", "UL_SRC_MUX"}, + {"MISO2_MUX", "UL2_CH1", "UL2_SRC_MUX"}, + {"MISO2_MUX", "UL2_CH2", "UL2_SRC_MUX"}, + + {"UL_SRC_MUX", "AMIC", "ADC_L"}, + {"UL_SRC_MUX", "AMIC", "ADC_R"}, + {"UL_SRC_MUX", "DMIC", "DMIC0_MUX"}, + {"UL_SRC_MUX", "DMIC", "DMIC1_MUX"}, + {"UL_SRC_MUX", NULL, "UL_SRC"}, + + {"UL2_SRC_MUX", "AMIC", "ADC_3"}, + {"UL2_SRC_MUX", "DMIC", "DMIC2_MUX"}, + {"UL2_SRC_MUX", NULL, "UL_SRC_34"}, + + {"DMIC0_MUX", "DMIC_DATA0", "AIN0_DMIC"}, + {"DMIC0_MUX", "DMIC_DATA1_L", "AIN2_DMIC"}, + {"DMIC0_MUX", "DMIC_DATA1_L_1", "AIN2_DMIC"}, + {"DMIC0_MUX", "DMIC_DATA1_R", "AIN3_DMIC"}, + {"DMIC1_MUX", "DMIC_DATA0", "AIN0_DMIC"}, + {"DMIC1_MUX", "DMIC_DATA1_L", "AIN2_DMIC"}, + {"DMIC1_MUX", "DMIC_DATA1_L_1", "AIN2_DMIC"}, + {"DMIC1_MUX", "DMIC_DATA1_R", "AIN3_DMIC"}, + {"DMIC2_MUX", "DMIC_DATA0", "AIN0_DMIC"}, + {"DMIC2_MUX", "DMIC_DATA1_L", "AIN2_DMIC"}, + {"DMIC2_MUX", "DMIC_DATA1_L_1", "AIN2_DMIC"}, + {"DMIC2_MUX", "DMIC_DATA1_R", "AIN3_DMIC"}, + + {"DMIC0_MUX", NULL, "UL_SRC_DMIC"}, + {"DMIC1_MUX", NULL, "UL_SRC_DMIC"}, + {"DMIC2_MUX", NULL, "UL_SRC_34_DMIC"}, + + {"AIN0_DMIC", NULL, "DMIC_0"}, + {"AIN2_DMIC", NULL, "DMIC_1"}, + {"AIN3_DMIC", NULL, "DMIC_1"}, + {"AIN0_DMIC", NULL, "MIC_BIAS_0"}, + {"AIN2_DMIC", NULL, "MIC_BIAS_2"}, + {"AIN3_DMIC", NULL, "MIC_BIAS_2"}, + + /* adc */ + {"ADC_L", NULL, "ADC_L_Mux"}, + {"ADC_L", NULL, "ADC_CLKGEN"}, + {"ADC_L", NULL, "ADC_L_EN"}, + {"ADC_R", NULL, "ADC_R_Mux"}, + {"ADC_R", NULL, "ADC_CLKGEN"}, + {"ADC_R", NULL, "ADC_R_EN"}, + /* + * amic fifo ch1/2 clk from ADC_L, + * enable ADC_L even use ADC_R only + */ + {"ADC_R", NULL, "ADC_L_EN"}, + {"ADC_3", NULL, "ADC_3_Mux"}, + {"ADC_3", NULL, "ADC_CLKGEN"}, + {"ADC_3", NULL, "ADC_3_EN"}, + + {"ADC_L_Mux", "Left Preamplifier", "PGA_L"}, + {"ADC_R_Mux", "Right Preamplifier", "PGA_R"}, + {"ADC_3_Mux", "Preamplifier", "PGA_3"}, + + {"PGA_L", NULL, "PGA_L_Mux"}, + {"PGA_L", NULL, "PGA_L_EN"}, + {"PGA_R", NULL, "PGA_R_Mux"}, + {"PGA_R", NULL, "PGA_R_EN"}, + {"PGA_3", NULL, "PGA_3_Mux"}, + {"PGA_3", NULL, "PGA_3_EN"}, + + {"PGA_L", NULL, "DCC_CLK", mt_dcc_clk_connect}, + {"PGA_R", NULL, "DCC_CLK", mt_dcc_clk_connect}, + {"PGA_3", NULL, "DCC_CLK", mt_dcc_clk_connect}, + + {"PGA_L_Mux", "AIN0", "AIN0"}, + {"PGA_L_Mux", "AIN1", "AIN1"}, + + {"PGA_R_Mux", "AIN0", "AIN0"}, + {"PGA_R_Mux", "AIN2", "AIN2"}, + {"PGA_R_Mux", "AIN3", "AIN3"}, + + {"PGA_3_Mux", "AIN2", "AIN2"}, + {"PGA_3_Mux", "AIN3", "AIN3"}, + + {"AIN0", NULL, "MIC_BIAS_0"}, + {"AIN1", NULL, "MIC_BIAS_1"}, + {"AIN2", NULL, "MIC_BIAS_0"}, + {"AIN2", NULL, "MIC_BIAS_2"}, + {"AIN3", NULL, "MIC_BIAS_2"}, + + /* DL Supply */ + {"DL Power Supply", NULL, "CLK_BUF"}, + {"DL Power Supply", NULL, "LDO_VAUD18"}, + {"DL Power Supply", NULL, "AUDGLB"}, + {"DL Power Supply", NULL, "CLKSQ Audio"}, + {"DL Power Supply", NULL, "AUDNCP_CK"}, + {"DL Power Supply", NULL, "ZCD13M_CK"}, + {"DL Power Supply", NULL, "AUD_CK"}, + {"DL Power Supply", NULL, "AUDIF_CK"}, + {"DL Power Supply", NULL, "ESD_RESIST"}, + {"DL Power Supply", NULL, "LDO"}, + {"DL Power Supply", NULL, "LDO_REMOTE"}, + {"DL Power Supply", NULL, "NV_REGULATOR"}, + {"DL Power Supply", NULL, "IBIST"}, + + /* DL Digital Supply */ + {"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_PDN_RESERVED"}, + {"DL Digital Clock", NULL, "SDM_FIFO_CLK"}, + {"DL Digital Clock", NULL, "NCP"}, + {"DL Digital Clock", NULL, "AFE_ON"}, + {"DL Digital Clock", NULL, "AFE_DL_SRC"}, + + {"DL Digital Clock CH_1_2", NULL, "DL Digital Clock"}, + {"DL Digital Clock CH_1_2", NULL, "SDM"}, + + {"DL Digital Clock CH_3", NULL, "DL Digital Clock"}, + {"DL Digital Clock CH_3", NULL, "SDM_3RD"}, + + {"AIF_RX", NULL, "DL Digital Clock CH_1_2"}, + + {"AIF2_RX", NULL, "DL Digital Clock CH_3"}, + + /* DL Path */ + {"DAC In Mux", "Normal Path", "AIF_RX"}, + {"DAC In Mux", "Sgen", "SGEN DL"}, + {"SGEN DL", NULL, "SGEN DL SRC"}, + {"SGEN DL", NULL, "SGEN MUTE"}, + {"SGEN DL", NULL, "SGEN DL Enable"}, + {"SGEN DL", NULL, "DL Digital Clock CH_1_2"}, + {"SGEN DL", NULL, "DL Digital Clock CH_3"}, + {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, + + {"DACL", NULL, "DAC In Mux"}, + {"DACL", NULL, "DL Power Supply"}, + + {"DACR", NULL, "DAC In Mux"}, + {"DACR", NULL, "DL Power Supply"}, + + /* DAC 3RD */ + {"DAC In Mux", "Normal Path", "AIF2_RX"}, + {"DAC_3RD", NULL, "DAC In Mux"}, + {"DAC_3RD", NULL, "DL Power Supply"}, + + /* Lineout Path */ + {"LOL Mux", "Playback", "DAC_3RD"}, + {"LINEOUT L", NULL, "LOL Mux"}, + + /* Headphone Path */ + {"HP_Supply", NULL, "HP_PULL_DOWN"}, + {"HP_Supply", NULL, "HP_MUTE"}, + {"HP_Supply", NULL, "HP_DAMP"}, + {"HP Mux", NULL, "HP_Supply"}, + + {"HP Mux", "Audio Playback", "DACL"}, + {"HP Mux", "Audio Playback", "DACR"}, + {"HP Mux", "HP Impedance", "DACL"}, + {"HP Mux", "HP Impedance", "DACR"}, + {"HP Mux", "LoudSPK Playback", "DACL"}, + {"HP Mux", "LoudSPK Playback", "DACR"}, + + {"Headphone L", NULL, "HP Mux"}, + {"Headphone R", NULL, "HP Mux"}, + {"Headphone L Ext Spk Amp", NULL, "HP Mux"}, + {"Headphone R Ext Spk Amp", NULL, "HP Mux"}, + + /* Receiver Path */ + {"RCV Mux", "Voice Playback", "DACL"}, + {"Receiver", NULL, "RCV Mux"}, +}; + +static int mt6359_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *cmpnt = dai->component; + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int rate = params_rate(params); + int id = dai->id; + + dev_dbg(priv->dev, "%s(), id %d, substream->stream %d, rate %d, number %d\n", + __func__, id, substream->stream, rate, substream->number); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + priv->dl_rate[id] = rate; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + priv->ul_rate[id] = rate; + + return 0; +} + +static int mt6359_codec_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *cmpnt = dai->component; + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s stream %d\n", __func__, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mt6359_set_playback_gpio(priv); + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + mt6359_set_capture_gpio(priv); + + return 0; +} + +static void mt6359_codec_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *cmpnt = dai->component; + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s stream %d\n", __func__, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mt6359_reset_playback_gpio(priv); + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + mt6359_reset_capture_gpio(priv); +} + +static const struct snd_soc_dai_ops mt6359_codec_dai_ops = { + .hw_params = mt6359_codec_dai_hw_params, + .startup = mt6359_codec_dai_startup, + .shutdown = mt6359_codec_dai_shutdown, +}; + +#define MT6359_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ + SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) + +static struct snd_soc_dai_driver mt6359_dai_driver[] = { + { + .id = MT6359_AIF_1, + .name = "mt6359-snd-codec-aif1", + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = MT6359_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = MT6359_FORMATS, + }, + .ops = &mt6359_codec_dai_ops, + }, + { + .id = MT6359_AIF_2, + .name = "mt6359-snd-codec-aif2", + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = MT6359_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = MT6359_FORMATS, + }, + .ops = &mt6359_codec_dai_ops, + }, +}; + +static int mt6359_codec_init_reg(struct snd_soc_component *cmpnt) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + /* enable clk buf */ + regmap_update_bits(priv->regmap, MT6359_DCXO_CW12, + 0x1 << RG_XO_AUDIO_EN_M_SFT, + 0x1 << RG_XO_AUDIO_EN_M_SFT); + + /* set those not controlled by dapm widget */ + + /* audio clk source from internal dcxo */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23, + RG_CLKSQ_IN_SEL_TEST_MASK_SFT, + 0x0); + + /* Disable HeadphoneL/HeadphoneR short circuit protection */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + RG_AUDHPLSCDISABLE_VAUDP32_MASK_SFT, + 0x1 << RG_AUDHPLSCDISABLE_VAUDP32_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, + RG_AUDHPRSCDISABLE_VAUDP32_MASK_SFT, + 0x1 << RG_AUDHPRSCDISABLE_VAUDP32_SFT); + /* Disable voice short circuit protection */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON6, + RG_AUDHSSCDISABLE_VAUDP32_MASK_SFT, + 0x1 << RG_AUDHSSCDISABLE_VAUDP32_SFT); + /* disable LO buffer left short circuit protection */ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON7, + RG_AUDLOLSCDISABLE_VAUDP32_MASK_SFT, + 0x1 << RG_AUDLOLSCDISABLE_VAUDP32_SFT); + + /* set gpio */ + mt6359_reset_playback_gpio(priv); + mt6359_reset_capture_gpio(priv); + + /* hp hifi mode, default normal mode */ + priv->hp_hifi_mode = 0; + + /* Disable AUD_ZCD */ + zcd_disable(priv); + + /* disable clk buf */ + regmap_update_bits(priv->regmap, MT6359_DCXO_CW12, + 0x1 << RG_XO_AUDIO_EN_M_SFT, + 0x0 << RG_XO_AUDIO_EN_M_SFT); + + return 0; +} + +static int mt6359_codec_probe(struct snd_soc_component *cmpnt) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + snd_soc_component_init_regmap(cmpnt, priv->regmap); + + return mt6359_codec_init_reg(cmpnt); +} + +static void mt6359_codec_remove(struct snd_soc_component *cmpnt) +{ + snd_soc_component_exit_regmap(cmpnt); +} + +static const DECLARE_TLV_DB_SCALE(hp_playback_tlv, -2200, 100, 0); +static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); +static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0); + +static const struct snd_kcontrol_new mt6359_snd_controls[] = { + /* dl pga gain */ + SOC_DOUBLE_EXT_TLV("Headset Volume", + MT6359_ZCD_CON2, 0, 7, 0x1E, 0, + snd_soc_get_volsw, mt6359_put_volsw, + hp_playback_tlv), + SOC_DOUBLE_EXT_TLV("Lineout Volume", + MT6359_ZCD_CON1, 0, 7, 0x12, 0, + snd_soc_get_volsw, mt6359_put_volsw, playback_tlv), + SOC_SINGLE_EXT_TLV("Handset Volume", + MT6359_ZCD_CON3, 0, 0x12, 0, + snd_soc_get_volsw, mt6359_put_volsw, playback_tlv), + + /* ul pga gain */ + SOC_SINGLE_EXT_TLV("PGA1 Volume", + MT6359_AUDENC_ANA_CON0, RG_AUDPREAMPLGAIN_SFT, 4, 0, + snd_soc_get_volsw, mt6359_put_volsw, capture_tlv), + SOC_SINGLE_EXT_TLV("PGA2 Volume", + MT6359_AUDENC_ANA_CON1, RG_AUDPREAMPRGAIN_SFT, 4, 0, + snd_soc_get_volsw, mt6359_put_volsw, capture_tlv), + SOC_SINGLE_EXT_TLV("PGA3 Volume", + MT6359_AUDENC_ANA_CON2, RG_AUDPREAMP3GAIN_SFT, 4, 0, + snd_soc_get_volsw, mt6359_put_volsw, capture_tlv), +}; + +static const struct snd_soc_component_driver mt6359_soc_component_driver = { + .name = CODEC_MT6359_NAME, + .probe = mt6359_codec_probe, + .remove = mt6359_codec_remove, + .controls = mt6359_snd_controls, + .num_controls = ARRAY_SIZE(mt6359_snd_controls), + .dapm_widgets = mt6359_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt6359_dapm_widgets), + .dapm_routes = mt6359_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(mt6359_dapm_routes), +}; + +static int mt6359_parse_dt(struct mt6359_priv *priv) +{ + int ret; + struct device *dev = priv->dev; + struct device_node *np; + + np = of_get_child_by_name(dev->parent->of_node, "mt6359codec"); + if (!np) + return -EINVAL; + + ret = of_property_read_u32(np, "mediatek,dmic-mode", + &priv->dmic_one_wire_mode); + if (ret) { + dev_warn(priv->dev, "%s() failed to read dmic-mode\n", + __func__); + priv->dmic_one_wire_mode = 0; + } + + ret = of_property_read_u32(np, "mediatek,mic-type-0", + &priv->mux_select[MUX_MIC_TYPE_0]); + if (ret) { + dev_warn(priv->dev, "%s() failed to read mic-type-0\n", + __func__); + priv->mux_select[MUX_MIC_TYPE_0] = MIC_TYPE_MUX_IDLE; + } + + ret = of_property_read_u32(np, "mediatek,mic-type-1", + &priv->mux_select[MUX_MIC_TYPE_1]); + if (ret) { + dev_warn(priv->dev, "%s() failed to read mic-type-1\n", + __func__); + priv->mux_select[MUX_MIC_TYPE_1] = MIC_TYPE_MUX_IDLE; + } + + ret = of_property_read_u32(np, "mediatek,mic-type-2", + &priv->mux_select[MUX_MIC_TYPE_2]); + if (ret) { + dev_warn(priv->dev, "%s() failed to read mic-type-2\n", + __func__); + priv->mux_select[MUX_MIC_TYPE_2] = MIC_TYPE_MUX_IDLE; + } + + return 0; +} + +static int mt6359_platform_driver_probe(struct platform_device *pdev) +{ + struct mt6359_priv *priv; + int ret; + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + + dev_dbg(&pdev->dev, "%s(), dev name %s\n", + __func__, dev_name(&pdev->dev)); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = mt6397->regmap; + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + dev_set_drvdata(&pdev->dev, priv); + priv->dev = &pdev->dev; + + priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18"); + if (IS_ERR(priv->avdd_reg)) { + dev_err(&pdev->dev, "%s(), have no vaud18 supply: %ld", + __func__, PTR_ERR(priv->avdd_reg)); + return PTR_ERR(priv->avdd_reg); + } + + ret = regulator_enable(priv->avdd_reg); + if (ret) { + dev_err(&pdev->dev, "%s(), failed to enable regulator!\n", + __func__); + return ret; + } + + ret = mt6359_parse_dt(priv); + if (ret) { + dev_warn(&pdev->dev, "%s() failed to parse dts\n", __func__); + return ret; + } + + return devm_snd_soc_register_component(&pdev->dev, + &mt6359_soc_component_driver, + mt6359_dai_driver, + ARRAY_SIZE(mt6359_dai_driver)); +} + +static int mt6359_platform_driver_remove(struct platform_device *pdev) +{ + struct mt6359_priv *priv = dev_get_drvdata(&pdev->dev); + int ret; + + dev_dbg(&pdev->dev, "%s(), dev name %s\n", + __func__, dev_name(&pdev->dev)); + + ret = regulator_disable(priv->avdd_reg); + if (ret) { + dev_err(&pdev->dev, "%s(), failed to disable regulator!\n", + __func__); + return ret; + } + + return 0; +} + +static struct platform_driver mt6359_platform_driver = { + .driver = { + .name = "mt6359-sound", + }, + .probe = mt6359_platform_driver_probe, + .remove = mt6359_platform_driver_remove, +}; + +module_platform_driver(mt6359_platform_driver) + +/* Module information */ +MODULE_DESCRIPTION("MT6359 ALSA SoC codec driver"); +MODULE_AUTHOR("KaiChieh Chuang <[email protected]>"); +MODULE_AUTHOR("Eason Yen <[email protected]>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h new file mode 100644 index 000000000000..3792e534a91b --- /dev/null +++ b/sound/soc/codecs/mt6359.h @@ -0,0 +1,2640 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 MediaTek Inc. + * Author: Argus Lin <[email protected]> + */ + +#ifndef _MT6359_H_ +#define _MT6359_H_ + +/*************Register Bit Define*************/ +#define PMIC_ACCDET_IRQ_SHIFT 0 +#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2 +#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3 +#define PMIC_ACCDET_IRQ_CLR_SHIFT 8 +#define PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT 10 +#define PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT 11 +#define PMIC_RG_INT_STATUS_ACCDET_SHIFT 5 +#define PMIC_RG_INT_STATUS_ACCDET_EINT0_SHIFT 6 +#define PMIC_RG_INT_STATUS_ACCDET_EINT1_SHIFT 7 +#define PMIC_RG_EINT0CONFIGACCDET_SHIFT 11 +#define PMIC_RG_EINT1CONFIGACCDET_SHIFT 0 +#define PMIC_ACCDET_EINT0_INVERTER_SW_EN_SHIFT 6 +#define PMIC_ACCDET_EINT1_INVERTER_SW_EN_SHIFT 8 +#define PMIC_RG_MTEST_EN_SHIFT 8 +#define PMIC_RG_MTEST_SEL_SHIFT 9 +#define PMIC_ACCDET_EINT0_M_SW_EN_SHIFT 10 +#define PMIC_ACCDET_EINT1_M_SW_EN_SHIFT 11 +#define PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT 5 +#define PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT 10 +#define PMIC_ACCDET_DA_STABLE_SHIFT 0 +#define PMIC_ACCDET_EINT0_EN_STABLE_SHIFT 1 +#define PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT 2 +#define PMIC_ACCDET_EINT1_EN_STABLE_SHIFT 6 +#define PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT 7 +#define PMIC_ACCDET_EINT_CTURBO_SEL_SHIFT 7 +#define PMIC_ACCDET_EINT0_CTURBO_SW_SHIFT 7 +#define PMIC_RG_EINTCOMPVTH_SHIFT 4 +#define PMIC_RG_EINT0HIRENB_SHIFT 12 +#define PMIC_RG_EINT0NOHYS_SHIFT 10 +#define PMIC_ACCDET_SW_EN_SHIFT 0 +#define PMIC_ACCDET_EINT0_MEM_IN_SHIFT 6 +#define PMIC_ACCDET_MEM_IN_SHIFT 6 +#define PMIC_ACCDET_EINT_DEBOUNCE0_SHIFT 0 +#define PMIC_ACCDET_EINT_DEBOUNCE1_SHIFT 4 +#define PMIC_ACCDET_EINT_DEBOUNCE2_SHIFT 8 +#define PMIC_ACCDET_EINT_DEBOUNCE3_SHIFT 12 +#define PMIC_RG_ACCDET2AUXSWEN_SHIFT 14 +#define PMIC_AUDACCDETAUXADCSWCTRL_SEL_SHIFT 9 +#define PMIC_AUDACCDETAUXADCSWCTRL_SW_SHIFT 10 +#define PMIC_RG_EINT0CTURBO_SHIFT 5 +#define PMIC_RG_EINT1CTURBO_SHIFT 13 +#define PMIC_ACCDET_EINT_M_PLUG_IN_NUM_SHIFT 12 +#define PMIC_ACCDET_EINT_M_DETECT_EN_SHIFT 12 +#define PMIC_ACCDET_EINT0_SW_EN_SHIFT 2 +#define PMIC_ACCDET_EINT1_SW_EN_SHIFT 4 +#define PMIC_ACCDET_EINT_CMPMOUT_SEL_SHIFT 12 +#define PMIC_ACCDET_EINT_CMPMEN_SEL_SHIFT 6 +#define PMIC_RG_HPLOUTPUTSTBENH_VAUDP32_SHIFT 0 +#define PMIC_RG_HPROUTPUTSTBENH_VAUDP32_SHIFT 4 +#define PMIC_RG_EINT0EN_SHIFT 2 +#define PMIC_RG_EINT1EN_SHIFT 10 +#define PMIC_RG_NCP_PDDIS_EN_SHIFT 0 +#define PMIC_RG_ACCDETSPARE_SHIFT 0 +#define PMIC_RG_ACCDET_RST_SHIFT 1 +#define PMIC_RG_AUDMICBIAS1HVEN_SHIFT 12 +#define PMIC_RG_AUDMICBIAS1VREF_SHIFT 4 +#define PMIC_RG_ANALOGFDEN_SHIFT 12 +#define PMIC_RG_AUDMICBIAS1DCSW1PEN_SHIFT 8 +#define PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT 2 +#define PMIC_ACCDET_SEQ_INIT_SHIFT 1 +#define PMIC_RG_EINTCOMPVTH_MASK 0xf +#define PMIC_ACCDET_EINT0_MEM_IN_MASK 0x3 +#define PMIC_ACCDET_EINT_DEBOUNCE0_MASK 0xf +#define PMIC_ACCDET_EINT_DEBOUNCE1_MASK 0xf +#define PMIC_ACCDET_EINT_DEBOUNCE2_MASK 0xf +#define PMIC_ACCDET_EINT_DEBOUNCE3_MASK 0xf +#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2 +#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3 + +/* AUDENC_ANA_CON16: */ +#define RG_AUD_MICBIAS1_LOWP_EN BIT(PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT) + +/* AUDENC_ANA_CON18: */ +#define RG_ACCDET_MODE_ANA11_MODE1 (0x000f) +#define RG_ACCDET_MODE_ANA11_MODE2 (0x008f) +#define RG_ACCDET_MODE_ANA11_MODE6 (0x008f) + +/* AUXADC_ADC5: Auxadc CH5 read data */ +#define AUXADC_DATA_RDY_CH5 BIT(15) +#define AUXADC_DATA_PROCEED_CH5 BIT(15) +#define AUXADC_DATA_MASK (0x0fff) + +/* AUXADC_RQST0_SET: Auxadc CH5 request, relevant 0x07EC */ +#define AUXADC_RQST_CH5_SET BIT(5) +/* AUXADC_RQST0_CLR: Auxadc CH5 request, relevant 0x07EC */ +#define AUXADC_RQST_CH5_CLR BIT(5) + +#define ACCDET_CALI_MASK0 (0xff) +#define ACCDET_CALI_MASK1 (0xff << 8) +#define ACCDET_CALI_MASK2 (0xff) +#define ACCDET_CALI_MASK3 (0xff << 8) +#define ACCDET_CALI_MASK4 (0xff) + +#define ACCDET_EINT1_IRQ_CLR_B11 BIT(PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT) +#define ACCDET_EINT0_IRQ_CLR_B10 BIT(PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT) +#define ACCDET_EINT_IRQ_CLR_B10_11 (0x03 << \ + PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT) +#define ACCDET_IRQ_CLR_B8 BIT(PMIC_ACCDET_IRQ_CLR_SHIFT) + +#define ACCDET_EINT1_IRQ_B3 BIT(PMIC_ACCDET_EINT1_IRQ_SHIFT) +#define ACCDET_EINT0_IRQ_B2 BIT(PMIC_ACCDET_EINT0_IRQ_SHIFT) +#define ACCDET_EINT_IRQ_B2_B3 (0x03 << PMIC_ACCDET_EINT0_IRQ_SHIFT) +#define ACCDET_IRQ_B0 BIT(PMIC_ACCDET_IRQ_SHIFT) + +/* ACCDET_CON25: RO, accdet FSM state,etc.*/ +#define ACCDET_STATE_MEM_IN_OFFSET (PMIC_ACCDET_MEM_IN_SHIFT) +#define ACCDET_STATE_AB_MASK (0x03) +#define ACCDET_STATE_AB_00 (0x00) +#define ACCDET_STATE_AB_01 (0x01) +#define ACCDET_STATE_AB_10 (0x02) +#define ACCDET_STATE_AB_11 (0x03) + +/* ACCDET_CON19 */ +#define ACCDET_EINT0_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT0_EN_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT)) + +#define ACCDET_EINT1_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT1_EN_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT) | \ + (1 << PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT)) + +/* The following are used for mt6359.c */ +/* MT6359_DCXO_CW12 */ +#define RG_XO_AUDIO_EN_M_SFT 13 + +/* LDO_VAUD18_CON0 */ +#define RG_LDO_VAUD18_EN_SFT 0 +#define RG_LDO_VAUD18_EN_MASK 0x1 +#define RG_LDO_VAUD18_EN_MASK_SFT (0x1 << 0) + +/* AUD_TOP_CKPDN_CON0 */ +#define RG_VOW13M_CK_PDN_SFT 13 +#define RG_VOW13M_CK_PDN_MASK 0x1 +#define RG_VOW13M_CK_PDN_MASK_SFT (0x1 << 13) +#define RG_VOW32K_CK_PDN_SFT 12 +#define RG_VOW32K_CK_PDN_MASK 0x1 +#define RG_VOW32K_CK_PDN_MASK_SFT (0x1 << 12) +#define RG_AUD_INTRP_CK_PDN_SFT 8 +#define RG_AUD_INTRP_CK_PDN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_MASK_SFT (0x1 << 8) +#define RG_PAD_AUD_CLK_MISO_CK_PDN_SFT 7 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK 0x1 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK_SFT (0x1 << 7) +#define RG_AUDNCP_CK_PDN_SFT 6 +#define RG_AUDNCP_CK_PDN_MASK 0x1 +#define RG_AUDNCP_CK_PDN_MASK_SFT (0x1 << 6) +#define RG_ZCD13M_CK_PDN_SFT 5 +#define RG_ZCD13M_CK_PDN_MASK 0x1 +#define RG_ZCD13M_CK_PDN_MASK_SFT (0x1 << 5) +#define RG_AUDIF_CK_PDN_SFT 2 +#define RG_AUDIF_CK_PDN_MASK 0x1 +#define RG_AUDIF_CK_PDN_MASK_SFT (0x1 << 2) +#define RG_AUD_CK_PDN_SFT 1 +#define RG_AUD_CK_PDN_MASK 0x1 +#define RG_AUD_CK_PDN_MASK_SFT (0x1 << 1) +#define RG_ACCDET_CK_PDN_SFT 0 +#define RG_ACCDET_CK_PDN_MASK 0x1 +#define RG_ACCDET_CK_PDN_MASK_SFT (0x1 << 0) + +/* AUD_TOP_CKPDN_CON0_SET */ +#define RG_AUD_TOP_CKPDN_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK_SFT (0x3fff << 0) + +/* AUD_TOP_CKPDN_CON0_CLR */ +#define RG_AUD_TOP_CKPDN_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK_SFT (0x3fff << 0) + +/* AUD_TOP_CKSEL_CON0 */ +#define RG_AUDIF_CK_CKSEL_SFT 3 +#define RG_AUDIF_CK_CKSEL_MASK 0x1 +#define RG_AUDIF_CK_CKSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_CKSEL_SFT 2 +#define RG_AUD_CK_CKSEL_MASK 0x1 +#define RG_AUD_CK_CKSEL_MASK_SFT (0x1 << 2) + +/* AUD_TOP_CKSEL_CON0_SET */ +#define RG_AUD_TOP_CKSEL_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK_SFT (0xf << 0) + +/* AUD_TOP_CKSEL_CON0_CLR */ +#define RG_AUD_TOP_CKSEL_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK_SFT (0xf << 0) + +/* AUD_TOP_CKTST_CON0 */ +#define RG_VOW13M_CK_TSTSEL_SFT 9 +#define RG_VOW13M_CK_TSTSEL_MASK 0x1 +#define RG_VOW13M_CK_TSTSEL_MASK_SFT (0x1 << 9) +#define RG_VOW13M_CK_TST_DIS_SFT 8 +#define RG_VOW13M_CK_TST_DIS_MASK 0x1 +#define RG_VOW13M_CK_TST_DIS_MASK_SFT (0x1 << 8) +#define RG_AUD26M_CK_TSTSEL_SFT 4 +#define RG_AUD26M_CK_TSTSEL_MASK 0x1 +#define RG_AUD26M_CK_TSTSEL_MASK_SFT (0x1 << 4) +#define RG_AUDIF_CK_TSTSEL_SFT 3 +#define RG_AUDIF_CK_TSTSEL_MASK 0x1 +#define RG_AUDIF_CK_TSTSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_TSTSEL_SFT 2 +#define RG_AUD_CK_TSTSEL_MASK 0x1 +#define RG_AUD_CK_TSTSEL_MASK_SFT (0x1 << 2) +#define RG_AUD26M_CK_TST_DIS_SFT 0 +#define RG_AUD26M_CK_TST_DIS_MASK 0x1 +#define RG_AUD26M_CK_TST_DIS_MASK_SFT (0x1 << 0) + +/* AUD_TOP_CLK_HWEN_CON0 */ +#define RG_AUD_INTRP_CK_PDN_HWEN_SFT 0 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK_SFT (0x1 << 0) + +/* AUD_TOP_CLK_HWEN_CON0_SET */ +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_SFT 0 +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK 0xffff +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK_SFT (0xffff << 0) + +/* AUD_TOP_CLK_HWEN_CON0_CLR */ +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_SFT 0 +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK 0xffff +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK_SFT (0xffff << 0) + +/* AUD_TOP_RST_CON0 */ +#define RG_AUDNCP_RST_SFT 3 +#define RG_AUDNCP_RST_MASK 0x1 +#define RG_AUDNCP_RST_MASK_SFT (0x1 << 3) +#define RG_ZCD_RST_SFT 2 +#define RG_ZCD_RST_MASK 0x1 +#define RG_ZCD_RST_MASK_SFT (0x1 << 2) +#define RG_ACCDET_RST_SFT 1 +#define RG_ACCDET_RST_MASK 0x1 +#define RG_ACCDET_RST_MASK_SFT (0x1 << 1) +#define RG_AUDIO_RST_SFT 0 +#define RG_AUDIO_RST_MASK 0x1 +#define RG_AUDIO_RST_MASK_SFT (0x1 << 0) + +/* AUD_TOP_RST_CON0_SET */ +#define RG_AUD_TOP_RST_CON0_SET_SFT 0 +#define RG_AUD_TOP_RST_CON0_SET_MASK 0xf +#define RG_AUD_TOP_RST_CON0_SET_MASK_SFT (0xf << 0) + +/* AUD_TOP_RST_CON0_CLR */ +#define RG_AUD_TOP_RST_CON0_CLR_SFT 0 +#define RG_AUD_TOP_RST_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_RST_CON0_CLR_MASK_SFT (0xf << 0) + +/* AUD_TOP_RST_BANK_CON0 */ +#define BANK_AUDZCD_SWRST_SFT 2 +#define BANK_AUDZCD_SWRST_MASK 0x1 +#define BANK_AUDZCD_SWRST_MASK_SFT (0x1 << 2) +#define BANK_AUDIO_SWRST_SFT 1 +#define BANK_AUDIO_SWRST_MASK 0x1 +#define BANK_AUDIO_SWRST_MASK_SFT (0x1 << 1) +#define BANK_ACCDET_SWRST_SFT 0 +#define BANK_ACCDET_SWRST_MASK 0x1 +#define BANK_ACCDET_SWRST_MASK_SFT (0x1 << 0) + +/* AFE_UL_DL_CON0 */ +#define AFE_UL_LR_SWAP_SFT 15 +#define AFE_UL_LR_SWAP_MASK 0x1 +#define AFE_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_DL_LR_SWAP_SFT 14 +#define AFE_DL_LR_SWAP_MASK 0x1 +#define AFE_DL_LR_SWAP_MASK_SFT (0x1 << 14) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_DL_SRC2_CON0_L */ +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* AFE_UL_SRC_CON0_H */ +#define C_DIGMIC_PHASE_SEL_CH1_CTL_SFT 11 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT (0x7 << 11) +#define C_DIGMIC_PHASE_SEL_CH2_CTL_SFT 8 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT (0x7 << 8) +#define C_TWO_DIGITAL_MIC_CTL_SFT 7 +#define C_TWO_DIGITAL_MIC_CTL_MASK 0x1 +#define C_TWO_DIGITAL_MIC_CTL_MASK_SFT (0x1 << 7) + +/* AFE_UL_SRC_CON0_L */ +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define DIGMIC_4P33M_SEL_CTL_SFT 6 +#define DIGMIC_4P33M_SEL_CTL_MASK 0x1 +#define DIGMIC_4P33M_SEL_CTL_MASK_SFT (0x1 << 6) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA6_L_SRC_CON0_H */ +#define ADDA6_C_DIGMIC_PHASE_SEL_CH1_CTL_SFT 11 +#define ADDA6_C_DIGMIC_PHASE_SEL_CH1_CTL_MASK 0x7 +#define ADDA6_C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT (0x7 << 11) +#define ADDA6_C_DIGMIC_PHASE_SEL_CH2_CTL_SFT 8 +#define ADDA6_C_DIGMIC_PHASE_SEL_CH2_CTL_MASK 0x7 +#define ADDA6_C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT (0x7 << 8) +#define ADDA6_C_TWO_DIGITAL_MIC_CTL_SFT 7 +#define ADDA6_C_TWO_DIGITAL_MIC_CTL_MASK 0x1 +#define ADDA6_C_TWO_DIGITAL_MIC_CTL_MASK_SFT (0x1 << 7) + +/* AFE_ADDA6_UL_SRC_CON0_L */ +#define ADDA6_DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define ADDA6_DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define ADDA6_DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define ADDA6_DIGMIC_4P33M_SEL_CTL_SFT 6 +#define ADDA6_DIGMIC_4P33M_SEL_CTL_MASK 0x1 +#define ADDA6_DIGMIC_4P33M_SEL_CTL_MASK_SFT (0x1 << 6) +#define ADDA6_DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define ADDA6_DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define ADDA6_DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define ADDA6_UL_LOOP_BACK_MODE_CTL_SFT 2 +#define ADDA6_UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define ADDA6_UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define ADDA6_UL_SDM_3_LEVEL_CTL_SFT 1 +#define ADDA6_UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define ADDA6_UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define ADDA6_UL_SRC_ON_TMP_CTL_SFT 0 +#define ADDA6_UL_SRC_ON_TMP_CTL_MASK 0x1 +#define ADDA6_UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* AFE_TOP_CON0 */ +#define ADDA6_MTKAIF_SINE_ON_SFT 4 +#define ADDA6_MTKAIF_SINE_ON_MASK 0x1 +#define ADDA6_MTKAIF_SINE_ON_MASK_SFT (0x1 << 4) +#define ADDA6_UL_SINE_ON_SFT 3 +#define ADDA6_UL_SINE_ON_MASK 0x1 +#define ADDA6_UL_SINE_ON_MASK_SFT (0x1 << 3) +#define MTKAIF_SINE_ON_SFT 2 +#define MTKAIF_SINE_ON_MASK 0x1 +#define MTKAIF_SINE_ON_MASK_SFT (0x1 << 2) +#define UL_SINE_ON_SFT 1 +#define UL_SINE_ON_MASK 0x1 +#define UL_SINE_ON_MASK_SFT (0x1 << 1) +#define DL_SINE_ON_SFT 0 +#define DL_SINE_ON_MASK 0x1 +#define DL_SINE_ON_MASK_SFT (0x1 << 0) + +/* AUDIO_TOP_CON0 */ +#define PDN_AFE_CTL_SFT 7 +#define PDN_AFE_CTL_MASK 0x1 +#define PDN_AFE_CTL_MASK_SFT (0x1 << 7) +#define PDN_DAC_CTL_SFT 6 +#define PDN_DAC_CTL_MASK 0x1 +#define PDN_DAC_CTL_MASK_SFT (0x1 << 6) +#define PDN_ADC_CTL_SFT 5 +#define PDN_ADC_CTL_MASK 0x1 +#define PDN_ADC_CTL_MASK_SFT (0x1 << 5) +#define PDN_ADDA6_ADC_CTL_SFT 4 +#define PDN_ADDA6_ADC_CTL_MASK 0x1 +#define PDN_ADDA6_ADC_CTL_MASK_SFT (0x1 << 4) +#define PDN_I2S_DL_CTL_SFT 3 +#define PDN_I2S_DL_CTL_MASK 0x1 +#define PDN_I2S_DL_CTL_MASK_SFT (0x1 << 3) +#define PWR_CLK_DIS_CTL_SFT 2 +#define PWR_CLK_DIS_CTL_MASK 0x1 +#define PWR_CLK_DIS_CTL_MASK_SFT (0x1 << 2) +#define PDN_AFE_TESTMODEL_CTL_SFT 1 +#define PDN_AFE_TESTMODEL_CTL_MASK 0x1 +#define PDN_AFE_TESTMODEL_CTL_MASK_SFT (0x1 << 1) +#define PDN_RESERVED_SFT 0 +#define PDN_RESERVED_MASK 0x1 +#define PDN_RESERVED_MASK_SFT (0x1 << 0) + +/* AFE_MON_DEBUG0 */ +#define AUDIO_SYS_TOP_MON_SWAP_SFT 14 +#define AUDIO_SYS_TOP_MON_SWAP_MASK 0x3 +#define AUDIO_SYS_TOP_MON_SWAP_MASK_SFT (0x3 << 14) +#define AUDIO_SYS_TOP_MON_SEL_SFT 8 +#define AUDIO_SYS_TOP_MON_SEL_MASK 0x1f +#define AUDIO_SYS_TOP_MON_SEL_MASK_SFT (0x1f << 8) +#define AFE_MON_SEL_SFT 0 +#define AFE_MON_SEL_MASK 0xff +#define AFE_MON_SEL_MASK_SFT (0xff << 0) + +/* AFUNC_AUD_CON0 */ +#define CCI_AUD_ANACK_SEL_SFT 15 +#define CCI_AUD_ANACK_SEL_MASK 0x1 +#define CCI_AUD_ANACK_SEL_MASK_SFT (0x1 << 15) +#define CCI_AUDIO_FIFO_WPTR_SFT 12 +#define CCI_AUDIO_FIFO_WPTR_MASK 0x7 +#define CCI_AUDIO_FIFO_WPTR_MASK_SFT (0x7 << 12) +#define CCI_SCRAMBLER_CG_EN_SFT 11 +#define CCI_SCRAMBLER_CG_EN_MASK 0x1 +#define CCI_SCRAMBLER_CG_EN_MASK_SFT (0x1 << 11) +#define CCI_LCH_INV_SFT 10 +#define CCI_LCH_INV_MASK 0x1 +#define CCI_LCH_INV_MASK_SFT (0x1 << 10) +#define CCI_RAND_EN_SFT 9 +#define CCI_RAND_EN_MASK 0x1 +#define CCI_RAND_EN_MASK_SFT (0x1 << 9) +#define CCI_SPLT_SCRMB_CLK_ON_SFT 8 +#define CCI_SPLT_SCRMB_CLK_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_CLK_ON_MASK_SFT (0x1 << 8) +#define CCI_SPLT_SCRMB_ON_SFT 7 +#define CCI_SPLT_SCRMB_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_ON_MASK_SFT (0x1 << 7) +#define CCI_AUD_IDAC_TEST_EN_SFT 6 +#define CCI_AUD_IDAC_TEST_EN_MASK 0x1 +#define CCI_AUD_IDAC_TEST_EN_MASK_SFT (0x1 << 6) +#define CCI_ZERO_PAD_DISABLE_SFT 5 +#define CCI_ZERO_PAD_DISABLE_MASK 0x1 +#define CCI_ZERO_PAD_DISABLE_MASK_SFT (0x1 << 5) +#define CCI_AUD_SPLIT_TEST_EN_SFT 4 +#define CCI_AUD_SPLIT_TEST_EN_MASK 0x1 +#define CCI_AUD_SPLIT_TEST_EN_MASK_SFT (0x1 << 4) +#define CCI_AUD_SDM_MUTEL_SFT 3 +#define CCI_AUD_SDM_MUTEL_MASK 0x1 +#define CCI_AUD_SDM_MUTEL_MASK_SFT (0x1 << 3) +#define CCI_AUD_SDM_MUTER_SFT 2 +#define CCI_AUD_SDM_MUTER_MASK 0x1 +#define CCI_AUD_SDM_MUTER_MASK_SFT (0x1 << 2) +#define CCI_AUD_SDM_7BIT_SEL_SFT 1 +#define CCI_AUD_SDM_7BIT_SEL_MASK 0x1 +#define CCI_AUD_SDM_7BIT_SEL_MASK_SFT (0x1 << 1) +#define CCI_SCRAMBLER_EN_SFT 0 +#define CCI_SCRAMBLER_EN_MASK 0x1 +#define CCI_SCRAMBLER_EN_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON1 */ +#define AUD_SDM_TEST_L_SFT 8 +#define AUD_SDM_TEST_L_MASK 0xff +#define AUD_SDM_TEST_L_MASK_SFT (0xff << 8) +#define AUD_SDM_TEST_R_SFT 0 +#define AUD_SDM_TEST_R_MASK 0xff +#define AUD_SDM_TEST_R_MASK_SFT (0xff << 0) + +/* AFUNC_AUD_CON2 */ +#define CCI_AUD_DAC_ANA_MUTE_SFT 7 +#define CCI_AUD_DAC_ANA_MUTE_MASK 0x1 +#define CCI_AUD_DAC_ANA_MUTE_MASK_SFT (0x1 << 7) +#define CCI_AUD_DAC_ANA_RSTB_SEL_SFT 6 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK 0x1 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK_SFT (0x1 << 6) +#define CCI_AUDIO_FIFO_CLKIN_INV_SFT 4 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK 0x1 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK_SFT (0x1 << 4) +#define CCI_AUDIO_FIFO_ENABLE_SFT 3 +#define CCI_AUDIO_FIFO_ENABLE_MASK 0x1 +#define CCI_AUDIO_FIFO_ENABLE_MASK_SFT (0x1 << 3) +#define CCI_ACD_MODE_SFT 2 +#define CCI_ACD_MODE_MASK 0x1 +#define CCI_ACD_MODE_MASK_SFT (0x1 << 2) +#define CCI_AFIFO_CLK_PWDB_SFT 1 +#define CCI_AFIFO_CLK_PWDB_MASK 0x1 +#define CCI_AFIFO_CLK_PWDB_MASK_SFT (0x1 << 1) +#define CCI_ACD_FUNC_RSTB_SFT 0 +#define CCI_ACD_FUNC_RSTB_MASK 0x1 +#define CCI_ACD_FUNC_RSTB_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON3 */ +#define SDM_ANA13M_TESTCK_SEL_SFT 15 +#define SDM_ANA13M_TESTCK_SEL_MASK 0x1 +#define SDM_ANA13M_TESTCK_SEL_MASK_SFT (0x1 << 15) +#define SDM_ANA13M_TESTCK_SRC_SEL_SFT 12 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 12) +#define SDM_TESTCK_SRC_SEL_SFT 8 +#define SDM_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_TESTCK_SRC_SEL_MASK_SFT (0x7 << 8) +#define DIGMIC_TESTCK_SRC_SEL_SFT 4 +#define DIGMIC_TESTCK_SRC_SEL_MASK 0x7 +#define DIGMIC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 4) +#define DIGMIC_TESTCK_SEL_SFT 0 +#define DIGMIC_TESTCK_SEL_MASK 0x1 +#define DIGMIC_TESTCK_SEL_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON4 */ +#define UL_FIFO_WCLK_INV_SFT 8 +#define UL_FIFO_WCLK_INV_MASK 0x1 +#define UL_FIFO_WCLK_INV_MASK_SFT (0x1 << 8) +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_SFT 6 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 6) +#define UL_FIFO_WDATA_TESTEN_SFT 5 +#define UL_FIFO_WDATA_TESTEN_MASK 0x1 +#define UL_FIFO_WDATA_TESTEN_MASK_SFT (0x1 << 5) +#define UL_FIFO_WDATA_TESTSRC_SEL_SFT 4 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 4) +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_SFT 3 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK 0x1 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK_SFT (0x1 << 3) +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_SFT 0 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK 0x7 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 0) + +/* AFUNC_AUD_CON5 */ +#define R_AUD_DAC_POS_LARGE_MONO_SFT 8 +#define R_AUD_DAC_POS_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_POS_LARGE_MONO_MASK_SFT (0xff << 8) +#define R_AUD_DAC_NEG_LARGE_MONO_SFT 0 +#define R_AUD_DAC_NEG_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_NEG_LARGE_MONO_MASK_SFT (0xff << 0) + +/* AFUNC_AUD_CON6 */ +#define R_AUD_DAC_POS_SMALL_MONO_SFT 12 +#define R_AUD_DAC_POS_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_POS_SMALL_MONO_MASK_SFT (0xf << 12) +#define R_AUD_DAC_NEG_SMALL_MONO_SFT 8 +#define R_AUD_DAC_NEG_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_NEG_SMALL_MONO_MASK_SFT (0xf << 8) +#define R_AUD_DAC_POS_TINY_MONO_SFT 6 +#define R_AUD_DAC_POS_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_POS_TINY_MONO_MASK_SFT (0x3 << 6) +#define R_AUD_DAC_NEG_TINY_MONO_SFT 4 +#define R_AUD_DAC_NEG_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_NEG_TINY_MONO_MASK_SFT (0x3 << 4) +#define R_AUD_DAC_MONO_SEL_SFT 3 +#define R_AUD_DAC_MONO_SEL_MASK 0x1 +#define R_AUD_DAC_MONO_SEL_MASK_SFT (0x1 << 3) +#define R_AUD_DAC_3TH_SEL_SFT 1 +#define R_AUD_DAC_3TH_SEL_MASK 0x1 +#define R_AUD_DAC_3TH_SEL_MASK_SFT (0x1 << 1) +#define R_AUD_DAC_SW_RSTB_SFT 0 +#define R_AUD_DAC_SW_RSTB_MASK 0x1 +#define R_AUD_DAC_SW_RSTB_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON7 */ +#define UL2_DIGMIC_TESTCK_SRC_SEL_SFT 10 +#define UL2_DIGMIC_TESTCK_SRC_SEL_MASK 0x7 +#define UL2_DIGMIC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 10) +#define UL2_DIGMIC_TESTCK_SEL_SFT 9 +#define UL2_DIGMIC_TESTCK_SEL_MASK 0x1 +#define UL2_DIGMIC_TESTCK_SEL_MASK_SFT (0x1 << 9) +#define UL2_FIFO_WCLK_INV_SFT 8 +#define UL2_FIFO_WCLK_INV_MASK 0x1 +#define UL2_FIFO_WCLK_INV_MASK_SFT (0x1 << 8) +#define UL2_FIFO_DIGMIC_WDATA_TESTSRC_SEL_SFT 6 +#define UL2_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL2_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 6) +#define UL2_FIFO_WDATA_TESTEN_SFT 5 +#define UL2_FIFO_WDATA_TESTEN_MASK 0x1 +#define UL2_FIFO_WDATA_TESTEN_MASK_SFT (0x1 << 5) +#define UL2_FIFO_WDATA_TESTSRC_SEL_SFT 4 +#define UL2_FIFO_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL2_FIFO_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 4) +#define UL2_FIFO_WCLK_6P5M_TESTCK_SEL_SFT 3 +#define UL2_FIFO_WCLK_6P5M_TESTCK_SEL_MASK 0x1 +#define UL2_FIFO_WCLK_6P5M_TESTCK_SEL_MASK_SFT (0x1 << 3) +#define UL2_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_SFT 0 +#define UL2_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK 0x7 +#define UL2_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 0) + +/* AFUNC_AUD_CON8 */ +#define SPLITTER2_DITHER_EN_SFT 9 +#define SPLITTER2_DITHER_EN_MASK 0x1 +#define SPLITTER2_DITHER_EN_MASK_SFT (0x1 << 9) +#define SPLITTER1_DITHER_EN_SFT 8 +#define SPLITTER1_DITHER_EN_MASK 0x1 +#define SPLITTER1_DITHER_EN_MASK_SFT (0x1 << 8) +#define SPLITTER2_DITHER_GAIN_SFT 4 +#define SPLITTER2_DITHER_GAIN_MASK 0xf +#define SPLITTER2_DITHER_GAIN_MASK_SFT (0xf << 4) +#define SPLITTER1_DITHER_GAIN_SFT 0 +#define SPLITTER1_DITHER_GAIN_MASK 0xf +#define SPLITTER1_DITHER_GAIN_MASK_SFT (0xf << 0) + +/* AFUNC_AUD_CON9 */ +#define CCI_AUD_ANACK_SEL_2ND_SFT 15 +#define CCI_AUD_ANACK_SEL_2ND_MASK 0x1 +#define CCI_AUD_ANACK_SEL_2ND_MASK_SFT (0x1 << 15) +#define CCI_AUDIO_FIFO_WPTR_2ND_SFT 12 +#define CCI_AUDIO_FIFO_WPTR_2ND_MASK 0x7 +#define CCI_AUDIO_FIFO_WPTR_2ND_MASK_SFT (0x7 << 12) +#define CCI_SCRAMBLER_CG_EN_2ND_SFT 11 +#define CCI_SCRAMBLER_CG_EN_2ND_MASK 0x1 +#define CCI_SCRAMBLER_CG_EN_2ND_MASK_SFT (0x1 << 11) +#define CCI_LCH_INV_2ND_SFT 10 +#define CCI_LCH_INV_2ND_MASK 0x1 +#define CCI_LCH_INV_2ND_MASK_SFT (0x1 << 10) +#define CCI_RAND_EN_2ND_SFT 9 +#define CCI_RAND_EN_2ND_MASK 0x1 +#define CCI_RAND_EN_2ND_MASK_SFT (0x1 << 9) +#define CCI_SPLT_SCRMB_CLK_ON_2ND_SFT 8 +#define CCI_SPLT_SCRMB_CLK_ON_2ND_MASK 0x1 +#define CCI_SPLT_SCRMB_CLK_ON_2ND_MASK_SFT (0x1 << 8) +#define CCI_SPLT_SCRMB_ON_2ND_SFT 7 +#define CCI_SPLT_SCRMB_ON_2ND_MASK 0x1 +#define CCI_SPLT_SCRMB_ON_2ND_MASK_SFT (0x1 << 7) +#define CCI_AUD_IDAC_TEST_EN_2ND_SFT 6 +#define CCI_AUD_IDAC_TEST_EN_2ND_MASK 0x1 +#define CCI_AUD_IDAC_TEST_EN_2ND_MASK_SFT (0x1 << 6) +#define CCI_ZERO_PAD_DISABLE_2ND_SFT 5 +#define CCI_ZERO_PAD_DISABLE_2ND_MASK 0x1 +#define CCI_ZERO_PAD_DISABLE_2ND_MASK_SFT (0x1 << 5) +#define CCI_AUD_SPLIT_TEST_EN_2ND_SFT 4 +#define CCI_AUD_SPLIT_TEST_EN_2ND_MASK 0x1 +#define CCI_AUD_SPLIT_TEST_EN_2ND_MASK_SFT (0x1 << 4) +#define CCI_AUD_SDM_MUTEL_2ND_SFT 3 +#define CCI_AUD_SDM_MUTEL_2ND_MASK 0x1 +#define CCI_AUD_SDM_MUTEL_2ND_MASK_SFT (0x1 << 3) +#define CCI_AUD_SDM_MUTER_2ND_SFT 2 +#define CCI_AUD_SDM_MUTER_2ND_MASK 0x1 +#define CCI_AUD_SDM_MUTER_2ND_MASK_SFT (0x1 << 2) +#define CCI_AUD_SDM_7BIT_SEL_2ND_SFT 1 +#define CCI_AUD_SDM_7BIT_SEL_2ND_MASK 0x1 +#define CCI_AUD_SDM_7BIT_SEL_2ND_MASK_SFT (0x1 << 1) +#define CCI_SCRAMBLER_EN_2ND_SFT 0 +#define CCI_SCRAMBLER_EN_2ND_MASK 0x1 +#define CCI_SCRAMBLER_EN_2ND_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON10 */ +#define AUD_SDM_TEST_L_2ND_SFT 8 +#define AUD_SDM_TEST_L_2ND_MASK 0xff +#define AUD_SDM_TEST_L_2ND_MASK_SFT (0xff << 8) +#define AUD_SDM_TEST_R_2ND_SFT 0 +#define AUD_SDM_TEST_R_2ND_MASK 0xff +#define AUD_SDM_TEST_R_2ND_MASK_SFT (0xff << 0) + +/* AFUNC_AUD_CON11 */ +#define CCI_AUD_DAC_ANA_MUTE_2ND_SFT 7 +#define CCI_AUD_DAC_ANA_MUTE_2ND_MASK 0x1 +#define CCI_AUD_DAC_ANA_MUTE_2ND_MASK_SFT (0x1 << 7) +#define CCI_AUD_DAC_ANA_RSTB_SEL_2ND_SFT 6 +#define CCI_AUD_DAC_ANA_RSTB_SEL_2ND_MASK 0x1 +#define CCI_AUD_DAC_ANA_RSTB_SEL_2ND_MASK_SFT (0x1 << 6) +#define CCI_AUDIO_FIFO_CLKIN_INV_2ND_SFT 4 +#define CCI_AUDIO_FIFO_CLKIN_INV_2ND_MASK 0x1 +#define CCI_AUDIO_FIFO_CLKIN_INV_2ND_MASK_SFT (0x1 << 4) +#define CCI_AUDIO_FIFO_ENABLE_2ND_SFT 3 +#define CCI_AUDIO_FIFO_ENABLE_2ND_MASK 0x1 +#define CCI_AUDIO_FIFO_ENABLE_2ND_MASK_SFT (0x1 << 3) +#define CCI_ACD_MODE_2ND_SFT 2 +#define CCI_ACD_MODE_2ND_MASK 0x1 +#define CCI_ACD_MODE_2ND_MASK_SFT (0x1 << 2) +#define CCI_AFIFO_CLK_PWDB_2ND_SFT 1 +#define CCI_AFIFO_CLK_PWDB_2ND_MASK 0x1 +#define CCI_AFIFO_CLK_PWDB_2ND_MASK_SFT (0x1 << 1) +#define CCI_ACD_FUNC_RSTB_2ND_SFT 0 +#define CCI_ACD_FUNC_RSTB_2ND_MASK 0x1 +#define CCI_ACD_FUNC_RSTB_2ND_MASK_SFT (0x1 << 0) + +/* AFUNC_AUD_CON12 */ +#define SPLITTER2_DITHER_EN_2ND_SFT 9 +#define SPLITTER2_DITHER_EN_2ND_MASK 0x1 +#define SPLITTER2_DITHER_EN_2ND_MASK_SFT (0x1 << 9) +#define SPLITTER1_DITHER_EN_2ND_SFT 8 +#define SPLITTER1_DITHER_EN_2ND_MASK 0x1 +#define SPLITTER1_DITHER_EN_2ND_MASK_SFT (0x1 << 8) +#define SPLITTER2_DITHER_GAIN_2ND_SFT 4 +#define SPLITTER2_DITHER_GAIN_2ND_MASK 0xf +#define SPLITTER2_DITHER_GAIN_2ND_MASK_SFT (0xf << 4) +#define SPLITTER1_DITHER_GAIN_2ND_SFT 0 +#define SPLITTER1_DITHER_GAIN_2ND_MASK 0xf +#define SPLITTER1_DITHER_GAIN_2ND_MASK_SFT (0xf << 0) + +/* AFUNC_AUD_MON0 */ +#define AUD_SCR_OUT_L_SFT 8 +#define AUD_SCR_OUT_L_MASK 0xff +#define AUD_SCR_OUT_L_MASK_SFT (0xff << 8) +#define AUD_SCR_OUT_R_SFT 0 +#define AUD_SCR_OUT_R_MASK 0xff +#define AUD_SCR_OUT_R_MASK_SFT (0xff << 0) + +/* AFUNC_AUD_MON1 */ +#define AUD_SCR_OUT_L_2ND_SFT 8 +#define AUD_SCR_OUT_L_2ND_MASK 0xff +#define AUD_SCR_OUT_L_2ND_MASK_SFT (0xff << 8) +#define AUD_SCR_OUT_R_2ND_SFT 0 +#define AUD_SCR_OUT_R_2ND_MASK 0xff +#define AUD_SCR_OUT_R_2ND_MASK_SFT (0xff << 0) + +/* AUDRC_TUNE_MON0 */ +#define ASYNC_TEST_OUT_BCK_SFT 15 +#define ASYNC_TEST_OUT_BCK_MASK 0x1 +#define ASYNC_TEST_OUT_BCK_MASK_SFT (0x1 << 15) +#define RGS_AUDRCTUNE1READ_SFT 8 +#define RGS_AUDRCTUNE1READ_MASK 0x1f +#define RGS_AUDRCTUNE1READ_MASK_SFT (0x1f << 8) +#define RGS_AUDRCTUNE0READ_SFT 0 +#define RGS_AUDRCTUNE0READ_MASK 0x1f +#define RGS_AUDRCTUNE0READ_MASK_SFT (0x1f << 0) + +/* AFE_ADDA_MTKAIF_FIFO_CFG0 */ +#define AFE_RESERVED_SFT 1 +#define AFE_RESERVED_MASK 0x7fff +#define AFE_RESERVED_MASK_SFT (0x7fff << 1) +#define RG_MTKAIF_RXIF_FIFO_INTEN_SFT 0 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK 0x1 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_FIFO_LOG_MON1 */ +#define MTKAIF_RXIF_WR_FULL_STATUS_SFT 1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK 0x1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK_SFT (0x1 << 1) +#define MTKAIF_RXIF_RD_EMPTY_STATUS_SFT 0 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK 0x1 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_MON0 */ +#define MTKAIFTX_V3_SYNC_OUT_SFT 15 +#define MTKAIFTX_V3_SYNC_OUT_MASK 0x1 +#define MTKAIFTX_V3_SYNC_OUT_MASK_SFT (0x1 << 15) +#define MTKAIFTX_V3_SDATA_OUT3_SFT 14 +#define MTKAIFTX_V3_SDATA_OUT3_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT3_MASK_SFT (0x1 << 14) +#define MTKAIFTX_V3_SDATA_OUT2_SFT 13 +#define MTKAIFTX_V3_SDATA_OUT2_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT2_MASK_SFT (0x1 << 13) +#define MTKAIFTX_V3_SDATA_OUT1_SFT 12 +#define MTKAIFTX_V3_SDATA_OUT1_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_FIFO_STATUS_SFT 0 +#define MTKAIF_RXIF_FIFO_STATUS_MASK 0xfff +#define MTKAIF_RXIF_FIFO_STATUS_MASK_SFT (0xfff << 0) + +/* AFE_ADDA_MTKAIF_MON1 */ +#define MTKAIFRX_V3_SYNC_IN_SFT 15 +#define MTKAIFRX_V3_SYNC_IN_MASK 0x1 +#define MTKAIFRX_V3_SYNC_IN_MASK_SFT (0x1 << 15) +#define MTKAIFRX_V3_SDATA_IN3_SFT 14 +#define MTKAIFRX_V3_SDATA_IN3_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN3_MASK_SFT (0x1 << 14) +#define MTKAIFRX_V3_SDATA_IN2_SFT 13 +#define MTKAIFRX_V3_SDATA_IN2_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN2_MASK_SFT (0x1 << 13) +#define MTKAIFRX_V3_SDATA_IN1_SFT 12 +#define MTKAIFRX_V3_SDATA_IN1_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_SFT 11 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK 0x1 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK_SFT (0x1 << 11) +#define MTKAIF_RXIF_INVALID_FLAG_SFT 8 +#define MTKAIF_RXIF_INVALID_FLAG_MASK 0x1 +#define MTKAIF_RXIF_INVALID_FLAG_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_INVALID_CYCLE_SFT 0 +#define MTKAIF_RXIF_INVALID_CYCLE_MASK 0xff +#define MTKAIF_RXIF_INVALID_CYCLE_MASK_SFT (0xff << 0) + +/* AFE_ADDA_MTKAIF_MON2 */ +#define MTKAIF_TXIF_IN_CH2_SFT 8 +#define MTKAIF_TXIF_IN_CH2_MASK 0xff +#define MTKAIF_TXIF_IN_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_TXIF_IN_CH1_SFT 0 +#define MTKAIF_TXIF_IN_CH1_MASK 0xff +#define MTKAIF_TXIF_IN_CH1_MASK_SFT (0xff << 0) + +/* AFE_ADDA6_MTKAIF_MON3 */ +#define ADDA6_MTKAIF_TXIF_IN_CH2_SFT 8 +#define ADDA6_MTKAIF_TXIF_IN_CH2_MASK 0xff +#define ADDA6_MTKAIF_TXIF_IN_CH2_MASK_SFT (0xff << 8) +#define ADDA6_MTKAIF_TXIF_IN_CH1_SFT 0 +#define ADDA6_MTKAIF_TXIF_IN_CH1_MASK 0xff +#define ADDA6_MTKAIF_TXIF_IN_CH1_MASK_SFT (0xff << 0) + +/* AFE_ADDA_MTKAIF_MON4 */ +#define MTKAIF_RXIF_OUT_CH2_SFT 8 +#define MTKAIF_RXIF_OUT_CH2_MASK 0xff +#define MTKAIF_RXIF_OUT_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_RXIF_OUT_CH1_SFT 0 +#define MTKAIF_RXIF_OUT_CH1_MASK 0xff +#define MTKAIF_RXIF_OUT_CH1_MASK_SFT (0xff << 0) + +/* AFE_ADDA_MTKAIF_MON5 */ +#define MTKAIF_RXIF_OUT_CH3_SFT 0 +#define MTKAIF_RXIF_OUT_CH3_MASK 0xff +#define MTKAIF_RXIF_OUT_CH3_MASK_SFT (0xff << 0) + +/* AFE_ADDA_MTKAIF_CFG0 */ +#define RG_MTKAIF_RXIF_CLKINV_SFT 15 +#define RG_MTKAIF_RXIF_CLKINV_MASK 0x1 +#define RG_MTKAIF_RXIF_CLKINV_MASK_SFT (0x1 << 15) +#define RG_ADDA6_MTKAIF_TXIF_PROTOCOL2_SFT 9 +#define RG_ADDA6_MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define RG_ADDA6_MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 9) +#define RG_MTKAIF_RXIF_PROTOCOL2_SFT 8 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 8) +#define RG_MTKAIF_BYPASS_SRC_MODE_SFT 6 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK 0x3 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK_SFT (0x3 << 6) +#define RG_MTKAIF_BYPASS_SRC_TEST_SFT 5 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK 0x1 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK_SFT (0x1 << 5) +#define RG_MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define RG_ADDA6_MTKAIF_PMIC_TXIF_8TO5_SFT 3 +#define RG_ADDA6_MTKAIF_PMIC_TXIF_8TO5_MASK 0x1 +#define RG_ADDA6_MTKAIF_PMIC_TXIF_8TO5_MASK_SFT (0x1 << 3) +#define RG_MTKAIF_PMIC_TXIF_8TO5_SFT 2 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK 0x1 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define RG_MTKAIF_LOOPBACK_TEST2_SFT 1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK_SFT (0x1 << 1) +#define RG_MTKAIF_LOOPBACK_TEST1_SFT 0 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG0 */ +#define RG_MTKAIF_RXIF_VOICE_MODE_SFT 12 +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_DATA_BIT_SFT 8 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK 0x7 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK_SFT (0x7 << 8) +#define RG_MTKAIF_RXIF_FIFO_RSP_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK_SFT (0x1 << 3) +#define RG_MTKAIF_RXIF_DATA_MODE_SFT 0 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK 0x1 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG1 */ +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_SFT 12 +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_SFT 8 +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8) +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_SFT 4 +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4) +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_SFT 0 +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK_SFT (0xf << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG2 */ +#define RG_MTKAIF_RXIF_P2_INPUT_SEL_SFT 15 +#define RG_MTKAIF_RXIF_P2_INPUT_SEL_MASK 0x1 +#define RG_MTKAIF_RXIF_P2_INPUT_SEL_MASK_SFT (0x1 << 15) +#define RG_MTKAIF_RXIF_SYNC_WORD2_DISABLE_SFT 14 +#define RG_MTKAIF_RXIF_SYNC_WORD2_DISABLE_MASK 0x1 +#define RG_MTKAIF_RXIF_SYNC_WORD2_DISABLE_MASK_SFT (0x1 << 14) +#define RG_MTKAIF_RXIF_SYNC_WORD1_DISABLE_SFT 13 +#define RG_MTKAIF_RXIF_SYNC_WORD1_DISABLE_MASK 0x1 +#define RG_MTKAIF_RXIF_SYNC_WORD1_DISABLE_MASK_SFT (0x1 << 13) +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_SFT 12 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK 0x1 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK_SFT (0x1 << 12) +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_SFT 0 +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK 0xfff +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG3 */ +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_SFT 7 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK 0x1 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK_SFT (0x1 << 7) +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 3) + +/* AFE_ADDA_MTKAIF_SYNCWORD_CFG0 */ +#define RG_MTKAIF_RX_SYNC_WORD2_SFT 4 +#define RG_MTKAIF_RX_SYNC_WORD2_MASK 0x7 +#define RG_MTKAIF_RX_SYNC_WORD2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RX_SYNC_WORD1_SFT 0 +#define RG_MTKAIF_RX_SYNC_WORD1_MASK 0x7 +#define RG_MTKAIF_RX_SYNC_WORD1_MASK_SFT (0x7 << 0) + +/* AFE_ADDA_MTKAIF_SYNCWORD_CFG1 */ +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD2_SFT 12 +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD2_MASK 0x7 +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD2_MASK_SFT (0x7 << 12) +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD1_SFT 8 +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD1_MASK 0x7 +#define RG_ADDA6_MTKAIF_TX_SYNC_WORD1_MASK_SFT (0x7 << 8) +#define RG_ADDA_MTKAIF_TX_SYNC_WORD2_SFT 4 +#define RG_ADDA_MTKAIF_TX_SYNC_WORD2_MASK 0x7 +#define RG_ADDA_MTKAIF_TX_SYNC_WORD2_MASK_SFT (0x7 << 4) +#define RG_ADDA_MTKAIF_TX_SYNC_WORD1_SFT 0 +#define RG_ADDA_MTKAIF_TX_SYNC_WORD1_MASK 0x7 +#define RG_ADDA_MTKAIF_TX_SYNC_WORD1_MASK_SFT (0x7 << 0) + +/* AFE_SGEN_CFG0 */ +#define SGEN_AMP_DIV_CH1_CTL_SFT 12 +#define SGEN_AMP_DIV_CH1_CTL_MASK 0xf +#define SGEN_AMP_DIV_CH1_CTL_MASK_SFT (0xf << 12) +#define SGEN_DAC_EN_CTL_SFT 7 +#define SGEN_DAC_EN_CTL_MASK 0x1 +#define SGEN_DAC_EN_CTL_MASK_SFT (0x1 << 7) +#define SGEN_MUTE_SW_CTL_SFT 6 +#define SGEN_MUTE_SW_CTL_MASK 0x1 +#define SGEN_MUTE_SW_CTL_MASK_SFT (0x1 << 6) +#define R_AUD_SDM_MUTE_L_SFT 5 +#define R_AUD_SDM_MUTE_L_MASK 0x1 +#define R_AUD_SDM_MUTE_L_MASK_SFT (0x1 << 5) +#define R_AUD_SDM_MUTE_R_SFT 4 +#define R_AUD_SDM_MUTE_R_MASK 0x1 +#define R_AUD_SDM_MUTE_R_MASK_SFT (0x1 << 4) +#define R_AUD_SDM_MUTE_L_2ND_SFT 3 +#define R_AUD_SDM_MUTE_L_2ND_MASK 0x1 +#define R_AUD_SDM_MUTE_L_2ND_MASK_SFT (0x1 << 3) +#define R_AUD_SDM_MUTE_R_2ND_SFT 2 +#define R_AUD_SDM_MUTE_R_2ND_MASK 0x1 +#define R_AUD_SDM_MUTE_R_2ND_MASK_SFT (0x1 << 2) + +/* AFE_SGEN_CFG1 */ +#define C_SGEN_RCH_INV_5BIT_SFT 15 +#define C_SGEN_RCH_INV_5BIT_MASK 0x1 +#define C_SGEN_RCH_INV_5BIT_MASK_SFT (0x1 << 15) +#define C_SGEN_RCH_INV_8BIT_SFT 14 +#define C_SGEN_RCH_INV_8BIT_MASK 0x1 +#define C_SGEN_RCH_INV_8BIT_MASK_SFT (0x1 << 14) +#define SGEN_FREQ_DIV_CH1_CTL_SFT 0 +#define SGEN_FREQ_DIV_CH1_CTL_MASK 0x1f +#define SGEN_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 0) + +/* AFE_ADC_ASYNC_FIFO_CFG */ +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_SFT 5 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 5) +#define RG_UL_ASYNC_FIFO_SOFT_RST_SFT 4 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK_SFT (0x1 << 4) +#define RG_AMIC_UL_ADC_CLK_SEL_SFT 1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK 0x1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK_SFT (0x1 << 1) + +/* AFE_ADC_ASYNC_FIFO_CFG1 */ +#define RG_UL2_ASYNC_FIFO_SOFT_RST_EN_SFT 5 +#define RG_UL2_ASYNC_FIFO_SOFT_RST_EN_MASK 0x1 +#define RG_UL2_ASYNC_FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 5) +#define RG_UL2_ASYNC_FIFO_SOFT_RST_SFT 4 +#define RG_UL2_ASYNC_FIFO_SOFT_RST_MASK 0x1 +#define RG_UL2_ASYNC_FIFO_SOFT_RST_MASK_SFT (0x1 << 4) + +/* AFE_DCCLK_CFG0 */ +#define DCCLK_DIV_SFT 5 +#define DCCLK_DIV_MASK 0x7ff +#define DCCLK_DIV_MASK_SFT (0x7ff << 5) +#define DCCLK_INV_SFT 4 +#define DCCLK_INV_MASK 0x1 +#define DCCLK_INV_MASK_SFT (0x1 << 4) +#define DCCLK_REF_CK_SEL_SFT 2 +#define DCCLK_REF_CK_SEL_MASK 0x3 +#define DCCLK_REF_CK_SEL_MASK_SFT (0x3 << 2) +#define DCCLK_PDN_SFT 1 +#define DCCLK_PDN_MASK 0x1 +#define DCCLK_PDN_MASK_SFT (0x1 << 1) +#define DCCLK_GEN_ON_SFT 0 +#define DCCLK_GEN_ON_MASK 0x1 +#define DCCLK_GEN_ON_MASK_SFT (0x1 << 0) + +/* AFE_DCCLK_CFG1 */ +#define RESYNC_SRC_SEL_SFT 10 +#define RESYNC_SRC_SEL_MASK 0x3 +#define RESYNC_SRC_SEL_MASK_SFT (0x3 << 10) +#define RESYNC_SRC_CK_INV_SFT 9 +#define RESYNC_SRC_CK_INV_MASK 0x1 +#define RESYNC_SRC_CK_INV_MASK_SFT (0x1 << 9) +#define DCCLK_RESYNC_BYPASS_SFT 8 +#define DCCLK_RESYNC_BYPASS_MASK 0x1 +#define DCCLK_RESYNC_BYPASS_MASK_SFT (0x1 << 8) +#define DCCLK_PHASE_SEL_SFT 4 +#define DCCLK_PHASE_SEL_MASK 0xf +#define DCCLK_PHASE_SEL_MASK_SFT (0xf << 4) + +/* AUDIO_DIG_CFG */ +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT 15 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT (0x1 << 15) +#define RG_AUD_PAD_TOP_PHASE_MODE2_SFT 8 +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT (0x7f << 8) +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT 7 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT (0x1 << 7) +#define RG_AUD_PAD_TOP_PHASE_MODE_SFT 0 +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT (0x7f << 0) + +/* AUDIO_DIG_CFG1 */ +#define RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT 7 +#define RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT (0x1 << 7) +#define RG_AUD_PAD_TOP_PHASE_MODE3_SFT 0 +#define RG_AUD_PAD_TOP_PHASE_MODE3_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE3_MASK_SFT (0x7f << 0) + +/* AFE_AUD_PAD_TOP */ +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_SFT 12 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK 0x7 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK_SFT (0x7 << 12) +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_SFT 11 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK 0x1 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK_SFT (0x1 << 11) +#define RG_AUD_PAD_TOP_TX_FIFO_ON_SFT 8 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK 0x1 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK_SFT (0x1 << 8) + +/* AFE_AUD_PAD_TOP_MON */ +#define ADDA_AUD_PAD_TOP_MON_SFT 0 +#define ADDA_AUD_PAD_TOP_MON_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON_MASK_SFT (0xffff << 0) + +/* AFE_AUD_PAD_TOP_MON1 */ +#define ADDA_AUD_PAD_TOP_MON1_SFT 0 +#define ADDA_AUD_PAD_TOP_MON1_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON1_MASK_SFT (0xffff << 0) + +/* AFE_AUD_PAD_TOP_MON2 */ +#define ADDA_AUD_PAD_TOP_MON2_SFT 0 +#define ADDA_AUD_PAD_TOP_MON2_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON2_MASK_SFT (0xffff << 0) + +/* AFE_DL_NLE_CFG */ +#define NLE_RCH_HPGAIN_SEL_SFT 10 +#define NLE_RCH_HPGAIN_SEL_MASK 0x1 +#define NLE_RCH_HPGAIN_SEL_MASK_SFT (0x1 << 10) +#define NLE_RCH_CH_SEL_SFT 9 +#define NLE_RCH_CH_SEL_MASK 0x1 +#define NLE_RCH_CH_SEL_MASK_SFT (0x1 << 9) +#define NLE_RCH_ON_SFT 8 +#define NLE_RCH_ON_MASK 0x1 +#define NLE_RCH_ON_MASK_SFT (0x1 << 8) +#define NLE_LCH_HPGAIN_SEL_SFT 2 +#define NLE_LCH_HPGAIN_SEL_MASK 0x1 +#define NLE_LCH_HPGAIN_SEL_MASK_SFT (0x1 << 2) +#define NLE_LCH_CH_SEL_SFT 1 +#define NLE_LCH_CH_SEL_MASK 0x1 +#define NLE_LCH_CH_SEL_MASK_SFT (0x1 << 1) +#define NLE_LCH_ON_SFT 0 +#define NLE_LCH_ON_MASK 0x1 +#define NLE_LCH_ON_MASK_SFT (0x1 << 0) + +/* AFE_DL_NLE_MON */ +#define NLE_MONITOR_SFT 0 +#define NLE_MONITOR_MASK 0x3fff +#define NLE_MONITOR_MASK_SFT (0x3fff << 0) + +/* AFE_CG_EN_MON */ +#define CK_CG_EN_MON_SFT 0 +#define CK_CG_EN_MON_MASK 0x3f +#define CK_CG_EN_MON_MASK_SFT (0x3f << 0) + +/* AFE_MIC_ARRAY_CFG */ +#define RG_AMIC_ADC1_SOURCE_SEL_SFT 10 +#define RG_AMIC_ADC1_SOURCE_SEL_MASK 0x3 +#define RG_AMIC_ADC1_SOURCE_SEL_MASK_SFT (0x3 << 10) +#define RG_AMIC_ADC2_SOURCE_SEL_SFT 8 +#define RG_AMIC_ADC2_SOURCE_SEL_MASK 0x3 +#define RG_AMIC_ADC2_SOURCE_SEL_MASK_SFT (0x3 << 8) +#define RG_AMIC_ADC3_SOURCE_SEL_SFT 6 +#define RG_AMIC_ADC3_SOURCE_SEL_MASK 0x3 +#define RG_AMIC_ADC3_SOURCE_SEL_MASK_SFT (0x3 << 6) +#define RG_DMIC_ADC1_SOURCE_SEL_SFT 4 +#define RG_DMIC_ADC1_SOURCE_SEL_MASK 0x3 +#define RG_DMIC_ADC1_SOURCE_SEL_MASK_SFT (0x3 << 4) +#define RG_DMIC_ADC2_SOURCE_SEL_SFT 2 +#define RG_DMIC_ADC2_SOURCE_SEL_MASK 0x3 +#define RG_DMIC_ADC2_SOURCE_SEL_MASK_SFT (0x3 << 2) +#define RG_DMIC_ADC3_SOURCE_SEL_SFT 0 +#define RG_DMIC_ADC3_SOURCE_SEL_MASK 0x3 +#define RG_DMIC_ADC3_SOURCE_SEL_MASK_SFT (0x3 << 0) + +/* AFE_CHOP_CFG0 */ +#define RG_CHOP_DIV_SEL_SFT 4 +#define RG_CHOP_DIV_SEL_MASK 0x1f +#define RG_CHOP_DIV_SEL_MASK_SFT (0x1f << 4) +#define RG_CHOP_DIV_EN_SFT 0 +#define RG_CHOP_DIV_EN_MASK 0x1 +#define RG_CHOP_DIV_EN_MASK_SFT (0x1 << 0) + +/* AFE_MTKAIF_MUX_CFG */ +#define RG_ADDA6_EN_SEL_SFT 12 +#define RG_ADDA6_EN_SEL_MASK 0x1 +#define RG_ADDA6_EN_SEL_MASK_SFT (0x1 << 12) +#define RG_ADDA6_CH2_SEL_SFT 10 +#define RG_ADDA6_CH2_SEL_MASK 0x3 +#define RG_ADDA6_CH2_SEL_MASK_SFT (0x3 << 10) +#define RG_ADDA6_CH1_SEL_SFT 8 +#define RG_ADDA6_CH1_SEL_MASK 0x3 +#define RG_ADDA6_CH1_SEL_MASK_SFT (0x3 << 8) +#define RG_ADDA_EN_SEL_SFT 4 +#define RG_ADDA_EN_SEL_MASK 0x1 +#define RG_ADDA_EN_SEL_MASK_SFT (0x1 << 4) +#define RG_ADDA_CH2_SEL_SFT 2 +#define RG_ADDA_CH2_SEL_MASK 0x3 +#define RG_ADDA_CH2_SEL_MASK_SFT (0x3 << 2) +#define RG_ADDA_CH1_SEL_SFT 0 +#define RG_ADDA_CH1_SEL_MASK 0x3 +#define RG_ADDA_CH1_SEL_MASK_SFT (0x3 << 0) + +/* AFE_PMIC_NEWIF_CFG3 */ +#define RG_UP8X_SYNC_WORD_SFT 0 +#define RG_UP8X_SYNC_WORD_MASK 0xffff +#define RG_UP8X_SYNC_WORD_MASK_SFT (0xffff << 0) + +/* AFE_NCP_CFG0 */ +#define RG_NCP_CK1_VALID_CNT_SFT 9 +#define RG_NCP_CK1_VALID_CNT_MASK 0x7f +#define RG_NCP_CK1_VALID_CNT_MASK_SFT (0x7f << 9) +#define RG_NCP_ADITH_SFT 8 +#define RG_NCP_ADITH_MASK 0x1 +#define RG_NCP_ADITH_MASK_SFT (0x1 << 8) +#define RG_NCP_DITHER_EN_SFT 7 +#define RG_NCP_DITHER_EN_MASK 0x1 +#define RG_NCP_DITHER_EN_MASK_SFT (0x1 << 7) +#define RG_NCP_DITHER_FIXED_CK0_ACK1_2P_SFT 4 +#define RG_NCP_DITHER_FIXED_CK0_ACK1_2P_MASK 0x7 +#define RG_NCP_DITHER_FIXED_CK0_ACK1_2P_MASK_SFT (0x7 << 4) +#define RG_NCP_DITHER_FIXED_CK0_ACK2_2P_SFT 1 +#define RG_NCP_DITHER_FIXED_CK0_ACK2_2P_MASK 0x7 +#define RG_NCP_DITHER_FIXED_CK0_ACK2_2P_MASK_SFT (0x7 << 1) +#define RG_NCP_ON_SFT 0 +#define RG_NCP_ON_MASK 0x1 +#define RG_NCP_ON_MASK_SFT (0x1 << 0) + +/* AFE_NCP_CFG1 */ +#define RG_XY_VAL_CFG_EN_SFT 15 +#define RG_XY_VAL_CFG_EN_MASK 0x1 +#define RG_XY_VAL_CFG_EN_MASK_SFT (0x1 << 15) +#define RG_X_VAL_CFG_SFT 8 +#define RG_X_VAL_CFG_MASK 0x7f +#define RG_X_VAL_CFG_MASK_SFT (0x7f << 8) +#define RG_Y_VAL_CFG_SFT 0 +#define RG_Y_VAL_CFG_MASK 0x7f +#define RG_Y_VAL_CFG_MASK_SFT (0x7f << 0) + +/* AFE_NCP_CFG2 */ +#define RG_NCP_NONCLK_SET_SFT 1 +#define RG_NCP_NONCLK_SET_MASK 0x1 +#define RG_NCP_NONCLK_SET_MASK_SFT (0x1 << 1) +#define RG_NCP_PDDIS_EN_SFT 0 +#define RG_NCP_PDDIS_EN_MASK 0x1 +#define RG_NCP_PDDIS_EN_MASK_SFT (0x1 << 0) + +/* AUDENC_ANA_CON0 */ +#define RG_AUDPREAMPLON_SFT 0 +#define RG_AUDPREAMPLON_MASK 0x1 +#define RG_AUDPREAMPLON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPLDCCEN_SFT 1 +#define RG_AUDPREAMPLDCCEN_MASK 0x1 +#define RG_AUDPREAMPLDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPLDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPLDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPLPGATEST_SFT 3 +#define RG_AUDPREAMPLPGATEST_MASK 0x1 +#define RG_AUDPREAMPLPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPLVSCALE_SFT 4 +#define RG_AUDPREAMPLVSCALE_MASK 0x3 +#define RG_AUDPREAMPLVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPLINPUTSEL_SFT 6 +#define RG_AUDPREAMPLINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPLINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPLGAIN_SFT 8 +#define RG_AUDPREAMPLGAIN_MASK 0x7 +#define RG_AUDPREAMPLGAIN_MASK_SFT (0x7 << 8) +#define RG_BULKL_VCM_EN_SFT 11 +#define RG_BULKL_VCM_EN_MASK 0x1 +#define RG_BULKL_VCM_EN_MASK_SFT (0x1 << 11) +#define RG_AUDADCLPWRUP_SFT 12 +#define RG_AUDADCLPWRUP_MASK 0x1 +#define RG_AUDADCLPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCLINPUTSEL_SFT 13 +#define RG_AUDADCLINPUTSEL_MASK 0x3 +#define RG_AUDADCLINPUTSEL_MASK_SFT (0x3 << 13) + +/* AUDENC_ANA_CON1 */ +#define RG_AUDPREAMPRON_SFT 0 +#define RG_AUDPREAMPRON_MASK 0x1 +#define RG_AUDPREAMPRON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPRDCCEN_SFT 1 +#define RG_AUDPREAMPRDCCEN_MASK 0x1 +#define RG_AUDPREAMPRDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPRDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPRDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPRDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPRPGATEST_SFT 3 +#define RG_AUDPREAMPRPGATEST_MASK 0x1 +#define RG_AUDPREAMPRPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPRVSCALE_SFT 4 +#define RG_AUDPREAMPRVSCALE_MASK 0x3 +#define RG_AUDPREAMPRVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPRINPUTSEL_SFT 6 +#define RG_AUDPREAMPRINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPRINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPRGAIN_SFT 8 +#define RG_AUDPREAMPRGAIN_MASK 0x7 +#define RG_AUDPREAMPRGAIN_MASK_SFT (0x7 << 8) +#define RG_BULKR_VCM_EN_SFT 11 +#define RG_BULKR_VCM_EN_MASK 0x1 +#define RG_BULKR_VCM_EN_MASK_SFT (0x1 << 11) +#define RG_AUDADCRPWRUP_SFT 12 +#define RG_AUDADCRPWRUP_MASK 0x1 +#define RG_AUDADCRPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCRINPUTSEL_SFT 13 +#define RG_AUDADCRINPUTSEL_MASK 0x3 +#define RG_AUDADCRINPUTSEL_MASK_SFT (0x3 << 13) + +/* AUDENC_ANA_CON2 */ +#define RG_AUDPREAMP3ON_SFT 0 +#define RG_AUDPREAMP3ON_MASK 0x1 +#define RG_AUDPREAMP3ON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMP3DCCEN_SFT 1 +#define RG_AUDPREAMP3DCCEN_MASK 0x1 +#define RG_AUDPREAMP3DCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMP3DCPRECHARGE_SFT 2 +#define RG_AUDPREAMP3DCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMP3DCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMP3PGATEST_SFT 3 +#define RG_AUDPREAMP3PGATEST_MASK 0x1 +#define RG_AUDPREAMP3PGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMP3VSCALE_SFT 4 +#define RG_AUDPREAMP3VSCALE_MASK 0x3 +#define RG_AUDPREAMP3VSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMP3INPUTSEL_SFT 6 +#define RG_AUDPREAMP3INPUTSEL_MASK 0x3 +#define RG_AUDPREAMP3INPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMP3GAIN_SFT 8 +#define RG_AUDPREAMP3GAIN_MASK 0x7 +#define RG_AUDPREAMP3GAIN_MASK_SFT (0x7 << 8) +#define RG_BULK3_VCM_EN_SFT 11 +#define RG_BULK3_VCM_EN_MASK 0x1 +#define RG_BULK3_VCM_EN_MASK_SFT (0x1 << 11) +#define RG_AUDADC3PWRUP_SFT 12 +#define RG_AUDADC3PWRUP_MASK 0x1 +#define RG_AUDADC3PWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADC3INPUTSEL_SFT 13 +#define RG_AUDADC3INPUTSEL_MASK 0x3 +#define RG_AUDADC3INPUTSEL_MASK_SFT (0x3 << 13) + +/* AUDENC_ANA_CON3 */ +#define RG_AUDULHALFBIAS_SFT 0 +#define RG_AUDULHALFBIAS_MASK 0x1 +#define RG_AUDULHALFBIAS_MASK_SFT (0x1 << 0) +#define RG_AUDGLBVOWLPWEN_SFT 1 +#define RG_AUDGLBVOWLPWEN_MASK 0x1 +#define RG_AUDGLBVOWLPWEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLPEN_SFT 2 +#define RG_AUDPREAMPLPEN_MASK 0x1 +#define RG_AUDPREAMPLPEN_MASK_SFT (0x1 << 2) +#define RG_AUDADC1STSTAGELPEN_SFT 3 +#define RG_AUDADC1STSTAGELPEN_MASK 0x1 +#define RG_AUDADC1STSTAGELPEN_MASK_SFT (0x1 << 3) +#define RG_AUDADC2NDSTAGELPEN_SFT 4 +#define RG_AUDADC2NDSTAGELPEN_MASK 0x1 +#define RG_AUDADC2NDSTAGELPEN_MASK_SFT (0x1 << 4) +#define RG_AUDADCFLASHLPEN_SFT 5 +#define RG_AUDADCFLASHLPEN_MASK 0x1 +#define RG_AUDADCFLASHLPEN_MASK_SFT (0x1 << 5) +#define RG_AUDPREAMPIDDTEST_SFT 6 +#define RG_AUDPREAMPIDDTEST_MASK 0x3 +#define RG_AUDPREAMPIDDTEST_MASK_SFT (0x3 << 6) +#define RG_AUDADC1STSTAGEIDDTEST_SFT 8 +#define RG_AUDADC1STSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC1STSTAGEIDDTEST_MASK_SFT (0x3 << 8) +#define RG_AUDADC2NDSTAGEIDDTEST_SFT 10 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK_SFT (0x3 << 10) +#define RG_AUDADCREFBUFIDDTEST_SFT 12 +#define RG_AUDADCREFBUFIDDTEST_MASK 0x3 +#define RG_AUDADCREFBUFIDDTEST_MASK_SFT (0x3 << 12) +#define RG_AUDADCFLASHIDDTEST_SFT 14 +#define RG_AUDADCFLASHIDDTEST_MASK 0x3 +#define RG_AUDADCFLASHIDDTEST_MASK_SFT (0x3 << 14) + +/* AUDENC_ANA_CON4 */ +#define RG_AUDRULHALFBIAS_SFT 0 +#define RG_AUDRULHALFBIAS_MASK 0x1 +#define RG_AUDRULHALFBIAS_MASK_SFT (0x1 << 0) +#define RG_AUDGLBRVOWLPWEN_SFT 1 +#define RG_AUDGLBRVOWLPWEN_MASK 0x1 +#define RG_AUDGLBRVOWLPWEN_MASK_SFT (0x1 << 1) +#define RG_AUDRPREAMPLPEN_SFT 2 +#define RG_AUDRPREAMPLPEN_MASK 0x1 +#define RG_AUDRPREAMPLPEN_MASK_SFT (0x1 << 2) +#define RG_AUDRADC1STSTAGELPEN_SFT 3 +#define RG_AUDRADC1STSTAGELPEN_MASK 0x1 +#define RG_AUDRADC1STSTAGELPEN_MASK_SFT (0x1 << 3) +#define RG_AUDRADC2NDSTAGELPEN_SFT 4 +#define RG_AUDRADC2NDSTAGELPEN_MASK 0x1 +#define RG_AUDRADC2NDSTAGELPEN_MASK_SFT (0x1 << 4) +#define RG_AUDRADCFLASHLPEN_SFT 5 +#define RG_AUDRADCFLASHLPEN_MASK 0x1 +#define RG_AUDRADCFLASHLPEN_MASK_SFT (0x1 << 5) +#define RG_AUDRPREAMPIDDTEST_SFT 6 +#define RG_AUDRPREAMPIDDTEST_MASK 0x3 +#define RG_AUDRPREAMPIDDTEST_MASK_SFT (0x3 << 6) +#define RG_AUDRADC1STSTAGEIDDTEST_SFT 8 +#define RG_AUDRADC1STSTAGEIDDTEST_MASK 0x3 +#define RG_AUDRADC1STSTAGEIDDTEST_MASK_SFT (0x3 << 8) +#define RG_AUDRADC2NDSTAGEIDDTEST_SFT 10 +#define RG_AUDRADC2NDSTAGEIDDTEST_MASK 0x3 +#define RG_AUDRADC2NDSTAGEIDDTEST_MASK_SFT (0x3 << 10) +#define RG_AUDRADCREFBUFIDDTEST_SFT 12 +#define RG_AUDRADCREFBUFIDDTEST_MASK 0x3 +#define RG_AUDRADCREFBUFIDDTEST_MASK_SFT (0x3 << 12) +#define RG_AUDRADCFLASHIDDTEST_SFT 14 +#define RG_AUDRADCFLASHIDDTEST_MASK 0x3 +#define RG_AUDRADCFLASHIDDTEST_MASK_SFT (0x3 << 14) + +/* AUDENC_ANA_CON5 */ +#define RG_AUDADCCLKRSTB_SFT 0 +#define RG_AUDADCCLKRSTB_MASK 0x1 +#define RG_AUDADCCLKRSTB_MASK_SFT (0x1 << 0) +#define RG_AUDADCCLKSEL_SFT 1 +#define RG_AUDADCCLKSEL_MASK 0x3 +#define RG_AUDADCCLKSEL_MASK_SFT (0x3 << 1) +#define RG_AUDADCCLKSOURCE_SFT 3 +#define RG_AUDADCCLKSOURCE_MASK 0x3 +#define RG_AUDADCCLKSOURCE_MASK_SFT (0x3 << 3) +#define RG_AUDADCCLKGENMODE_SFT 5 +#define RG_AUDADCCLKGENMODE_MASK 0x3 +#define RG_AUDADCCLKGENMODE_MASK_SFT (0x3 << 5) +#define RG_AUDPREAMP_ACCFS_SFT 7 +#define RG_AUDPREAMP_ACCFS_MASK 0x1 +#define RG_AUDPREAMP_ACCFS_MASK_SFT (0x1 << 7) +#define RG_AUDPREAMPAAFEN_SFT 8 +#define RG_AUDPREAMPAAFEN_MASK 0x1 +#define RG_AUDPREAMPAAFEN_MASK_SFT (0x1 << 8) +#define RG_DCCVCMBUFLPMODSEL_SFT 9 +#define RG_DCCVCMBUFLPMODSEL_MASK 0x1 +#define RG_DCCVCMBUFLPMODSEL_MASK_SFT (0x1 << 9) +#define RG_DCCVCMBUFLPSWEN_SFT 10 +#define RG_DCCVCMBUFLPSWEN_MASK 0x1 +#define RG_DCCVCMBUFLPSWEN_MASK_SFT (0x1 << 10) +#define RG_AUDSPAREPGA_SFT 11 +#define RG_AUDSPAREPGA_MASK 0x1f +#define RG_AUDSPAREPGA_MASK_SFT (0x1f << 11) + +/* AUDENC_ANA_CON6 */ +#define RG_AUDADC1STSTAGESDENB_SFT 0 +#define RG_AUDADC1STSTAGESDENB_MASK 0x1 +#define RG_AUDADC1STSTAGESDENB_MASK_SFT (0x1 << 0) +#define RG_AUDADC2NDSTAGERESET_SFT 1 +#define RG_AUDADC2NDSTAGERESET_MASK 0x1 +#define RG_AUDADC2NDSTAGERESET_MASK_SFT (0x1 << 1) +#define RG_AUDADC3RDSTAGERESET_SFT 2 +#define RG_AUDADC3RDSTAGERESET_MASK 0x1 +#define RG_AUDADC3RDSTAGERESET_MASK_SFT (0x1 << 2) +#define RG_AUDADCFSRESET_SFT 3 +#define RG_AUDADCFSRESET_MASK 0x1 +#define RG_AUDADCFSRESET_MASK_SFT (0x1 << 3) +#define RG_AUDADCWIDECM_SFT 4 +#define RG_AUDADCWIDECM_MASK 0x1 +#define RG_AUDADCWIDECM_MASK_SFT (0x1 << 4) +#define RG_AUDADCNOPATEST_SFT 5 +#define RG_AUDADCNOPATEST_MASK 0x1 +#define RG_AUDADCNOPATEST_MASK_SFT (0x1 << 5) +#define RG_AUDADCBYPASS_SFT 6 +#define RG_AUDADCBYPASS_MASK 0x1 +#define RG_AUDADCBYPASS_MASK_SFT (0x1 << 6) +#define RG_AUDADCFFBYPASS_SFT 7 +#define RG_AUDADCFFBYPASS_MASK 0x1 +#define RG_AUDADCFFBYPASS_MASK_SFT (0x1 << 7) +#define RG_AUDADCDACFBCURRENT_SFT 8 +#define RG_AUDADCDACFBCURRENT_MASK 0x1 +#define RG_AUDADCDACFBCURRENT_MASK_SFT (0x1 << 8) +#define RG_AUDADCDACIDDTEST_SFT 9 +#define RG_AUDADCDACIDDTEST_MASK 0x3 +#define RG_AUDADCDACIDDTEST_MASK_SFT (0x3 << 9) +#define RG_AUDADCDACNRZ_SFT 11 +#define RG_AUDADCDACNRZ_MASK 0x1 +#define RG_AUDADCDACNRZ_MASK_SFT (0x1 << 11) +#define RG_AUDADCNODEM_SFT 12 +#define RG_AUDADCNODEM_MASK 0x1 +#define RG_AUDADCNODEM_MASK_SFT (0x1 << 12) +#define RG_AUDADCDACTEST_SFT 13 +#define RG_AUDADCDACTEST_MASK 0x1 +#define RG_AUDADCDACTEST_MASK_SFT (0x1 << 13) +#define RG_AUDADCDAC0P25FS_SFT 14 +#define RG_AUDADCDAC0P25FS_MASK 0x1 +#define RG_AUDADCDAC0P25FS_MASK_SFT (0x1 << 14) +#define RG_AUDADCRDAC0P25FS_SFT 15 +#define RG_AUDADCRDAC0P25FS_MASK 0x1 +#define RG_AUDADCRDAC0P25FS_MASK_SFT (0x1 << 15) + +/* AUDENC_ANA_CON7 */ +#define RG_AUDADCTESTDATA_SFT 0 +#define RG_AUDADCTESTDATA_MASK 0xffff +#define RG_AUDADCTESTDATA_MASK_SFT (0xffff << 0) + +/* AUDENC_ANA_CON8 */ +#define RG_AUDRCTUNEL_SFT 0 +#define RG_AUDRCTUNEL_MASK 0x1f +#define RG_AUDRCTUNEL_MASK_SFT (0x1f << 0) +#define RG_AUDRCTUNELSEL_SFT 5 +#define RG_AUDRCTUNELSEL_MASK 0x1 +#define RG_AUDRCTUNELSEL_MASK_SFT (0x1 << 5) +#define RG_AUDRCTUNER_SFT 8 +#define RG_AUDRCTUNER_MASK 0x1f +#define RG_AUDRCTUNER_MASK_SFT (0x1f << 8) +#define RG_AUDRCTUNERSEL_SFT 13 +#define RG_AUDRCTUNERSEL_MASK 0x1 +#define RG_AUDRCTUNERSEL_MASK_SFT (0x1 << 13) + +/* AUDENC_ANA_CON9 */ +#define RG_AUD3CTUNEL_SFT 0 +#define RG_AUD3CTUNEL_MASK 0x1f +#define RG_AUD3CTUNEL_MASK_SFT (0x1f << 0) +#define RG_AUD3CTUNELSEL_SFT 5 +#define RG_AUD3CTUNELSEL_MASK 0x1 +#define RG_AUD3CTUNELSEL_MASK_SFT (0x1 << 5) +#define RGS_AUDRCTUNE3READ_SFT 6 +#define RGS_AUDRCTUNE3READ_MASK 0x1f +#define RGS_AUDRCTUNE3READ_MASK_SFT (0x1f << 6) +#define RG_AUD3SPARE_SFT 11 +#define RG_AUD3SPARE_MASK 0x1f +#define RG_AUD3SPARE_MASK_SFT (0x1f << 11) + +/* AUDENC_ANA_CON10 */ +#define RGS_AUDRCTUNELREAD_SFT 0 +#define RGS_AUDRCTUNELREAD_MASK 0x1f +#define RGS_AUDRCTUNELREAD_MASK_SFT (0x1f << 0) +#define RGS_AUDRCTUNERREAD_SFT 8 +#define RGS_AUDRCTUNERREAD_MASK 0x1f +#define RGS_AUDRCTUNERREAD_MASK_SFT (0x1f << 8) + +/* AUDENC_ANA_CON11 */ +#define RG_AUDSPAREVA30_SFT 0 +#define RG_AUDSPAREVA30_MASK 0xff +#define RG_AUDSPAREVA30_MASK_SFT (0xff << 0) +#define RG_AUDSPAREVA18_SFT 8 +#define RG_AUDSPAREVA18_MASK 0xff +#define RG_AUDSPAREVA18_MASK_SFT (0xff << 8) + +/* AUDENC_ANA_CON12 */ +#define RG_AUDPGA_DECAP_SFT 0 +#define RG_AUDPGA_DECAP_MASK 0x1 +#define RG_AUDPGA_DECAP_MASK_SFT (0x1 << 0) +#define RG_AUDPGA_CAPRA_SFT 1 +#define RG_AUDPGA_CAPRA_MASK 0x1 +#define RG_AUDPGA_CAPRA_MASK_SFT (0x1 << 1) +#define RG_AUDPGA_ACCCMP_SFT 2 +#define RG_AUDPGA_ACCCMP_MASK 0x1 +#define RG_AUDPGA_ACCCMP_MASK_SFT (0x1 << 2) +#define RG_AUDENC_SPARE2_SFT 3 +#define RG_AUDENC_SPARE2_MASK 0x1fff +#define RG_AUDENC_SPARE2_MASK_SFT (0x1fff << 3) + +/* AUDENC_ANA_CON13 */ +#define RG_AUDDIGMICEN_SFT 0 +#define RG_AUDDIGMICEN_MASK 0x1 +#define RG_AUDDIGMICEN_MASK_SFT (0x1 << 0) +#define RG_AUDDIGMICBIAS_SFT 1 +#define RG_AUDDIGMICBIAS_MASK 0x3 +#define RG_AUDDIGMICBIAS_MASK_SFT (0x3 << 1) +#define RG_DMICHPCLKEN_SFT 3 +#define RG_DMICHPCLKEN_MASK 0x1 +#define RG_DMICHPCLKEN_MASK_SFT (0x1 << 3) +#define RG_AUDDIGMICPDUTY_SFT 4 +#define RG_AUDDIGMICPDUTY_MASK 0x3 +#define RG_AUDDIGMICPDUTY_MASK_SFT (0x3 << 4) +#define RG_AUDDIGMICNDUTY_SFT 6 +#define RG_AUDDIGMICNDUTY_MASK 0x3 +#define RG_AUDDIGMICNDUTY_MASK_SFT (0x3 << 6) +#define RG_DMICMONEN_SFT 8 +#define RG_DMICMONEN_MASK 0x1 +#define RG_DMICMONEN_MASK_SFT (0x1 << 8) +#define RG_DMICMONSEL_SFT 9 +#define RG_DMICMONSEL_MASK 0x7 +#define RG_DMICMONSEL_MASK_SFT (0x7 << 9) + +/* AUDENC_ANA_CON14 */ +#define RG_AUDDIGMIC1EN_SFT 0 +#define RG_AUDDIGMIC1EN_MASK 0x1 +#define RG_AUDDIGMIC1EN_MASK_SFT (0x1 << 0) +#define RG_AUDDIGMICBIAS1_SFT 1 +#define RG_AUDDIGMICBIAS1_MASK 0x3 +#define RG_AUDDIGMICBIAS1_MASK_SFT (0x3 << 1) +#define RG_DMIC1HPCLKEN_SFT 3 +#define RG_DMIC1HPCLKEN_MASK 0x1 +#define RG_DMIC1HPCLKEN_MASK_SFT (0x1 << 3) +#define RG_AUDDIGMIC1PDUTY_SFT 4 +#define RG_AUDDIGMIC1PDUTY_MASK 0x3 +#define RG_AUDDIGMIC1PDUTY_MASK_SFT (0x3 << 4) +#define RG_AUDDIGMIC1NDUTY_SFT 6 +#define RG_AUDDIGMIC1NDUTY_MASK 0x3 +#define RG_AUDDIGMIC1NDUTY_MASK_SFT (0x3 << 6) +#define RG_DMIC1MONEN_SFT 8 +#define RG_DMIC1MONEN_MASK 0x1 +#define RG_DMIC1MONEN_MASK_SFT (0x1 << 8) +#define RG_DMIC1MONSEL_SFT 9 +#define RG_DMIC1MONSEL_MASK 0x7 +#define RG_DMIC1MONSEL_MASK_SFT (0x7 << 9) +#define RG_AUDSPAREVMIC_SFT 12 +#define RG_AUDSPAREVMIC_MASK 0xf +#define RG_AUDSPAREVMIC_MASK_SFT (0xf << 12) + +/* AUDENC_ANA_CON15 */ +#define RG_AUDPWDBMICBIAS0_SFT 0 +#define RG_AUDPWDBMICBIAS0_MASK 0x1 +#define RG_AUDPWDBMICBIAS0_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS0BYPASSEN_SFT 1 +#define RG_AUDMICBIAS0BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS0BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS0LOWPEN_SFT 2 +#define RG_AUDMICBIAS0LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS0LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDPWDBMICBIAS3_SFT 3 +#define RG_AUDPWDBMICBIAS3_MASK 0x1 +#define RG_AUDPWDBMICBIAS3_MASK_SFT (0x1 << 3) +#define RG_AUDMICBIAS0VREF_SFT 4 +#define RG_AUDMICBIAS0VREF_MASK 0x7 +#define RG_AUDMICBIAS0VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS0DCSW0P1EN_SFT 8 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS0DCSW0P2EN_SFT 9 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK_SFT (0x1 << 9) +#define RG_AUDMICBIAS0DCSW0NEN_SFT 10 +#define RG_AUDMICBIAS0DCSW0NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0NEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIAS0DCSW2P1EN_SFT 12 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK_SFT (0x1 << 12) +#define RG_AUDMICBIAS0DCSW2P2EN_SFT 13 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK_SFT (0x1 << 13) +#define RG_AUDMICBIAS0DCSW2NEN_SFT 14 +#define RG_AUDMICBIAS0DCSW2NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2NEN_MASK_SFT (0x1 << 14) + +/* AUDENC_ANA_CON16 */ +#define RG_AUDPWDBMICBIAS1_SFT 0 +#define RG_AUDPWDBMICBIAS1_MASK 0x1 +#define RG_AUDPWDBMICBIAS1_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS1BYPASSEN_SFT 1 +#define RG_AUDMICBIAS1BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS1BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS1LOWPEN_SFT 2 +#define RG_AUDMICBIAS1LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS1LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS1VREF_SFT 4 +#define RG_AUDMICBIAS1VREF_MASK 0x7 +#define RG_AUDMICBIAS1VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS1DCSW1PEN_SFT 8 +#define RG_AUDMICBIAS1DCSW1PEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1PEN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS1DCSW1NEN_SFT 9 +#define RG_AUDMICBIAS1DCSW1NEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1NEN_MASK_SFT (0x1 << 9) +#define RG_BANDGAPGEN_SFT 10 +#define RG_BANDGAPGEN_MASK 0x1 +#define RG_BANDGAPGEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIAS1HVEN_SFT 12 +#define RG_AUDMICBIAS1HVEN_MASK 0x1 +#define RG_AUDMICBIAS1HVEN_MASK_SFT (0x1 << 12) +#define RG_AUDMICBIAS1HVVREF_SFT 13 +#define RG_AUDMICBIAS1HVVREF_MASK 0x1 +#define RG_AUDMICBIAS1HVVREF_MASK_SFT (0x1 << 13) + +/* AUDENC_ANA_CON17 */ +#define RG_AUDPWDBMICBIAS2_SFT 0 +#define RG_AUDPWDBMICBIAS2_MASK 0x1 +#define RG_AUDPWDBMICBIAS2_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS2BYPASSEN_SFT 1 +#define RG_AUDMICBIAS2BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS2BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS2LOWPEN_SFT 2 +#define RG_AUDMICBIAS2LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS2LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS2VREF_SFT 4 +#define RG_AUDMICBIAS2VREF_MASK 0x7 +#define RG_AUDMICBIAS2VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS2DCSW3P1EN_SFT 8 +#define RG_AUDMICBIAS2DCSW3P1EN_MASK 0x1 +#define RG_AUDMICBIAS2DCSW3P1EN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS2DCSW3P2EN_SFT 9 +#define RG_AUDMICBIAS2DCSW3P2EN_MASK 0x1 +#define RG_AUDMICBIAS2DCSW3P2EN_MASK_SFT (0x1 << 9) +#define RG_AUDMICBIAS2DCSW3NEN_SFT 10 +#define RG_AUDMICBIAS2DCSW3NEN_MASK 0x1 +#define RG_AUDMICBIAS2DCSW3NEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIASSPARE_SFT 12 +#define RG_AUDMICBIASSPARE_MASK 0xf +#define RG_AUDMICBIASSPARE_MASK_SFT (0xf << 12) + +/* AUDENC_ANA_CON18 */ +#define RG_AUDACCDETMICBIAS0PULLLOW_SFT 0 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK_SFT (0x1 << 0) +#define RG_AUDACCDETMICBIAS1PULLLOW_SFT 1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK_SFT (0x1 << 1) +#define RG_AUDACCDETMICBIAS2PULLLOW_SFT 2 +#define RG_AUDACCDETMICBIAS2PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS2PULLLOW_MASK_SFT (0x1 << 2) +#define RG_AUDACCDETVIN1PULLLOW_SFT 3 +#define RG_AUDACCDETVIN1PULLLOW_MASK 0x1 +#define RG_AUDACCDETVIN1PULLLOW_MASK_SFT (0x1 << 3) +#define RG_AUDACCDETVTHACAL_SFT 4 +#define RG_AUDACCDETVTHACAL_MASK 0x1 +#define RG_AUDACCDETVTHACAL_MASK_SFT (0x1 << 4) +#define RG_AUDACCDETVTHBCAL_SFT 5 +#define RG_AUDACCDETVTHBCAL_MASK 0x1 +#define RG_AUDACCDETVTHBCAL_MASK_SFT (0x1 << 5) +#define RG_AUDACCDETTVDET_SFT 6 +#define RG_AUDACCDETTVDET_MASK 0x1 +#define RG_AUDACCDETTVDET_MASK_SFT (0x1 << 6) +#define RG_ACCDETSEL_SFT 7 +#define RG_ACCDETSEL_MASK 0x1 +#define RG_ACCDETSEL_MASK_SFT (0x1 << 7) +#define RG_SWBUFMODSEL_SFT 8 +#define RG_SWBUFMODSEL_MASK 0x1 +#define RG_SWBUFMODSEL_MASK_SFT (0x1 << 8) +#define RG_SWBUFSWEN_SFT 9 +#define RG_SWBUFSWEN_MASK 0x1 +#define RG_SWBUFSWEN_MASK_SFT (0x1 << 9) +#define RG_EINT0NOHYS_SFT 10 +#define RG_EINT0NOHYS_MASK 0x1 +#define RG_EINT0NOHYS_MASK_SFT (0x1 << 10) +#define RG_EINT0CONFIGACCDET_SFT 11 +#define RG_EINT0CONFIGACCDET_MASK 0x1 +#define RG_EINT0CONFIGACCDET_MASK_SFT (0x1 << 11) +#define RG_EINT0HIRENB_SFT 12 +#define RG_EINT0HIRENB_MASK 0x1 +#define RG_EINT0HIRENB_MASK_SFT (0x1 << 12) +#define RG_ACCDET2AUXRESBYPASS_SFT 13 +#define RG_ACCDET2AUXRESBYPASS_MASK 0x1 +#define RG_ACCDET2AUXRESBYPASS_MASK_SFT (0x1 << 13) +#define RG_ACCDET2AUXSWEN_SFT 14 +#define RG_ACCDET2AUXSWEN_MASK 0x1 +#define RG_ACCDET2AUXSWEN_MASK_SFT (0x1 << 14) +#define RG_AUDACCDETMICBIAS3PULLLOW_SFT 15 +#define RG_AUDACCDETMICBIAS3PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS3PULLLOW_MASK_SFT (0x1 << 15) + +/* AUDENC_ANA_CON19 */ +#define RG_EINT1CONFIGACCDET_SFT 0 +#define RG_EINT1CONFIGACCDET_MASK 0x1 +#define RG_EINT1CONFIGACCDET_MASK_SFT (0x1 << 0) +#define RG_EINT1HIRENB_SFT 1 +#define RG_EINT1HIRENB_MASK 0x1 +#define RG_EINT1HIRENB_MASK_SFT (0x1 << 1) +#define RG_EINT1NOHYS_SFT 2 +#define RG_EINT1NOHYS_MASK 0x1 +#define RG_EINT1NOHYS_MASK_SFT (0x1 << 2) +#define RG_EINTCOMPVTH_SFT 4 +#define RG_EINTCOMPVTH_MASK 0xf +#define RG_EINTCOMPVTH_MASK_SFT (0xf << 4) +#define RG_MTEST_EN_SFT 8 +#define RG_MTEST_EN_MASK 0x1 +#define RG_MTEST_EN_MASK_SFT (0x1 << 8) +#define RG_MTEST_SEL_SFT 9 +#define RG_MTEST_SEL_MASK 0x1 +#define RG_MTEST_SEL_MASK_SFT (0x1 << 9) +#define RG_MTEST_CURRENT_SFT 10 +#define RG_MTEST_CURRENT_MASK 0x1 +#define RG_MTEST_CURRENT_MASK_SFT (0x1 << 10) +#define RG_ANALOGFDEN_SFT 12 +#define RG_ANALOGFDEN_MASK 0x1 +#define RG_ANALOGFDEN_MASK_SFT (0x1 << 12) +#define RG_FDVIN1PPULLLOW_SFT 13 +#define RG_FDVIN1PPULLLOW_MASK 0x1 +#define RG_FDVIN1PPULLLOW_MASK_SFT (0x1 << 13) +#define RG_FDEINT0TYPE_SFT 14 +#define RG_FDEINT0TYPE_MASK 0x1 +#define RG_FDEINT0TYPE_MASK_SFT (0x1 << 14) +#define RG_FDEINT1TYPE_SFT 15 +#define RG_FDEINT1TYPE_MASK 0x1 +#define RG_FDEINT1TYPE_MASK_SFT (0x1 << 15) + +/* AUDENC_ANA_CON20 */ +#define RG_EINT0CMPEN_SFT 0 +#define RG_EINT0CMPEN_MASK 0x1 +#define RG_EINT0CMPEN_MASK_SFT (0x1 << 0) +#define RG_EINT0CMPMEN_SFT 1 +#define RG_EINT0CMPMEN_MASK 0x1 +#define RG_EINT0CMPMEN_MASK_SFT (0x1 << 1) +#define RG_EINT0EN_SFT 2 +#define RG_EINT0EN_MASK 0x1 +#define RG_EINT0EN_MASK_SFT (0x1 << 2) +#define RG_EINT0CEN_SFT 3 +#define RG_EINT0CEN_MASK 0x1 +#define RG_EINT0CEN_MASK_SFT (0x1 << 3) +#define RG_EINT0INVEN_SFT 4 +#define RG_EINT0INVEN_MASK 0x1 +#define RG_EINT0INVEN_MASK_SFT (0x1 << 4) +#define RG_EINT0CTURBO_SFT 5 +#define RG_EINT0CTURBO_MASK 0x7 +#define RG_EINT0CTURBO_MASK_SFT (0x7 << 5) +#define RG_EINT1CMPEN_SFT 8 +#define RG_EINT1CMPEN_MASK 0x1 +#define RG_EINT1CMPEN_MASK_SFT (0x1 << 8) +#define RG_EINT1CMPMEN_SFT 9 +#define RG_EINT1CMPMEN_MASK 0x1 +#define RG_EINT1CMPMEN_MASK_SFT (0x1 << 9) +#define RG_EINT1EN_SFT 10 +#define RG_EINT1EN_MASK 0x1 +#define RG_EINT1EN_MASK_SFT (0x1 << 10) +#define RG_EINT1CEN_SFT 11 +#define RG_EINT1CEN_MASK 0x1 +#define RG_EINT1CEN_MASK_SFT (0x1 << 11) +#define RG_EINT1INVEN_SFT 12 +#define RG_EINT1INVEN_MASK 0x1 +#define RG_EINT1INVEN_MASK_SFT (0x1 << 12) +#define RG_EINT1CTURBO_SFT 13 +#define RG_EINT1CTURBO_MASK 0x7 +#define RG_EINT1CTURBO_MASK_SFT (0x7 << 13) + +/* AUDENC_ANA_CON21 */ +#define RG_ACCDETSPARE_SFT 0 +#define RG_ACCDETSPARE_MASK 0xffff +#define RG_ACCDETSPARE_MASK_SFT (0xffff << 0) + +/* AUDENC_ANA_CON22 */ +#define RG_AUDENCSPAREVA30_SFT 0 +#define RG_AUDENCSPAREVA30_MASK 0xff +#define RG_AUDENCSPAREVA30_MASK_SFT (0xff << 0) +#define RG_AUDENCSPAREVA18_SFT 8 +#define RG_AUDENCSPAREVA18_MASK 0xff +#define RG_AUDENCSPAREVA18_MASK_SFT (0xff << 8) + +/* AUDENC_ANA_CON23 */ +#define RG_CLKSQ_EN_SFT 0 +#define RG_CLKSQ_EN_MASK 0x1 +#define RG_CLKSQ_EN_MASK_SFT (0x1 << 0) +#define RG_CLKSQ_IN_SEL_TEST_SFT 1 +#define RG_CLKSQ_IN_SEL_TEST_MASK 0x1 +#define RG_CLKSQ_IN_SEL_TEST_MASK_SFT (0x1 << 1) +#define RG_CM_REFGENSEL_SFT 2 +#define RG_CM_REFGENSEL_MASK 0x1 +#define RG_CM_REFGENSEL_MASK_SFT (0x1 << 2) +#define RG_AUDIO_VOW_EN_SFT 3 +#define RG_AUDIO_VOW_EN_MASK 0x1 +#define RG_AUDIO_VOW_EN_MASK_SFT (0x1 << 3) +#define RG_CLKSQ_EN_VOW_SFT 4 +#define RG_CLKSQ_EN_VOW_MASK 0x1 +#define RG_CLKSQ_EN_VOW_MASK_SFT (0x1 << 4) +#define RG_CLKAND_EN_VOW_SFT 5 +#define RG_CLKAND_EN_VOW_MASK 0x1 +#define RG_CLKAND_EN_VOW_MASK_SFT (0x1 << 5) +#define RG_VOWCLK_SEL_EN_VOW_SFT 6 +#define RG_VOWCLK_SEL_EN_VOW_MASK 0x1 +#define RG_VOWCLK_SEL_EN_VOW_MASK_SFT (0x1 << 6) +#define RG_SPARE_VOW_SFT 7 +#define RG_SPARE_VOW_MASK 0x7 +#define RG_SPARE_VOW_MASK_SFT (0x7 << 7) + +/* AUDDEC_ANA_CON0 */ +#define RG_AUDDACLPWRUP_VAUDP32_SFT 0 +#define RG_AUDDACLPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDDACLPWRUP_VAUDP32_MASK_SFT (0x1 << 0) +#define RG_AUDDACRPWRUP_VAUDP32_SFT 1 +#define RG_AUDDACRPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDDACRPWRUP_VAUDP32_MASK_SFT (0x1 << 1) +#define RG_AUD_DAC_PWR_UP_VA32_SFT 2 +#define RG_AUD_DAC_PWR_UP_VA32_MASK 0x1 +#define RG_AUD_DAC_PWR_UP_VA32_MASK_SFT (0x1 << 2) +#define RG_AUD_DAC_PWL_UP_VA32_SFT 3 +#define RG_AUD_DAC_PWL_UP_VA32_MASK 0x1 +#define RG_AUD_DAC_PWL_UP_VA32_MASK_SFT (0x1 << 3) +#define RG_AUDHPLPWRUP_VAUDP32_SFT 4 +#define RG_AUDHPLPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPLPWRUP_VAUDP32_MASK_SFT (0x1 << 4) +#define RG_AUDHPRPWRUP_VAUDP32_SFT 5 +#define RG_AUDHPRPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPRPWRUP_VAUDP32_MASK_SFT (0x1 << 5) +#define RG_AUDHPLPWRUP_IBIAS_VAUDP32_SFT 6 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP32_MASK 0x1 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP32_MASK_SFT (0x1 << 6) +#define RG_AUDHPRPWRUP_IBIAS_VAUDP32_SFT 7 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP32_MASK 0x1 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP32_MASK_SFT (0x1 << 7) +#define RG_AUDHPLMUXINPUTSEL_VAUDP32_SFT 8 +#define RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK 0x3 +#define RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK_SFT (0x3 << 8) +#define RG_AUDHPRMUXINPUTSEL_VAUDP32_SFT 10 +#define RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK 0x3 +#define RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK_SFT (0x3 << 10) +#define RG_AUDHPLSCDISABLE_VAUDP32_SFT 12 +#define RG_AUDHPLSCDISABLE_VAUDP32_MASK 0x1 +#define RG_AUDHPLSCDISABLE_VAUDP32_MASK_SFT (0x1 << 12) +#define RG_AUDHPRSCDISABLE_VAUDP32_SFT 13 +#define RG_AUDHPRSCDISABLE_VAUDP32_MASK 0x1 +#define RG_AUDHPRSCDISABLE_VAUDP32_MASK_SFT (0x1 << 13) +#define RG_AUDHPLBSCCURRENT_VAUDP32_SFT 14 +#define RG_AUDHPLBSCCURRENT_VAUDP32_MASK 0x1 +#define RG_AUDHPLBSCCURRENT_VAUDP32_MASK_SFT (0x1 << 14) +#define RG_AUDHPRBSCCURRENT_VAUDP32_SFT 15 +#define RG_AUDHPRBSCCURRENT_VAUDP32_MASK 0x1 +#define RG_AUDHPRBSCCURRENT_VAUDP32_MASK_SFT (0x1 << 15) + +/* AUDDEC_ANA_CON1 */ +#define RG_AUDHPLOUTPWRUP_VAUDP32_SFT 0 +#define RG_AUDHPLOUTPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPLOUTPWRUP_VAUDP32_MASK_SFT (0x1 << 0) +#define RG_AUDHPROUTPWRUP_VAUDP32_SFT 1 +#define RG_AUDHPROUTPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPROUTPWRUP_VAUDP32_MASK_SFT (0x1 << 1) +#define RG_AUDHPLOUTAUXPWRUP_VAUDP32_SFT 2 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP32_MASK_SFT (0x1 << 2) +#define RG_AUDHPROUTAUXPWRUP_VAUDP32_SFT 3 +#define RG_AUDHPROUTAUXPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHPROUTAUXPWRUP_VAUDP32_MASK_SFT (0x1 << 3) +#define RG_HPLAUXFBRSW_EN_VAUDP32_SFT 4 +#define RG_HPLAUXFBRSW_EN_VAUDP32_MASK 0x1 +#define RG_HPLAUXFBRSW_EN_VAUDP32_MASK_SFT (0x1 << 4) +#define RG_HPRAUXFBRSW_EN_VAUDP32_SFT 5 +#define RG_HPRAUXFBRSW_EN_VAUDP32_MASK 0x1 +#define RG_HPRAUXFBRSW_EN_VAUDP32_MASK_SFT (0x1 << 5) +#define RG_HPLSHORT2HPLAUX_EN_VAUDP32_SFT 6 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP32_MASK 0x1 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP32_MASK_SFT (0x1 << 6) +#define RG_HPRSHORT2HPRAUX_EN_VAUDP32_SFT 7 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP32_MASK 0x1 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP32_MASK_SFT (0x1 << 7) +#define RG_HPLOUTSTGCTRL_VAUDP32_SFT 8 +#define RG_HPLOUTSTGCTRL_VAUDP32_MASK 0x7 +#define RG_HPLOUTSTGCTRL_VAUDP32_MASK_SFT (0x7 << 8) +#define RG_HPROUTSTGCTRL_VAUDP32_SFT 12 +#define RG_HPROUTSTGCTRL_VAUDP32_MASK 0x7 +#define RG_HPROUTSTGCTRL_VAUDP32_MASK_SFT (0x7 << 12) + +/* AUDDEC_ANA_CON2 */ +#define RG_HPLOUTPUTSTBENH_VAUDP32_SFT 0 +#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK 0x7 +#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 0) +#define RG_HPROUTPUTSTBENH_VAUDP32_SFT 4 +#define RG_HPROUTPUTSTBENH_VAUDP32_MASK 0x7 +#define RG_HPROUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 4) +#define RG_AUDHPSTARTUP_VAUDP32_SFT 7 +#define RG_AUDHPSTARTUP_VAUDP32_MASK 0x1 +#define RG_AUDHPSTARTUP_VAUDP32_MASK_SFT (0x1 << 7) +#define RG_AUDREFN_DERES_EN_VAUDP32_SFT 8 +#define RG_AUDREFN_DERES_EN_VAUDP32_MASK 0x1 +#define RG_AUDREFN_DERES_EN_VAUDP32_MASK_SFT (0x1 << 8) +#define RG_HPINPUTSTBENH_VAUDP32_SFT 9 +#define RG_HPINPUTSTBENH_VAUDP32_MASK 0x1 +#define RG_HPINPUTSTBENH_VAUDP32_MASK_SFT (0x1 << 9) +#define RG_HPINPUTRESET0_VAUDP32_SFT 10 +#define RG_HPINPUTRESET0_VAUDP32_MASK 0x1 +#define RG_HPINPUTRESET0_VAUDP32_MASK_SFT (0x1 << 10) +#define RG_HPOUTPUTRESET0_VAUDP32_SFT 11 +#define RG_HPOUTPUTRESET0_VAUDP32_MASK 0x1 +#define RG_HPOUTPUTRESET0_VAUDP32_MASK_SFT (0x1 << 11) +#define RG_HPPSHORT2VCM_VAUDP32_SFT 12 +#define RG_HPPSHORT2VCM_VAUDP32_MASK 0x7 +#define RG_HPPSHORT2VCM_VAUDP32_MASK_SFT (0x7 << 12) +#define RG_AUDHPTRIM_EN_VAUDP32_SFT 15 +#define RG_AUDHPTRIM_EN_VAUDP32_MASK 0x1 +#define RG_AUDHPTRIM_EN_VAUDP32_MASK_SFT (0x1 << 15) + +/* AUDDEC_ANA_CON3 */ +#define RG_AUDHPLTRIM_VAUDP32_SFT 0 +#define RG_AUDHPLTRIM_VAUDP32_MASK 0x1f +#define RG_AUDHPLTRIM_VAUDP32_MASK_SFT (0x1f << 0) +#define RG_AUDHPLFINETRIM_VAUDP32_SFT 5 +#define RG_AUDHPLFINETRIM_VAUDP32_MASK 0x7 +#define RG_AUDHPLFINETRIM_VAUDP32_MASK_SFT (0x7 << 5) +#define RG_AUDHPRTRIM_VAUDP32_SFT 8 +#define RG_AUDHPRTRIM_VAUDP32_MASK 0x1f +#define RG_AUDHPRTRIM_VAUDP32_MASK_SFT (0x1f << 8) +#define RG_AUDHPRFINETRIM_VAUDP32_SFT 13 +#define RG_AUDHPRFINETRIM_VAUDP32_MASK 0x7 +#define RG_AUDHPRFINETRIM_VAUDP32_MASK_SFT (0x7 << 13) + +/* AUDDEC_ANA_CON4 */ +#define RG_AUDHPDIFFINPBIASADJ_VAUDP32_SFT 0 +#define RG_AUDHPDIFFINPBIASADJ_VAUDP32_MASK 0x7 +#define RG_AUDHPDIFFINPBIASADJ_VAUDP32_MASK_SFT (0x7 << 0) +#define RG_AUDHPLFCOMPRESSEL_VAUDP32_SFT 4 +#define RG_AUDHPLFCOMPRESSEL_VAUDP32_MASK 0x7 +#define RG_AUDHPLFCOMPRESSEL_VAUDP32_MASK_SFT (0x7 << 4) +#define RG_AUDHPHFCOMPRESSEL_VAUDP32_SFT 8 +#define RG_AUDHPHFCOMPRESSEL_VAUDP32_MASK 0x7 +#define RG_AUDHPHFCOMPRESSEL_VAUDP32_MASK_SFT (0x7 << 8) +#define RG_AUDHPHFCOMPBUFGAINSEL_VAUDP32_SFT 12 +#define RG_AUDHPHFCOMPBUFGAINSEL_VAUDP32_MASK 0x3 +#define RG_AUDHPHFCOMPBUFGAINSEL_VAUDP32_MASK_SFT (0x3 << 12) +#define RG_AUDHPCOMP_EN_VAUDP32_SFT 15 +#define RG_AUDHPCOMP_EN_VAUDP32_MASK 0x1 +#define RG_AUDHPCOMP_EN_VAUDP32_MASK_SFT (0x1 << 15) + +/* AUDDEC_ANA_CON5 */ +#define RG_AUDHPDECMGAINADJ_VAUDP32_SFT 0 +#define RG_AUDHPDECMGAINADJ_VAUDP32_MASK 0x7 +#define RG_AUDHPDECMGAINADJ_VAUDP32_MASK_SFT (0x7 << 0) +#define RG_AUDHPDEDMGAINADJ_VAUDP32_SFT 4 +#define RG_AUDHPDEDMGAINADJ_VAUDP32_MASK 0x7 +#define RG_AUDHPDEDMGAINADJ_VAUDP32_MASK_SFT (0x7 << 4) + +/* AUDDEC_ANA_CON6 */ +#define RG_AUDHSPWRUP_VAUDP32_SFT 0 +#define RG_AUDHSPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDHSPWRUP_VAUDP32_MASK_SFT (0x1 << 0) +#define RG_AUDHSPWRUP_IBIAS_VAUDP32_SFT 1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP32_MASK 0x1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP32_MASK_SFT (0x1 << 1) +#define RG_AUDHSMUXINPUTSEL_VAUDP32_SFT 2 +#define RG_AUDHSMUXINPUTSEL_VAUDP32_MASK 0x3 +#define RG_AUDHSMUXINPUTSEL_VAUDP32_MASK_SFT (0x3 << 2) +#define RG_AUDHSSCDISABLE_VAUDP32_SFT 4 +#define RG_AUDHSSCDISABLE_VAUDP32_MASK 0x1 +#define RG_AUDHSSCDISABLE_VAUDP32_MASK_SFT (0x1 << 4) +#define RG_AUDHSBSCCURRENT_VAUDP32_SFT 5 +#define RG_AUDHSBSCCURRENT_VAUDP32_MASK 0x1 +#define RG_AUDHSBSCCURRENT_VAUDP32_MASK_SFT (0x1 << 5) +#define RG_AUDHSSTARTUP_VAUDP32_SFT 6 +#define RG_AUDHSSTARTUP_VAUDP32_MASK 0x1 +#define RG_AUDHSSTARTUP_VAUDP32_MASK_SFT (0x1 << 6) +#define RG_HSOUTPUTSTBENH_VAUDP32_SFT 7 +#define RG_HSOUTPUTSTBENH_VAUDP32_MASK 0x1 +#define RG_HSOUTPUTSTBENH_VAUDP32_MASK_SFT (0x1 << 7) +#define RG_HSINPUTSTBENH_VAUDP32_SFT 8 +#define RG_HSINPUTSTBENH_VAUDP32_MASK 0x1 +#define RG_HSINPUTSTBENH_VAUDP32_MASK_SFT (0x1 << 8) +#define RG_HSINPUTRESET0_VAUDP32_SFT 9 +#define RG_HSINPUTRESET0_VAUDP32_MASK 0x1 +#define RG_HSINPUTRESET0_VAUDP32_MASK_SFT (0x1 << 9) +#define RG_HSOUTPUTRESET0_VAUDP32_SFT 10 +#define RG_HSOUTPUTRESET0_VAUDP32_MASK 0x1 +#define RG_HSOUTPUTRESET0_VAUDP32_MASK_SFT (0x1 << 10) +#define RG_HSOUT_SHORTVCM_VAUDP32_SFT 11 +#define RG_HSOUT_SHORTVCM_VAUDP32_MASK 0x1 +#define RG_HSOUT_SHORTVCM_VAUDP32_MASK_SFT (0x1 << 11) + +/* AUDDEC_ANA_CON7 */ +#define RG_AUDLOLPWRUP_VAUDP32_SFT 0 +#define RG_AUDLOLPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDLOLPWRUP_VAUDP32_MASK_SFT (0x1 << 0) +#define RG_AUDLOLPWRUP_IBIAS_VAUDP32_SFT 1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP32_MASK 0x1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP32_MASK_SFT (0x1 << 1) +#define RG_AUDLOLMUXINPUTSEL_VAUDP32_SFT 2 +#define RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK 0x3 +#define RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK_SFT (0x3 << 2) +#define RG_AUDLOLSCDISABLE_VAUDP32_SFT 4 +#define RG_AUDLOLSCDISABLE_VAUDP32_MASK 0x1 +#define RG_AUDLOLSCDISABLE_VAUDP32_MASK_SFT (0x1 << 4) +#define RG_AUDLOLBSCCURRENT_VAUDP32_SFT 5 +#define RG_AUDLOLBSCCURRENT_VAUDP32_MASK 0x1 +#define RG_AUDLOLBSCCURRENT_VAUDP32_MASK_SFT (0x1 << 5) +#define RG_AUDLOSTARTUP_VAUDP32_SFT 6 +#define RG_AUDLOSTARTUP_VAUDP32_MASK 0x1 +#define RG_AUDLOSTARTUP_VAUDP32_MASK_SFT (0x1 << 6) +#define RG_LOINPUTSTBENH_VAUDP32_SFT 7 +#define RG_LOINPUTSTBENH_VAUDP32_MASK 0x1 +#define RG_LOINPUTSTBENH_VAUDP32_MASK_SFT (0x1 << 7) +#define RG_LOOUTPUTSTBENH_VAUDP32_SFT 8 +#define RG_LOOUTPUTSTBENH_VAUDP32_MASK 0x1 +#define RG_LOOUTPUTSTBENH_VAUDP32_MASK_SFT (0x1 << 8) +#define RG_LOINPUTRESET0_VAUDP32_SFT 9 +#define RG_LOINPUTRESET0_VAUDP32_MASK 0x1 +#define RG_LOINPUTRESET0_VAUDP32_MASK_SFT (0x1 << 9) +#define RG_LOOUTPUTRESET0_VAUDP32_SFT 10 +#define RG_LOOUTPUTRESET0_VAUDP32_MASK 0x1 +#define RG_LOOUTPUTRESET0_VAUDP32_MASK_SFT (0x1 << 10) +#define RG_LOOUT_SHORTVCM_VAUDP32_SFT 11 +#define RG_LOOUT_SHORTVCM_VAUDP32_MASK 0x1 +#define RG_LOOUT_SHORTVCM_VAUDP32_MASK_SFT (0x1 << 11) +#define RG_AUDDACTPWRUP_VAUDP32_SFT 12 +#define RG_AUDDACTPWRUP_VAUDP32_MASK 0x1 +#define RG_AUDDACTPWRUP_VAUDP32_MASK_SFT (0x1 << 12) +#define RG_AUD_DAC_PWT_UP_VA32_SFT 13 +#define RG_AUD_DAC_PWT_UP_VA32_MASK 0x1 +#define RG_AUD_DAC_PWT_UP_VA32_MASK_SFT (0x1 << 13) + +/* AUDDEC_ANA_CON8 */ +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP32_SFT 0 +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP32_MASK 0xf +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP32_MASK_SFT (0xf << 0) +#define RG_AUDTRIMBUF_GAINSEL_VAUDP32_SFT 4 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP32_MASK 0x3 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP32_MASK_SFT (0x3 << 4) +#define RG_AUDTRIMBUF_EN_VAUDP32_SFT 6 +#define RG_AUDTRIMBUF_EN_VAUDP32_MASK 0x1 +#define RG_AUDTRIMBUF_EN_VAUDP32_MASK_SFT (0x1 << 6) +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP32_SFT 8 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP32_MASK 0x3 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP32_MASK_SFT (0x3 << 8) +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP32_SFT 10 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP32_MASK 0x3 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP32_MASK_SFT (0x3 << 10) +#define RG_AUDHPSPKDET_EN_VAUDP32_SFT 12 +#define RG_AUDHPSPKDET_EN_VAUDP32_MASK 0x1 +#define RG_AUDHPSPKDET_EN_VAUDP32_MASK_SFT (0x1 << 12) + +/* AUDDEC_ANA_CON9 */ +#define RG_ABIDEC_RSVD0_VA32_SFT 0 +#define RG_ABIDEC_RSVD0_VA32_MASK 0xff +#define RG_ABIDEC_RSVD0_VA32_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD0_VAUDP32_SFT 8 +#define RG_ABIDEC_RSVD0_VAUDP32_MASK 0xff +#define RG_ABIDEC_RSVD0_VAUDP32_MASK_SFT (0xff << 8) + +/* AUDDEC_ANA_CON10 */ +#define RG_ABIDEC_RSVD1_VAUDP32_SFT 0 +#define RG_ABIDEC_RSVD1_VAUDP32_MASK 0xff +#define RG_ABIDEC_RSVD1_VAUDP32_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD2_VAUDP32_SFT 8 +#define RG_ABIDEC_RSVD2_VAUDP32_MASK 0xff +#define RG_ABIDEC_RSVD2_VAUDP32_MASK_SFT (0xff << 8) + +/* AUDDEC_ANA_CON11 */ +#define RG_AUDZCDMUXSEL_VAUDP32_SFT 0 +#define RG_AUDZCDMUXSEL_VAUDP32_MASK 0x7 +#define RG_AUDZCDMUXSEL_VAUDP32_MASK_SFT (0x7 << 0) +#define RG_AUDZCDCLKSEL_VAUDP32_SFT 3 +#define RG_AUDZCDCLKSEL_VAUDP32_MASK 0x1 +#define RG_AUDZCDCLKSEL_VAUDP32_MASK_SFT (0x1 << 3) +#define RG_AUDBIASADJ_0_VAUDP32_SFT 7 +#define RG_AUDBIASADJ_0_VAUDP32_MASK 0x1ff +#define RG_AUDBIASADJ_0_VAUDP32_MASK_SFT (0x1ff << 7) + +/* AUDDEC_ANA_CON12 */ +#define RG_AUDBIASADJ_1_VAUDP32_SFT 0 +#define RG_AUDBIASADJ_1_VAUDP32_MASK 0xff +#define RG_AUDBIASADJ_1_VAUDP32_MASK_SFT (0xff << 0) +#define RG_AUDIBIASPWRDN_VAUDP32_SFT 8 +#define RG_AUDIBIASPWRDN_VAUDP32_MASK 0x1 +#define RG_AUDIBIASPWRDN_VAUDP32_MASK_SFT (0x1 << 8) + +/* AUDDEC_ANA_CON13 */ +#define RG_RSTB_DECODER_VA32_SFT 0 +#define RG_RSTB_DECODER_VA32_MASK 0x1 +#define RG_RSTB_DECODER_VA32_MASK_SFT (0x1 << 0) +#define RG_SEL_DECODER_96K_VA32_SFT 1 +#define RG_SEL_DECODER_96K_VA32_MASK 0x1 +#define RG_SEL_DECODER_96K_VA32_MASK_SFT (0x1 << 1) +#define RG_SEL_DELAY_VCORE_SFT 2 +#define RG_SEL_DELAY_VCORE_MASK 0x1 +#define RG_SEL_DELAY_VCORE_MASK_SFT (0x1 << 2) +#define RG_AUDGLB_PWRDN_VA32_SFT 4 +#define RG_AUDGLB_PWRDN_VA32_MASK 0x1 +#define RG_AUDGLB_PWRDN_VA32_MASK_SFT (0x1 << 4) +#define RG_AUDGLB_LP_VOW_EN_VA32_SFT 5 +#define RG_AUDGLB_LP_VOW_EN_VA32_MASK 0x1 +#define RG_AUDGLB_LP_VOW_EN_VA32_MASK_SFT (0x1 << 5) +#define RG_AUDGLB_LP2_VOW_EN_VA32_SFT 6 +#define RG_AUDGLB_LP2_VOW_EN_VA32_MASK 0x1 +#define RG_AUDGLB_LP2_VOW_EN_VA32_MASK_SFT (0x1 << 6) + +/* AUDDEC_ANA_CON14 */ +#define RG_LCLDO_DEC_EN_VA32_SFT 0 +#define RG_LCLDO_DEC_EN_VA32_MASK 0x1 +#define RG_LCLDO_DEC_EN_VA32_MASK_SFT (0x1 << 0) +#define RG_LCLDO_DEC_PDDIS_EN_VA18_SFT 1 +#define RG_LCLDO_DEC_PDDIS_EN_VA18_MASK 0x1 +#define RG_LCLDO_DEC_PDDIS_EN_VA18_MASK_SFT (0x1 << 1) +#define RG_LCLDO_DEC_REMOTE_SENSE_VA18_SFT 2 +#define RG_LCLDO_DEC_REMOTE_SENSE_VA18_MASK 0x1 +#define RG_LCLDO_DEC_REMOTE_SENSE_VA18_MASK_SFT (0x1 << 2) +#define RG_NVREG_EN_VAUDP32_SFT 4 +#define RG_NVREG_EN_VAUDP32_MASK 0x1 +#define RG_NVREG_EN_VAUDP32_MASK_SFT (0x1 << 4) +#define RG_NVREG_PULL0V_VAUDP32_SFT 5 +#define RG_NVREG_PULL0V_VAUDP32_MASK 0x1 +#define RG_NVREG_PULL0V_VAUDP32_MASK_SFT (0x1 << 5) +#define RG_AUDPMU_RSVD_VA18_SFT 8 +#define RG_AUDPMU_RSVD_VA18_MASK 0xff +#define RG_AUDPMU_RSVD_VA18_MASK_SFT (0xff << 8) + +/* MT6359_ZCD_CON0 */ +#define RG_AUDZCDENABLE_SFT 0 +#define RG_AUDZCDENABLE_MASK 0x1 +#define RG_AUDZCDENABLE_MASK_SFT (0x1 << 0) +#define RG_AUDZCDGAINSTEPTIME_SFT 1 +#define RG_AUDZCDGAINSTEPTIME_MASK 0x7 +#define RG_AUDZCDGAINSTEPTIME_MASK_SFT (0x7 << 1) +#define RG_AUDZCDGAINSTEPSIZE_SFT 4 +#define RG_AUDZCDGAINSTEPSIZE_MASK 0x3 +#define RG_AUDZCDGAINSTEPSIZE_MASK_SFT (0x3 << 4) +#define RG_AUDZCDTIMEOUTMODESEL_SFT 6 +#define RG_AUDZCDTIMEOUTMODESEL_MASK 0x1 +#define RG_AUDZCDTIMEOUTMODESEL_MASK_SFT (0x1 << 6) + +/* MT6359_ZCD_CON1 */ +#define RG_AUDLOLGAIN_SFT 0 +#define RG_AUDLOLGAIN_MASK 0x1f +#define RG_AUDLOLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDLORGAIN_SFT 7 +#define RG_AUDLORGAIN_MASK 0x1f +#define RG_AUDLORGAIN_MASK_SFT (0x1f << 7) + +/* MT6359_ZCD_CON2 */ +#define RG_AUDHPLGAIN_SFT 0 +#define RG_AUDHPLGAIN_MASK 0x1f +#define RG_AUDHPLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDHPRGAIN_SFT 7 +#define RG_AUDHPRGAIN_MASK 0x1f +#define RG_AUDHPRGAIN_MASK_SFT (0x1f << 7) + +/* MT6359_ZCD_CON3 */ +#define RG_AUDHSGAIN_SFT 0 +#define RG_AUDHSGAIN_MASK 0x1f +#define RG_AUDHSGAIN_MASK_SFT (0x1f << 0) + +/* MT6359_ZCD_CON4 */ +#define RG_AUDIVLGAIN_SFT 0 +#define RG_AUDIVLGAIN_MASK 0x7 +#define RG_AUDIVLGAIN_MASK_SFT (0x7 << 0) +#define RG_AUDIVRGAIN_SFT 8 +#define RG_AUDIVRGAIN_MASK 0x7 +#define RG_AUDIVRGAIN_MASK_SFT (0x7 << 8) + +/* MT6359_ZCD_CON5 */ +#define RG_AUDINTGAIN1_SFT 0 +#define RG_AUDINTGAIN1_MASK 0x3f +#define RG_AUDINTGAIN1_MASK_SFT (0x3f << 0) +#define RG_AUDINTGAIN2_SFT 8 +#define RG_AUDINTGAIN2_MASK 0x3f +#define RG_AUDINTGAIN2_MASK_SFT (0x3f << 8) + +/* audio register */ +#define MT6359_GPIO_DIR0 0x88 +#define MT6359_GPIO_DIR0_SET 0x8a +#define MT6359_GPIO_DIR0_CLR 0x8c +#define MT6359_GPIO_DIR1 0x8e +#define MT6359_GPIO_DIR1_SET 0x90 +#define MT6359_GPIO_DIR1_CLR 0x92 + +#define MT6359_DCXO_CW11 0x7a6 +#define MT6359_DCXO_CW12 0x7a8 +#define MT6359_LDO_VAUD18_CON0 0x1c98 + +#define MT6359_GPIO_MODE0 0xcc +#define MT6359_GPIO_MODE0_SET 0xce +#define MT6359_GPIO_MODE0_CLR 0xd0 +#define MT6359_GPIO_MODE1 0xd2 +#define MT6359_GPIO_MODE1_SET 0xd4 +#define MT6359_GPIO_MODE1_CLR 0xd6 +#define MT6359_GPIO_MODE2 0xd8 +#define MT6359_GPIO_MODE2_SET 0xda +#define MT6359_GPIO_MODE2_CLR 0xdc +#define MT6359_GPIO_MODE3 0xde +#define MT6359_GPIO_MODE3_SET 0xe0 +#define MT6359_GPIO_MODE3_CLR 0xe2 +#define MT6359_GPIO_MODE4 0xe4 +#define MT6359_GPIO_MODE4_SET 0xe6 +#define MT6359_GPIO_MODE4_CLR 0xe8 + +#define MT6359_AUD_TOP_ID 0x2300 +#define MT6359_AUD_TOP_REV0 0x2302 +#define MT6359_AUD_TOP_DBI 0x2304 +#define MT6359_AUD_TOP_DXI 0x2306 +#define MT6359_AUD_TOP_CKPDN_TPM0 0x2308 +#define MT6359_AUD_TOP_CKPDN_TPM1 0x230a +#define MT6359_AUD_TOP_CKPDN_CON0 0x230c +#define MT6359_AUD_TOP_CKPDN_CON0_SET 0x230e +#define MT6359_AUD_TOP_CKPDN_CON0_CLR 0x2310 +#define MT6359_AUD_TOP_CKSEL_CON0 0x2312 +#define MT6359_AUD_TOP_CKSEL_CON0_SET 0x2314 +#define MT6359_AUD_TOP_CKSEL_CON0_CLR 0x2316 +#define MT6359_AUD_TOP_CKTST_CON0 0x2318 +#define MT6359_AUD_TOP_CLK_HWEN_CON0 0x231a +#define MT6359_AUD_TOP_CLK_HWEN_CON0_SET 0x231c +#define MT6359_AUD_TOP_CLK_HWEN_CON0_CLR 0x231e +#define MT6359_AUD_TOP_RST_CON0 0x2320 +#define MT6359_AUD_TOP_RST_CON0_SET 0x2322 +#define MT6359_AUD_TOP_RST_CON0_CLR 0x2324 +#define MT6359_AUD_TOP_RST_BANK_CON0 0x2326 +#define MT6359_AUD_TOP_INT_CON0 0x2328 +#define MT6359_AUD_TOP_INT_CON0_SET 0x232a +#define MT6359_AUD_TOP_INT_CON0_CLR 0x232c +#define MT6359_AUD_TOP_INT_MASK_CON0 0x232e +#define MT6359_AUD_TOP_INT_MASK_CON0_SET 0x2330 +#define MT6359_AUD_TOP_INT_MASK_CON0_CLR 0x2332 +#define MT6359_AUD_TOP_INT_STATUS0 0x2334 +#define MT6359_AUD_TOP_INT_RAW_STATUS0 0x2336 +#define MT6359_AUD_TOP_INT_MISC_CON0 0x2338 +#define MT6359_AUD_TOP_MON_CON0 0x233a +#define MT6359_AUDIO_DIG_DSN_ID 0x2380 +#define MT6359_AUDIO_DIG_DSN_REV0 0x2382 +#define MT6359_AUDIO_DIG_DSN_DBI 0x2384 +#define MT6359_AUDIO_DIG_DSN_DXI 0x2386 +#define MT6359_AFE_UL_DL_CON0 0x2388 +#define MT6359_AFE_DL_SRC2_CON0_L 0x238a +#define MT6359_AFE_UL_SRC_CON0_H 0x238c +#define MT6359_AFE_UL_SRC_CON0_L 0x238e +#define MT6359_AFE_ADDA6_L_SRC_CON0_H 0x2390 +#define MT6359_AFE_ADDA6_UL_SRC_CON0_L 0x2392 +#define MT6359_AFE_TOP_CON0 0x2394 +#define MT6359_AUDIO_TOP_CON0 0x2396 +#define MT6359_AFE_MON_DEBUG0 0x2398 +#define MT6359_AFUNC_AUD_CON0 0x239a +#define MT6359_AFUNC_AUD_CON1 0x239c +#define MT6359_AFUNC_AUD_CON2 0x239e +#define MT6359_AFUNC_AUD_CON3 0x23a0 +#define MT6359_AFUNC_AUD_CON4 0x23a2 +#define MT6359_AFUNC_AUD_CON5 0x23a4 +#define MT6359_AFUNC_AUD_CON6 0x23a6 +#define MT6359_AFUNC_AUD_CON7 0x23a8 +#define MT6359_AFUNC_AUD_CON8 0x23aa +#define MT6359_AFUNC_AUD_CON9 0x23ac +#define MT6359_AFUNC_AUD_CON10 0x23ae +#define MT6359_AFUNC_AUD_CON11 0x23b0 +#define MT6359_AFUNC_AUD_CON12 0x23b2 +#define MT6359_AFUNC_AUD_MON0 0x23b4 +#define MT6359_AFUNC_AUD_MON1 0x23b6 +#define MT6359_AUDRC_TUNE_MON0 0x23b8 +#define MT6359_AFE_ADDA_MTKAIF_FIFO_CFG0 0x23ba +#define MT6359_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 0x23bc +#define MT6359_AFE_ADDA_MTKAIF_MON0 0x23be +#define MT6359_AFE_ADDA_MTKAIF_MON1 0x23c0 +#define MT6359_AFE_ADDA_MTKAIF_MON2 0x23c2 +#define MT6359_AFE_ADDA6_MTKAIF_MON3 0x23c4 +#define MT6359_AFE_ADDA_MTKAIF_MON4 0x23c6 +#define MT6359_AFE_ADDA_MTKAIF_MON5 0x23c8 +#define MT6359_AFE_ADDA_MTKAIF_CFG0 0x23ca +#define MT6359_AFE_ADDA_MTKAIF_RX_CFG0 0x23cc +#define MT6359_AFE_ADDA_MTKAIF_RX_CFG1 0x23ce +#define MT6359_AFE_ADDA_MTKAIF_RX_CFG2 0x23d0 +#define MT6359_AFE_ADDA_MTKAIF_RX_CFG3 0x23d2 +#define MT6359_AFE_ADDA_MTKAIF_SYNCWORD_CFG0 0x23d4 +#define MT6359_AFE_ADDA_MTKAIF_SYNCWORD_CFG1 0x23d6 +#define MT6359_AFE_SGEN_CFG0 0x23d8 +#define MT6359_AFE_SGEN_CFG1 0x23da +#define MT6359_AFE_ADC_ASYNC_FIFO_CFG 0x23dc +#define MT6359_AFE_ADC_ASYNC_FIFO_CFG1 0x23de +#define MT6359_AFE_DCCLK_CFG0 0x23e0 +#define MT6359_AFE_DCCLK_CFG1 0x23e2 +#define MT6359_AUDIO_DIG_CFG 0x23e4 +#define MT6359_AUDIO_DIG_CFG1 0x23e6 +#define MT6359_AFE_AUD_PAD_TOP 0x23e8 +#define MT6359_AFE_AUD_PAD_TOP_MON 0x23ea +#define MT6359_AFE_AUD_PAD_TOP_MON1 0x23ec +#define MT6359_AFE_AUD_PAD_TOP_MON2 0x23ee +#define MT6359_AFE_DL_NLE_CFG 0x23f0 +#define MT6359_AFE_DL_NLE_MON 0x23f2 +#define MT6359_AFE_CG_EN_MON 0x23f4 +#define MT6359_AFE_MIC_ARRAY_CFG 0x23f6 +#define MT6359_AFE_CHOP_CFG0 0x23f8 +#define MT6359_AFE_MTKAIF_MUX_CFG 0x23fa +#define MT6359_AUDIO_DIG_2ND_DSN_ID 0x2400 +#define MT6359_AUDIO_DIG_2ND_DSN_REV0 0x2402 +#define MT6359_AUDIO_DIG_2ND_DSN_DBI 0x2404 +#define MT6359_AUDIO_DIG_2ND_DSN_DXI 0x2406 +#define MT6359_AFE_PMIC_NEWIF_CFG3 0x2408 +#define MT6359_AUDIO_DIG_3RD_DSN_ID 0x2480 +#define MT6359_AUDIO_DIG_3RD_DSN_REV0 0x2482 +#define MT6359_AUDIO_DIG_3RD_DSN_DBI 0x2484 +#define MT6359_AUDIO_DIG_3RD_DSN_DXI 0x2486 +#define MT6359_AFE_NCP_CFG0 0x24de +#define MT6359_AFE_NCP_CFG1 0x24e0 +#define MT6359_AFE_NCP_CFG2 0x24e2 +#define MT6359_AUDENC_DSN_ID 0x2500 +#define MT6359_AUDENC_DSN_REV0 0x2502 +#define MT6359_AUDENC_DSN_DBI 0x2504 +#define MT6359_AUDENC_DSN_FPI 0x2506 +#define MT6359_AUDENC_ANA_CON0 0x2508 +#define MT6359_AUDENC_ANA_CON1 0x250a +#define MT6359_AUDENC_ANA_CON2 0x250c +#define MT6359_AUDENC_ANA_CON3 0x250e +#define MT6359_AUDENC_ANA_CON4 0x2510 +#define MT6359_AUDENC_ANA_CON5 0x2512 +#define MT6359_AUDENC_ANA_CON6 0x2514 +#define MT6359_AUDENC_ANA_CON7 0x2516 +#define MT6359_AUDENC_ANA_CON8 0x2518 +#define MT6359_AUDENC_ANA_CON9 0x251a +#define MT6359_AUDENC_ANA_CON10 0x251c +#define MT6359_AUDENC_ANA_CON11 0x251e +#define MT6359_AUDENC_ANA_CON12 0x2520 +#define MT6359_AUDENC_ANA_CON13 0x2522 +#define MT6359_AUDENC_ANA_CON14 0x2524 +#define MT6359_AUDENC_ANA_CON15 0x2526 +#define MT6359_AUDENC_ANA_CON16 0x2528 +#define MT6359_AUDENC_ANA_CON17 0x252a +#define MT6359_AUDENC_ANA_CON18 0x252c +#define MT6359_AUDENC_ANA_CON19 0x252e +#define MT6359_AUDENC_ANA_CON20 0x2530 +#define MT6359_AUDENC_ANA_CON21 0x2532 +#define MT6359_AUDENC_ANA_CON22 0x2534 +#define MT6359_AUDENC_ANA_CON23 0x2536 +#define MT6359_AUDDEC_DSN_ID 0x2580 +#define MT6359_AUDDEC_DSN_REV0 0x2582 +#define MT6359_AUDDEC_DSN_DBI 0x2584 +#define MT6359_AUDDEC_DSN_FPI 0x2586 +#define MT6359_AUDDEC_ANA_CON0 0x2588 +#define MT6359_AUDDEC_ANA_CON1 0x258a +#define MT6359_AUDDEC_ANA_CON2 0x258c +#define MT6359_AUDDEC_ANA_CON3 0x258e +#define MT6359_AUDDEC_ANA_CON4 0x2590 +#define MT6359_AUDDEC_ANA_CON5 0x2592 +#define MT6359_AUDDEC_ANA_CON6 0x2594 +#define MT6359_AUDDEC_ANA_CON7 0x2596 +#define MT6359_AUDDEC_ANA_CON8 0x2598 +#define MT6359_AUDDEC_ANA_CON9 0x259a +#define MT6359_AUDDEC_ANA_CON10 0x259c +#define MT6359_AUDDEC_ANA_CON11 0x259e +#define MT6359_AUDDEC_ANA_CON12 0x25a0 +#define MT6359_AUDDEC_ANA_CON13 0x25a2 +#define MT6359_AUDDEC_ANA_CON14 0x25a4 +#define MT6359_AUDZCD_DSN_ID 0x2600 +#define MT6359_AUDZCD_DSN_REV0 0x2602 +#define MT6359_AUDZCD_DSN_DBI 0x2604 +#define MT6359_AUDZCD_DSN_FPI 0x2606 +#define MT6359_ZCD_CON0 0x2608 +#define MT6359_ZCD_CON1 0x260a +#define MT6359_ZCD_CON2 0x260c +#define MT6359_ZCD_CON3 0x260e +#define MT6359_ZCD_CON4 0x2610 +#define MT6359_ZCD_CON5 0x2612 +#define MT6359_ACCDET_DSN_DIG_ID 0x2680 +#define MT6359_ACCDET_DSN_DIG_REV0 0x2682 +#define MT6359_ACCDET_DSN_DBI 0x2684 +#define MT6359_ACCDET_DSN_FPI 0x2686 +#define MT6359_ACCDET_CON0 0x2688 +#define MT6359_ACCDET_CON1 0x268a +#define MT6359_ACCDET_CON2 0x268c +#define MT6359_ACCDET_CON3 0x268e +#define MT6359_ACCDET_CON4 0x2690 +#define MT6359_ACCDET_CON5 0x2692 +#define MT6359_ACCDET_CON6 0x2694 +#define MT6359_ACCDET_CON7 0x2696 +#define MT6359_ACCDET_CON8 0x2698 +#define MT6359_ACCDET_CON9 0x269a +#define MT6359_ACCDET_CON10 0x269c +#define MT6359_ACCDET_CON11 0x269e +#define MT6359_ACCDET_CON12 0x26a0 +#define MT6359_ACCDET_CON13 0x26a2 +#define MT6359_ACCDET_CON14 0x26a4 +#define MT6359_ACCDET_CON15 0x26a6 +#define MT6359_ACCDET_CON16 0x26a8 +#define MT6359_ACCDET_CON17 0x26aa +#define MT6359_ACCDET_CON18 0x26ac +#define MT6359_ACCDET_CON19 0x26ae +#define MT6359_ACCDET_CON20 0x26b0 +#define MT6359_ACCDET_CON21 0x26b2 +#define MT6359_ACCDET_CON22 0x26b4 +#define MT6359_ACCDET_CON23 0x26b6 +#define MT6359_ACCDET_CON24 0x26b8 +#define MT6359_ACCDET_CON25 0x26ba +#define MT6359_ACCDET_CON26 0x26bc +#define MT6359_ACCDET_CON27 0x26be +#define MT6359_ACCDET_CON28 0x26c0 +#define MT6359_ACCDET_CON29 0x26c2 +#define MT6359_ACCDET_CON30 0x26c4 +#define MT6359_ACCDET_CON31 0x26c6 +#define MT6359_ACCDET_CON32 0x26c8 +#define MT6359_ACCDET_CON33 0x26ca +#define MT6359_ACCDET_CON34 0x26cc +#define MT6359_ACCDET_CON35 0x26ce +#define MT6359_ACCDET_CON36 0x26d0 +#define MT6359_ACCDET_CON37 0x26d2 +#define MT6359_ACCDET_CON38 0x26d4 +#define MT6359_ACCDET_CON39 0x26d6 +#define MT6359_ACCDET_CON40 0x26d8 +#define MT6359_MAX_REGISTER MT6359_ZCD_CON5 + +/* dl bias */ +#define DRBIAS_MASK 0x7 +#define DRBIAS_HP_SFT (RG_AUDBIASADJ_0_VAUDP32_SFT + 0) +#define DRBIAS_HP_MASK_SFT (DRBIAS_MASK << DRBIAS_HP_SFT) +#define DRBIAS_HS_SFT (RG_AUDBIASADJ_0_VAUDP32_SFT + 3) +#define DRBIAS_HS_MASK_SFT (DRBIAS_MASK << DRBIAS_HS_SFT) +#define DRBIAS_LO_SFT (RG_AUDBIASADJ_0_VAUDP32_SFT + 6) +#define DRBIAS_LO_MASK_SFT (DRBIAS_MASK << DRBIAS_LO_SFT) +#define IBIAS_MASK 0x3 +#define IBIAS_HP_SFT (RG_AUDBIASADJ_1_VAUDP32_SFT + 0) +#define IBIAS_HP_MASK_SFT (IBIAS_MASK << IBIAS_HP_SFT) +#define IBIAS_HS_SFT (RG_AUDBIASADJ_1_VAUDP32_SFT + 2) +#define IBIAS_HS_MASK_SFT (IBIAS_MASK << IBIAS_HS_SFT) +#define IBIAS_LO_SFT (RG_AUDBIASADJ_1_VAUDP32_SFT + 4) +#define IBIAS_LO_MASK_SFT (IBIAS_MASK << IBIAS_LO_SFT) +#define IBIAS_ZCD_SFT (RG_AUDBIASADJ_1_VAUDP32_SFT + 6) +#define IBIAS_ZCD_MASK_SFT (IBIAS_MASK << IBIAS_ZCD_SFT) + +/* dl gain */ +#define DL_GAIN_N_10DB_REG (DL_GAIN_N_10DB << 7 | DL_GAIN_N_10DB) +#define DL_GAIN_N_22DB_REG (DL_GAIN_N_22DB << 7 | DL_GAIN_N_22DB) +#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) +#define DL_GAIN_REG_MASK 0x0f9f + +/* mic type mux */ +#define MT_SOC_ENUM_EXT_ID(xname, xenum, xhandler_get, xhandler_put, id) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .device = id,\ + .info = snd_soc_info_enum_double, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(xenum) } + +enum { + MT6359_MTKAIF_PROTOCOL_1 = 0, + MT6359_MTKAIF_PROTOCOL_2, + MT6359_MTKAIF_PROTOCOL_2_CLK_P2, +}; + +enum { + MT6359_AIF_1 = 0, /* dl: hp, rcv, hp+lo */ + MT6359_AIF_2, /* dl: lo only */ + MT6359_AIF_NUM, +}; + +enum { + AUDIO_ANALOG_VOLUME_HSOUTL, + AUDIO_ANALOG_VOLUME_HSOUTR, + AUDIO_ANALOG_VOLUME_HPOUTL, + AUDIO_ANALOG_VOLUME_HPOUTR, + AUDIO_ANALOG_VOLUME_LINEOUTL, + AUDIO_ANALOG_VOLUME_LINEOUTR, + AUDIO_ANALOG_VOLUME_MICAMP1, + AUDIO_ANALOG_VOLUME_MICAMP2, + AUDIO_ANALOG_VOLUME_MICAMP3, + AUDIO_ANALOG_VOLUME_TYPE_MAX +}; + +enum { + MUX_MIC_TYPE_0, /* ain0, micbias 0 */ + MUX_MIC_TYPE_1, /* ain1, micbias 1 */ + MUX_MIC_TYPE_2, /* ain2/3, micbias 2 */ + MUX_PGA_L, + MUX_PGA_R, + MUX_PGA_3, + MUX_HP, + MUX_NUM, +}; + +enum { + DEVICE_HP, + DEVICE_LO, + DEVICE_RCV, + DEVICE_MIC1, + DEVICE_MIC2, + DEVICE_NUM +}; + +enum { + HP_GAIN_CTL_ZCD = 0, + HP_GAIN_CTL_NLE, + HP_GAIN_CTL_NUM, +}; + +enum { + HP_MUX_OPEN = 0, + HP_MUX_HPSPK, + HP_MUX_HP, + HP_MUX_TEST_MODE, + HP_MUX_HP_IMPEDANCE, + HP_MUX_MASK = 0x7, +}; + +enum { + RCV_MUX_OPEN = 0, + RCV_MUX_MUTE, + RCV_MUX_VOICE_PLAYBACK, + RCV_MUX_TEST_MODE, + RCV_MUX_MASK = 0x3, +}; + +enum { + LO_MUX_OPEN = 0, + LO_MUX_L_DAC, + LO_MUX_3RD_DAC, + LO_MUX_TEST_MODE, + LO_MUX_MASK = 0x3, +}; + +/* Supply widget subseq */ +enum { + /* common */ + SUPPLY_SEQ_CLK_BUF, + SUPPLY_SEQ_LDO_VAUD18, + SUPPLY_SEQ_AUD_GLB, + SUPPLY_SEQ_HP_PULL_DOWN, + SUPPLY_SEQ_CLKSQ, + SUPPLY_SEQ_ADC_CLKGEN, + SUPPLY_SEQ_TOP_CK, + SUPPLY_SEQ_TOP_CK_LAST, + SUPPLY_SEQ_DCC_CLK, + SUPPLY_SEQ_MIC_BIAS, + SUPPLY_SEQ_DMIC, + SUPPLY_SEQ_AUD_TOP, + SUPPLY_SEQ_AUD_TOP_LAST, + SUPPLY_SEQ_DL_SDM_FIFO_CLK, + SUPPLY_SEQ_DL_SDM, + SUPPLY_SEQ_DL_NCP, + SUPPLY_SEQ_AFE, + /* playback */ + SUPPLY_SEQ_DL_SRC, + SUPPLY_SEQ_DL_ESD_RESIST, + SUPPLY_SEQ_HP_DAMPING_OFF_RESET_CMFB, + SUPPLY_SEQ_HP_MUTE, + SUPPLY_SEQ_DL_LDO_REMOTE_SENSE, + SUPPLY_SEQ_DL_LDO, + SUPPLY_SEQ_DL_NV, + SUPPLY_SEQ_HP_ANA_TRIM, + SUPPLY_SEQ_DL_IBIST, + /* capture */ + SUPPLY_SEQ_UL_PGA, + SUPPLY_SEQ_UL_ADC, + SUPPLY_SEQ_UL_MTKAIF, + SUPPLY_SEQ_UL_SRC_DMIC, + SUPPLY_SEQ_UL_SRC, +}; + +enum { + CH_L = 0, + CH_R, + NUM_CH, +}; + +enum { + DRBIAS_4UA = 0, + DRBIAS_5UA, + DRBIAS_6UA, + DRBIAS_7UA, + DRBIAS_8UA, + DRBIAS_9UA, + DRBIAS_10UA, + DRBIAS_11UA, +}; + +enum { + IBIAS_4UA = 0, + IBIAS_5UA, + IBIAS_6UA, + IBIAS_7UA, +}; + +enum { + IBIAS_ZCD_3UA = 0, + IBIAS_ZCD_4UA, + IBIAS_ZCD_5UA, + IBIAS_ZCD_6UA, +}; + +enum { + MIC_BIAS_1P7 = 0, + MIC_BIAS_1P8, + MIC_BIAS_1P9, + MIC_BIAS_2P0, + MIC_BIAS_2P1, + MIC_BIAS_2P5, + MIC_BIAS_2P6, + MIC_BIAS_2P7, +}; + +/* dl pga gain */ +enum { + DL_GAIN_8DB = 0, + DL_GAIN_0DB = 8, + DL_GAIN_N_1DB = 9, + DL_GAIN_N_10DB = 18, + DL_GAIN_N_22DB = 30, + DL_GAIN_N_40DB = 0x1f, +}; + +/* Mic Type MUX */ +enum { + MIC_TYPE_MUX_IDLE = 0, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, +}; + +/* UL SRC MUX */ +enum { + UL_SRC_MUX_AMIC = 0, + UL_SRC_MUX_DMIC, +}; + +/* MISO MUX */ +enum { + MISO_MUX_UL1_CH1 = 0, + MISO_MUX_UL1_CH2, + MISO_MUX_UL2_CH1, + MISO_MUX_UL2_CH2, +}; + +/* DMIC MUX */ +enum { + DMIC_MUX_DMIC_DATA0 = 0, + DMIC_MUX_DMIC_DATA1_L, + DMIC_MUX_DMIC_DATA1_L_1, + DMIC_MUX_DMIC_DATA1_R, +}; + +/* ADC L MUX */ +enum { + ADC_MUX_IDLE = 0, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, +}; + +/* PGA L MUX */ +enum { + PGA_L_MUX_NONE = 0, + PGA_L_MUX_AIN0, + PGA_L_MUX_AIN1, +}; + +/* PGA R MUX */ +enum { + PGA_R_MUX_NONE = 0, + PGA_R_MUX_AIN2, + PGA_R_MUX_AIN3, + PGA_R_MUX_AIN0, +}; + +/* PGA 3 MUX */ +enum { + PGA_3_MUX_NONE = 0, + PGA_3_MUX_AIN3, + PGA_3_MUX_AIN2, +}; + +struct mt6359_priv { + struct device *dev; + struct regmap *regmap; + unsigned int dl_rate[MT6359_AIF_NUM]; + unsigned int ul_rate[MT6359_AIF_NUM]; + int ana_gain[AUDIO_ANALOG_VOLUME_TYPE_MAX]; + unsigned int mux_select[MUX_NUM]; + unsigned int dmic_one_wire_mode; + int dev_counter[DEVICE_NUM]; + int hp_gain_ctl; + int hp_hifi_mode; + int mtkaif_protocol; + struct regulator *avdd_reg; +}; + +#define CODEC_MT6359_NAME "mtk-codec-mt6359" +#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \ + (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ + (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) + +#endif/* end _MT6359_H_ */ diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 9f5aee7de686..f0cba7b5758b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -251,7 +251,7 @@ static const unsigned short logtable[256] = { * * Acquires the semaphore without jiffies. Try to acquire the semaphore * atomically. Returns 0 if the semaphore has been acquired successfully - * or 1 if it it cannot be acquired. + * or 1 if it cannot be acquired. */ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) { diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index b0ba0d2acbdd..6a2318e04bb7 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -693,7 +693,7 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, } static const struct sdw_device_id rt1308_id[] = { - SDW_SLAVE_ENTRY(0x025d, 0x1308, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt1308_id); diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 85aba311bdc8..6b4e0eb30c89 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -294,6 +294,7 @@ static struct i2c_driver rt5682_i2c_driver = { .name = "rt5682", .of_match_table = rt5682_of_match, .acpi_match_table = rt5682_acpi_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = rt5682_i2c_probe, .shutdown = rt5682_i2c_shutdown, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 94bf6bee78e6..b0386f592290 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -717,7 +717,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) } static const struct sdw_device_id rt5682_id[] = { - SDW_SLAVE_ENTRY(0x025d, 0x5682, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x5682, 0x2, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt5682_id); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index a4713bd6508d..93ebf0279b62 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2481,7 +2481,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, static bool rt5682_clk_check(struct rt5682_priv *rt5682) { if (!rt5682->master[RT5682_AIF1]) { - dev_err(rt5682->component->dev, "sysclk/dai not set correctly\n"); + dev_dbg(rt5682->component->dev, "sysclk/dai not set correctly\n"); return false; } return true; @@ -2559,7 +2559,7 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw, container_of(hw, struct rt5682_priv, dai_clks_hw[RT5682_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682->component; - const char * const clk_name = __clk_get_name(hw->clk); + const char * const clk_name = clk_hw_get_name(hw); if (!rt5682_clk_check(rt5682)) return 0; @@ -2583,7 +2583,7 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate, container_of(hw, struct rt5682_priv, dai_clks_hw[RT5682_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682->component; - const char * const clk_name = __clk_get_name(hw->clk); + const char * const clk_name = clk_hw_get_name(hw); if (!rt5682_clk_check(rt5682)) return -EINVAL; @@ -2608,7 +2608,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, dai_clks_hw[RT5682_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682->component; struct clk *parent_clk; - const char * const clk_name = __clk_get_name(hw->clk); + const char * const clk_name = clk_hw_get_name(hw); int pre_div; unsigned int clk_pll2_out; @@ -2766,39 +2766,34 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component) struct device *dev = component->dev; struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); struct rt5682_platform_data *pdata = &rt5682->pdata; - struct clk_init_data init; - struct clk *dai_clk; - struct clk_lookup *dai_clk_lookup; struct clk_hw *dai_clk_hw; - const char *parent_name; int i, ret; for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) { + struct clk_init_data init = { }; + dai_clk_hw = &rt5682->dai_clks_hw[i]; switch (i) { case RT5682_DAI_WCLK_IDX: /* Make MCLK the parent of WCLK */ if (rt5682->mclk) { - parent_name = __clk_get_name(rt5682->mclk); - init.parent_names = &parent_name; + init.parent_data = &(struct clk_parent_data){ + .fw_name = "mclk", + }; init.num_parents = 1; - } else { - init.parent_names = NULL; - init.num_parents = 0; } break; case RT5682_DAI_BCLK_IDX: /* Make WCLK the parent of BCLK */ - parent_name = __clk_get_name( - rt5682->dai_clks[RT5682_DAI_WCLK_IDX]); - init.parent_names = &parent_name; + init.parent_hws = &(const struct clk_hw *){ + &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX] + }; init.num_parents = 1; break; default: dev_err(dev, "Invalid clock index\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } init.name = pdata->dai_clk_names[i]; @@ -2806,39 +2801,26 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component) init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; dai_clk_hw->init = &init; - dai_clk = devm_clk_register(dev, dai_clk_hw); - if (IS_ERR(dai_clk)) { - dev_warn(dev, "Failed to register %s: %ld\n", - init.name, PTR_ERR(dai_clk)); - ret = PTR_ERR(dai_clk); - goto err; + 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; } - rt5682->dai_clks[i] = dai_clk; if (dev->of_node) { devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); } else { - dai_clk_lookup = clkdev_create(dai_clk, init.name, - "%s", dev_name(dev)); - if (!dai_clk_lookup) { - ret = -ENOMEM; - goto err; - } else { - rt5682->dai_clks_lookup[i] = dai_clk_lookup; - } + ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, + init.name, + dev_name(dev)); + if (ret) + return ret; } } return 0; - -err: - do { - if (rt5682->dai_clks_lookup[i]) - clkdev_drop(rt5682->dai_clks_lookup[i]); - } while (i-- > 0); - - return ret; } #endif /* CONFIG_COMMON_CLK */ @@ -2895,15 +2877,6 @@ static void rt5682_remove(struct snd_soc_component *component) { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); -#ifdef CONFIG_COMMON_CLK - int i; - - for (i = RT5682_DAI_NUM_CLKS - 1; i >= 0; --i) { - if (rt5682->dai_clks_lookup[i]) - clkdev_drop(rt5682->dai_clks_lookup[i]); - } -#endif - rt5682_reset(rt5682); } diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 6d94327beae5..354acd735ef4 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1411,8 +1411,6 @@ struct rt5682_priv { #ifdef CONFIG_COMMON_CLK struct clk_hw dai_clks_hw[RT5682_DAI_NUM_CLKS]; - struct clk_lookup *dai_clks_lookup[RT5682_DAI_NUM_CLKS]; - struct clk *dai_clks[RT5682_DAI_NUM_CLKS]; struct clk *mclk; #endif diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 4d14048d1197..5430941cb2da 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -478,7 +478,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave) } static const struct sdw_device_id rt700_id[] = { - SDW_SLAVE_ENTRY(0x025d, 0x700, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x700, 0x1, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt700_id); diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 45b928954b58..dff098ddde01 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -479,7 +479,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave) } static const struct sdw_device_id rt711_id[] = { - SDW_SLAVE_ENTRY(0x025d, 0x711, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x2, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt711_id); diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index d11b23d6b240..00e441560f00 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -541,7 +541,7 @@ static int rt715_sdw_probe(struct sdw_slave *slave, } static const struct sdw_device_id rt715_id[] = { - SDW_SLAVE_ENTRY(0x025d, 0x715, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt715_id); diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 0250b94c8f65..7831c96d0d83 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -487,7 +487,7 @@ static int tas5086_init(struct device *dev, struct tas5086_private *priv) /* * If any of the channels is configured to start in Mid-Z mode, * configure 'part 1' of the PWM starts to use Mid-Z, and tell - * all configured mid-z channels to start start under 'part 1'. + * all configured mid-z channels to start under 'part 1'. */ if (priv->pwm_start_mid_z) regmap_write(priv->regmap, TAS5086_PWM_START, diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 5cd50d841177..5d1b2a03f0ac 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -412,6 +412,16 @@ static const struct snd_soc_dapm_widget adcx140_dapm_widgets[] = { SND_SOC_DAPM_ADC("CH3_ADC", "CH3 Capture", ADCX140_IN_CH_EN, 5, 0), SND_SOC_DAPM_ADC("CH4_ADC", "CH4 Capture", ADCX140_IN_CH_EN, 4, 0), + SND_SOC_DAPM_ADC("CH1_DIG", "CH1 Capture", ADCX140_IN_CH_EN, 7, 0), + SND_SOC_DAPM_ADC("CH2_DIG", "CH2 Capture", ADCX140_IN_CH_EN, 6, 0), + SND_SOC_DAPM_ADC("CH3_DIG", "CH3 Capture", ADCX140_IN_CH_EN, 5, 0), + SND_SOC_DAPM_ADC("CH4_DIG", "CH4 Capture", ADCX140_IN_CH_EN, 4, 0), + SND_SOC_DAPM_ADC("CH5_DIG", "CH5 Capture", ADCX140_IN_CH_EN, 3, 0), + SND_SOC_DAPM_ADC("CH6_DIG", "CH6 Capture", ADCX140_IN_CH_EN, 2, 0), + SND_SOC_DAPM_ADC("CH7_DIG", "CH7 Capture", ADCX140_IN_CH_EN, 1, 0), + SND_SOC_DAPM_ADC("CH8_DIG", "CH8 Capture", ADCX140_IN_CH_EN, 0, 0), + + SND_SOC_DAPM_SWITCH("CH1_ASI_EN", SND_SOC_NOPM, 0, 0, &adcx140_dapm_ch1_en_switch), SND_SOC_DAPM_SWITCH("CH2_ASI_EN", SND_SOC_NOPM, 0, 0, @@ -470,6 +480,15 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"CH3_ASI_EN", "Switch", "CH3_ADC"}, {"CH4_ASI_EN", "Switch", "CH4_ADC"}, + {"CH1_ASI_EN", "Switch", "CH1_DIG"}, + {"CH2_ASI_EN", "Switch", "CH2_DIG"}, + {"CH3_ASI_EN", "Switch", "CH3_DIG"}, + {"CH4_ASI_EN", "Switch", "CH4_DIG"}, + {"CH5_ASI_EN", "Switch", "CH5_DIG"}, + {"CH6_ASI_EN", "Switch", "CH6_DIG"}, + {"CH7_ASI_EN", "Switch", "CH7_DIG"}, + {"CH8_ASI_EN", "Switch", "CH8_DIG"}, + {"CH5_ASI_EN", "Switch", "CH5_OUT"}, {"CH6_ASI_EN", "Switch", "CH6_OUT"}, {"CH7_ASI_EN", "Switch", "CH7_OUT"}, @@ -541,6 +560,15 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"PDM Clk Div Select", "705.6 kHz", "MIC1P Input Mux"}, {"PDM Clk Div Select", "5.6448 MHz", "MIC1P Input Mux"}, + {"MIC1P Input Mux", NULL, "CH1_DIG"}, + {"MIC1M Input Mux", NULL, "CH2_DIG"}, + {"MIC2P Input Mux", NULL, "CH3_DIG"}, + {"MIC2M Input Mux", NULL, "CH4_DIG"}, + {"MIC3P Input Mux", NULL, "CH5_DIG"}, + {"MIC3M Input Mux", NULL, "CH6_DIG"}, + {"MIC4P Input Mux", NULL, "CH7_DIG"}, + {"MIC4M Input Mux", NULL, "CH8_DIG"}, + {"MIC1 Analog Mux", "Line In", "MIC1P"}, {"MIC2 Analog Mux", "Line In", "MIC2P"}, {"MIC3 Analog Mux", "Line In", "MIC3P"}, @@ -554,6 +582,15 @@ static const struct snd_soc_dapm_route adcx140_audio_map[] = { {"MIC3M Input Mux", "Analog", "MIC3M"}, {"MIC4P Input Mux", "Analog", "MIC4P"}, {"MIC4M Input Mux", "Analog", "MIC4M"}, + + {"MIC1P Input Mux", "Digital", "MIC1P"}, + {"MIC1M Input Mux", "Digital", "MIC1M"}, + {"MIC2P Input Mux", "Digital", "MIC2P"}, + {"MIC2M Input Mux", "Digital", "MIC2M"}, + {"MIC3P Input Mux", "Digital", "MIC3P"}, + {"MIC3M Input Mux", "Digital", "MIC3M"}, + {"MIC4P Input Mux", "Digital", "MIC4P"}, + {"MIC4M Input Mux", "Digital", "MIC4M"}, }; static const struct snd_kcontrol_new adcx140_snd_controls[] = { diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 467802875c13..8dcea566b375 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -50,6 +50,28 @@ struct aic32x4_priv { struct device *dev; }; +static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u32 adc_reg; + + /* + * Workaround: the datasheet does not mention a required programming + * sequence but experiments show the ADC needs to be reset after each + * capture to avoid audible artifacts. + */ + switch (event) { + case SND_SOC_DAPM_POST_PMD: + adc_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP); + snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg | + AIC32X4_LADC_EN | AIC32X4_RADC_EN); + snd_soc_component_write(component, AIC32X4_ADCSETUP, adc_reg); + break; + } + return 0; +}; + static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -434,6 +456,7 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc), SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), @@ -665,7 +688,8 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component, } static int aic32x4_setup_clocks(struct snd_soc_component *component, - unsigned int sample_rate) + unsigned int sample_rate, unsigned int channel, + unsigned int bit_depth) { u8 aosr; u16 dosr; @@ -753,7 +777,8 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, dosr); clk_set_rate(clocks[5].clk, - sample_rate * 32); + sample_rate * channel * + bit_depth); return 0; } } @@ -775,9 +800,11 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, u8 iface1_reg = 0; u8 dacsetup_reg = 0; - aic32x4_setup_clocks(component, params_rate(params)); + aic32x4_setup_clocks(component, params_rate(params), + params_channels(params), + params_physical_width(params)); - switch (params_width(params)) { + switch (params_physical_width(params)) { case 16: iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT); @@ -862,7 +889,8 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component, #define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000 #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ - | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE \ + | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops aic32x4_ops = { .hw_params = aic32x4_hw_params, @@ -883,7 +911,7 @@ static struct snd_soc_dai_driver aic32x4_dai = { .capture = { .stream_name = "Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = AIC32X4_RATES, .formats = AIC32X4_FORMATS,}, .ops = &aic32x4_ops, @@ -953,12 +981,6 @@ static int aic32x4_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (gpio_is_valid(aic32x4->rstn_gpio)) { - ndelay(10); - gpio_set_value(aic32x4->rstn_gpio, 1); - mdelay(1); - } - snd_soc_component_write(component, AIC32X4_RESET, 0x01); if (aic32x4->setup) @@ -1191,10 +1213,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) aic32x4->mclk_name = "mclk"; } - ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); - if (ret) - return ret; - if (gpio_is_valid(aic32x4->rstn_gpio)) { ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio, GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); @@ -1216,6 +1234,16 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) return ret; } + if (gpio_is_valid(aic32x4->rstn_gpio)) { + ndelay(10); + gpio_set_value_cansleep(aic32x4->rstn_gpio, 1); + mdelay(1); + } + + ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); + if (ret) + return ret; + return 0; } EXPORT_SYMBOL(aic32x4_probe); diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 2f2b2f5d55e4..28b4656c4e14 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -346,7 +346,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp struct list_head xfer_list; struct wm0010_boot_xfer *xfer; int ret; - struct completion done; + DECLARE_COMPLETION_ONSTACK(done); const struct firmware *fw; const struct dfw_binrec *rec; const struct dfw_inforec *inforec; @@ -370,7 +370,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp wm0010->boot_failed = false; if (WARN_ON(!list_empty(&xfer_list))) return -EINVAL; - init_completion(&done); /* First record should be INFO */ if (rec->command != DFW_CMD_INFO) { diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 0623a2251084..0bd3bbc2aacf 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1702,6 +1702,8 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME, SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0), SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0), SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0), +SOC_SINGLE("DAC Monomix Switch", WM8962_DAC_DSP_MIXING_1, WM8962_DAC_MONOMIX_SHIFT, 1, 0), +SOC_SINGLE("ADC Monomix Switch", WM8962_THREED1, WM8962_ADC_MONOMIX_SHIFT, 1, 0), SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1, 5, 1, 0), diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 7072ffacbdfd..f333e2ff4a16 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -755,7 +755,7 @@ static void pll_factors(struct snd_soc_component *component, u64 Kpart; unsigned int K, Ndiv, Nmod, target; - /* The the PLL output is always 98.304MHz. */ + /* The PLL output is always 98.304MHz. */ target = 98304000; /* If the input frequency is over 14.4MHz then scale it down. */ diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 410cca57da52..4ff0c6cfa32d 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -199,7 +199,7 @@ #define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C #define ADSP2_REGION_LOCK_ERR_MASK 0x8000 -#define ADSP2_SLAVE_ERR_MASK 0x4000 +#define ADSP2_ADDR_ERR_MASK 0x4000 #define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 #define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002 #define ADSP2_CTRL_ERR_EINT 0x0001 @@ -4364,9 +4364,9 @@ irqreturn_t wm_adsp2_bus_error(int irq, void *data) wm_adsp_fatal_error(dsp); } - if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { - if (val & ADSP2_SLAVE_ERR_MASK) - adsp_err(dsp, "bus error: slave error\n"); + 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"); else adsp_err(dsp, "bus error: region lock error\n"); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 1c4ca5ec8caf..3f76ff71ea47 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -324,7 +324,7 @@ config SND_SOC_FSL_ASOC_CARD help ALSA SoC Audio support with ASRC feature for Freescale SoCs that have ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888, - CS4271, CS4272 and SGTL5000. + CS4271, CS4272, SGTL5000 and TLV320AIC32x4. Say Y if you want to add support for Freescale Generic ASoC Sound Card. config SND_SOC_IMX_AUDMIX diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 52adedc03245..a2dd3b6b7fec 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -617,6 +617,9 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) codec_dai_name = "sgtl5000"; priv->codec_priv.mclk_id = SGTL5000_SYSCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) { + codec_dai_name = "tlv320aic32x4-hifi"; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { codec_dai_name = "wm8962"; priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; @@ -696,6 +699,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; } } else if (of_node_name_eq(cpu_np, "esai")) { + struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal"); + + if (!IS_ERR(esai_clk)) { + priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk); + priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk); + clk_put(esai_clk); + } else if (PTR_ERR(esai_clk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto asrc_fail; + } + priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; } else if (of_node_name_eq(cpu_np, "sai")) { @@ -849,6 +863,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-ac97", }, { .compatible = "fsl,imx-audio-cs42888", }, { .compatible = "fsl,imx-audio-cs427x", }, + { .compatible = "fsl,imx-audio-tlv320aic32x4", }, { .compatible = "fsl,imx-audio-sgtl5000", }, { .compatible = "fsl,imx-audio-wm8962", }, { .compatible = "fsl,imx-audio-wm8960", }, diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index be021250d6e9..e0c39c5f4854 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -154,7 +154,7 @@ static void fsl_dma_abort_stream(struct snd_pcm_substream *substream) /** * fsl_dma_update_pointers - update LD pointers to point to the next period * - * As each period is completed, this function changes the the link + * As each period is completed, this function changes the link * descriptor pointers for that period to point to the next period. */ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cdff739924e2..b2d65e53dbc4 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -37,6 +37,24 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { .list = fsl_sai_rates, }; +/** + * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream + * + * SAI supports synchronous mode using bit/frame clocks of either Transmitter's + * or Receiver's for both streams. This function is used to check if clocks of + * the stream's are synced by the opposite stream. + * + * @sai: SAI context + * @dir: stream direction + */ +static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) +{ + int adir = (dir == TX) ? RX : TX; + + /* current dir in async mode while opposite dir in sync mode */ + return !sai->synchronous[dir] && sai->synchronous[adir]; +} + static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; @@ -332,6 +350,8 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) unsigned int ofs = sai->soc_data->reg_offset; unsigned long clk_rate; u32 savediv = 0, ratio, savesub = freq; + int adir = tx ? RX : TX; + int dir = tx ? TX : RX; u32 id; int ret = 0; @@ -390,19 +410,17 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) * 4) For Tx and Rx are both Synchronous with another SAI, we just * ignore it. */ - if ((sai->synchronous[TX] && !sai->synchronous[RX]) || - (!tx && !sai->synchronous[RX])) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), + if (fsl_sai_dir_is_synced(sai, adir)) { + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); - } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) || - (tx && !sai->synchronous[TX])) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), + } else if (!sai->synchronous[dir]) { + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); } @@ -424,6 +442,8 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 val_cr4 = 0, val_cr5 = 0; u32 slots = (channels == 1) ? 2 : channels; u32 slot_width = word_width; + int adir = tx ? RX : TX; + u32 pins; int ret; if (sai->slots) @@ -432,6 +452,8 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, if (sai->slot_width) slot_width = sai->slot_width; + pins = DIV_ROUND_UP(channels, slots); + if (!sai->is_slave_mode) { if (sai->bclk_ratio) ret = fsl_sai_set_bclk(cpu_dai, tx, @@ -467,42 +489,38 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr4 |= FSL_SAI_CR4_FRSZ(slots); + /* Set to output mode to avoid tri-stated data pins */ + if (tx) + val_cr4 |= FSL_SAI_CR4_CHMOD; + /* * For SAI master 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) and RMR(TMR) for playback(capture), or there will be sync - * error. + * RCR5(TCR5) for playback(capture), or there will be sync error. */ - if (!sai->is_slave_mode) { - if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs), - FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, - val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs), - FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | - FSL_SAI_CR5_FBT_MASK, val_cr5); - regmap_write(sai->regmap, FSL_SAI_TMR, - ~0UL - ((1 << channels) - 1)); - } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs), - FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, - val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs), - FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | - FSL_SAI_CR5_FBT_MASK, val_cr5); - regmap_write(sai->regmap, FSL_SAI_RMR, - ~0UL - ((1 << channels) - 1)); - } + if (!sai->is_slave_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, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_xCR5(!tx, ofs), + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); } + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), + FSL_SAI_CR3_TRCE_MASK, + FSL_SAI_CR3_TRCE((1 << pins) - 1)); regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), - FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | + FSL_SAI_CR4_CHMOD_MASK, val_cr4); regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); - regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1)); + regmap_write(sai->regmap, FSL_SAI_xMR(tx), + ~0UL - ((1 << min(channels, slots)) - 1)); return 0; } @@ -512,6 +530,10 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int ofs = sai->soc_data->reg_offset; + + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), + FSL_SAI_CR3_TRCE_MASK, 0); if (!sai->is_slave_mode && sai->mclk_streams & BIT(substream->stream)) { @@ -522,6 +544,38 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, return 0; } +static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) +{ + unsigned int ofs = sai->soc_data->reg_offset; + bool tx = dir == TX; + u32 xcsr, count = 100; + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), + FSL_SAI_CSR_TERE, 0); + + /* TERE will remain set till the end of current frame */ + do { + udelay(10); + regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr); + } while (--count && xcsr & FSL_SAI_CSR_TERE); + + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), + FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); + + /* + * For sai master mode, after several open/close sai, + * there will be no frame clock, and can't recover + * anymore. Add software reset to fix this issue. + * This is a hardware bug, and will be fix in the + * next sai version. + */ + if (!sai->is_slave_mode) { + /* Software Reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); + } +} static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) @@ -530,7 +584,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 xcsr, count = 100; + int adir = tx ? RX : TX; + int dir = tx ? TX : RX; + u32 xcsr; /* * Asynchronous mode: Clear SYNC for both Tx and Rx. @@ -553,10 +609,22 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + /* + * Enable the opposite direction for synchronous mode + * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx + * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx + * + * RM recommends to enable RE after TE for case 1 and to enable + * TE after RE for case 2, but we here may not always guarantee + * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables + * TE after RE, which is against what RM recommends but should + * be safe to do, judging by years of testing results. + */ + if (fsl_sai_dir_is_synced(sai, adir)) + regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); @@ -571,43 +639,23 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, /* Check if the opposite FRDE is also disabled */ regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); - if (!(xcsr & FSL_SAI_CSR_FRDE)) { - /* Disable both directions and reset their FIFOs */ - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_TERE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_TERE, 0); - - /* TERE will remain set till the end of current frame */ - do { - udelay(10); - regmap_read(sai->regmap, - FSL_SAI_xCSR(tx, ofs), &xcsr); - } while (--count && xcsr & FSL_SAI_CSR_TERE); - - regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - - /* - * For sai master mode, after several open/close sai, - * there will be no frame clock, and can't recover - * anymore. Add software reset to fix this issue. - * This is a hardware bug, and will be fix in the - * next sai version. - */ - if (!sai->is_slave_mode) { - /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), - FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), - FSL_SAI_CSR_SR); - /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); - regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); - } - } + + /* + * If opposite stream provides clocks for synchronous mode and + * it is inactive, disable it before disabling the current one + */ + if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE)) + fsl_sai_config_disable(sai, adir); + + /* + * Disable current stream if either of: + * 1. current stream doesn't provide clocks for synchronous mode + * 2. current stream provides clocks for synchronous mode but no + * more stream is active. + */ + if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE)) + fsl_sai_config_disable(sai, dir); + break; default: return -EINVAL; @@ -620,14 +668,9 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), - FSL_SAI_CR3_TRCE_MASK, - FSL_SAI_CR3_TRCE); - /* * EDMA controller needs period size to be a multiple of * tx/rx maxburst @@ -644,17 +687,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, return ret; } -static void fsl_sai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); - unsigned int ofs = sai->soc_data->reg_offset; - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), - FSL_SAI_CR3_TRCE_MASK, 0); -} - static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, .set_sysclk = fsl_sai_set_dai_sysclk, @@ -664,7 +696,6 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, .startup = fsl_sai_startup, - .shutdown = fsl_sai_shutdown, }; static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) @@ -928,7 +959,7 @@ static int fsl_sai_probe(struct platform_device *pdev) "bus", base, &fsl_sai_regmap_config); /* Compatible with old DTB cases */ - if (IS_ERR(sai->regmap)) + if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER) sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai", base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 6aba7d28f5f3..736a437450c8 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -109,7 +109,7 @@ #define FSL_SAI_CR2_DIV_MASK 0xff /* SAI Transmit and Receive Configuration 3 Register */ -#define FSL_SAI_CR3_TRCE BIT(16) +#define FSL_SAI_CR3_TRCE(x) ((x) << 16) #define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f @@ -119,6 +119,8 @@ #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) #define FSL_SAI_CR4_SYWD_MASK (0x1f << 8) +#define FSL_SAI_CR4_CHMOD BIT(5) +#define FSL_SAI_CR4_CHMOD_MASK BIT(5) #define FSL_SAI_CR4_MF BIT(4) #define FSL_SAI_CR4_FSE BIT(3) #define FSL_SAI_CR4_FSP BIT(1) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 15a27a2cd0ca..fad1eb6253d5 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -145,13 +145,13 @@ static int imx_es8328_probe(struct platform_device *pdev) data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) { ret = -ENOMEM; - goto fail; + goto put_device; } comp = devm_kzalloc(dev, 3 * sizeof(*comp), GFP_KERNEL); if (!comp) { ret = -ENOMEM; - goto fail; + goto put_device; } data->dev = dev; @@ -182,12 +182,12 @@ static int imx_es8328_probe(struct platform_device *pdev) ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) { dev_err(dev, "Unable to parse card name\n"); - goto fail; + goto put_device; } ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); if (ret) { dev_err(dev, "Unable to parse routing: %d\n", ret); - goto fail; + goto put_device; } data->card.num_links = 1; data->card.owner = THIS_MODULE; @@ -196,10 +196,12 @@ static int imx_es8328_probe(struct platform_device *pdev) ret = snd_soc_register_card(&data->card); if (ret) { dev_err(dev, "Unable to register: %d\n", ret); - goto fail; + goto put_device; } platform_set_drvdata(pdev, data); +put_device: + put_device(&ssi_pdev->dev); fail: of_node_put(ssi_np); of_node_put(codec_np); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 04d4d28ed511..75365c7bb393 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -424,37 +424,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, return ret; } -static int simple_parse_aux_devs(struct device_node *node, - struct asoc_simple_priv *priv) -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *aux_node; - struct snd_soc_card *card = simple_priv_to_card(priv); - int i, n, len; - - if (!of_find_property(node, PREFIX "aux-devs", &len)) - return 0; /* Ok to have no aux-devs */ - - n = len / sizeof(__be32); - if (n <= 0) - return -EINVAL; - - card->aux_dev = devm_kcalloc(dev, - n, sizeof(*card->aux_dev), GFP_KERNEL); - if (!card->aux_dev) - return -ENOMEM; - - for (i = 0; i < n; i++) { - aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); - if (!aux_node) - return -EINVAL; - card->aux_dev[i].dlc.of_node = aux_node; - } - - card->num_aux_devs = n; - return 0; -} - static int simple_parse_of(struct asoc_simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); @@ -504,7 +473,7 @@ static int simple_parse_of(struct asoc_simple_priv *priv) if (ret < 0) return ret; - ret = simple_parse_aux_devs(top, priv); + ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); return ret; } diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 82805a8681e5..0e48c4f532ce 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -209,7 +209,7 @@ config SND_SOC_INTEL_SKYLAKE_SSP_CLK config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC bool "HDAudio codec support" help - If you have Intel Skylake or Kabylake with HDaudio codec + If you have Intel Skylake or Kabylake with HDAudio codec and DMIC present then enable this option by saying Y. config SND_SOC_INTEL_SKYLAKE_COMMON diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index ff42f629b035..6b5a34a15acb 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -299,7 +299,7 @@ static int sst_find_and_send_pipe_algo(struct sst_data *drv, { int ret = 0; struct sst_algo_control *bc; - struct sst_module *algo = NULL; + struct sst_module *algo; dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe); @@ -602,7 +602,7 @@ static int sst_set_pipe_gain(struct sst_ids *ids, int ret = 0; struct sst_gain_mixer_control *mc; struct sst_gain_value *gv; - struct sst_module *gain = NULL; + struct sst_module *gain; list_for_each_entry(gain, &ids->gain_list, node) { struct snd_kcontrol *kctl = gain->kctl; diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c index 1595e01a7e12..89c9c5ad6b21 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-compress.c +++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c @@ -42,8 +42,7 @@ static void sst_drain_notify(void *arg) static int sst_platform_compr_open(struct snd_soc_component *component, struct snd_compr_stream *cstream) { - - int ret_val = 0; + int ret_val; struct snd_compr_runtime *runtime = cstream->runtime; struct sst_runtime_stream *stream; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index b1cac7abdc0a..6add70500ed8 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -366,7 +366,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sst_runtime_stream *stream; - int ret_val = 0, str_id; + int ret_val, str_id; stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; @@ -385,7 +385,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, if (ret_val) return ret_val; substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER; - return ret_val; + return 0; } static int sst_enable_ssp(struct snd_pcm_substream *substream, diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 10c9ecfa7038..8b5777d3229a 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -173,6 +173,6 @@ struct sst_data { struct snd_soc_card *soc_card; struct sst_cmd_sba_hw_set_ssp ssp_cmd; }; -int sst_register_dsp(struct sst_device *sst); -int sst_unregister_dsp(struct sst_device *sst); +int sst_register_dsp(struct sst_device *dev); +int sst_unregister_dsp(struct sst_device *dev); #endif diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index d6563985e008..d450b9848028 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -49,7 +49,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) union ipc_header_mrfld header; union sst_imr_reg_mrfld imr; struct ipc_post *msg = NULL; - unsigned int size = 0; + unsigned int size; struct intel_sst_drv *drv = (struct intel_sst_drv *) context; irqreturn_t retval = IRQ_HANDLED; @@ -370,7 +370,6 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) kfree(ctx->fw_in_mem); ctx->fw_in_mem = NULL; sst_memcpy_free_resources(ctx); - ctx = NULL; } EXPORT_SYMBOL_GPL(sst_context_cleanup); @@ -424,7 +423,7 @@ static int intel_sst_suspend(struct device *dev) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); struct sst_fw_save *fw_save; - int i, ret = 0; + int i, ret; /* check first if we are already in SW reset */ if (ctx->sst_state == SST_RESET) diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 50441cf6f77d..2bee646e81b8 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -428,34 +428,34 @@ struct intel_sst_ops { }; int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); -int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id); -int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id); -int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id); -int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id); +int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); +int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); +int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); +int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); -int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx, - struct snd_sst_bytes_v2 *sbytes); +int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, + struct snd_sst_bytes_v2 *bytes); int sst_set_stream_param(int str_id, struct snd_sst_params *str_param); int sst_set_metadata(int str_id, char *params); -int sst_get_stream(struct intel_sst_drv *sst_drv_ctx, +int sst_get_stream(struct intel_sst_drv *ctx, struct snd_sst_params *str_param); int sst_get_stream_allocated(struct intel_sst_drv *ctx, struct snd_sst_params *str_param, struct snd_sst_lib_download **lib_dnld); int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, int str_id, bool partial_drain); -int sst_post_message_mrfld(struct intel_sst_drv *ctx, - struct ipc_post *msg, bool sync); -void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg); -int sst_start_mrfld(struct intel_sst_drv *ctx); -int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx); -void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx); - -int sst_load_fw(struct intel_sst_drv *ctx); +int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, + struct ipc_post *ipc_msg, bool sync); +void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, struct ipc_post *msg); +int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx); +int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx); +void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx); + +int sst_load_fw(struct intel_sst_drv *sst_drv_ctx); int sst_load_library(struct snd_sst_lib_download *lib, u8 ops); void sst_post_download_mrfld(struct intel_sst_drv *ctx); int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); -void sst_memcpy_free_resources(struct intel_sst_drv *ctx); +void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx); int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block); @@ -490,7 +490,7 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst, bool large, bool fill_dsp, bool sync, bool response); void sst_process_pending_msg(struct work_struct *work); -int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx); +int sst_assign_pvt_id(struct intel_sst_drv *drv); int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id); struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx, int str_id); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index fc91a304256b..5c42cce90ce2 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -398,8 +398,7 @@ int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n"); - if (sst_drv_ctx->sst_state != SST_RESET || - sst_drv_ctx->sst_state == SST_SHUTDOWN) + if (sst_drv_ctx->sst_state != SST_RESET) return -EAGAIN; if (!sst_drv_ctx->fw_in_mem) { diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 053c27707147..c099f7df6168 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -188,7 +188,7 @@ int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, struct intel_sst_drv *sst_drv_ctx, struct sst_block **block, u32 msg_id, u32 drv_id) { - int retval = 0; + int retval; retval = sst_create_ipc_msg(arg, large); if (retval) @@ -198,7 +198,7 @@ int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, kfree(*arg); return -ENOMEM; } - return retval; + return 0; } /* diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.h b/sound/soc/intel/baytrail/sst-baytrail-ipc.h index 755098509327..cc960b79e9e1 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.h +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.h @@ -26,8 +26,7 @@ extern struct sst_ops sst_byt_ops; /* stream API */ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, - uint32_t (*get_write_position)(struct sst_byt_stream *stream, - void *data), + uint32_t (*notify_position)(struct sst_byt_stream *stream, void *data), void *data); /* stream configuration */ diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index d96fc1313434..12dd41796e82 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -569,9 +569,12 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_MAX98373_SDW select SND_SOC_RT700_SDW select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 + select SND_SOC_RT1316_SDW select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_DMIC help diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dc04acb911b6..de7cc9b86354 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -35,9 +35,10 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o snd-soc-ehl-rt5660-objs := ehl_rt5660.o hda_dsp_common.o snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_max98373.o \ - sof_sdw_rt711.o sof_sdw_rt700.o \ - sof_sdw_rt1308.o sof_sdw_rt715.o \ - sof_sdw_rt5682.o \ + sof_sdw_rt1308.o sof_sdw_rt1316.o \ + sof_sdw_rt5682.o sof_sdw_rt700.o \ + sof_sdw_rt711.o sof_sdw_rt711_sdca.o \ + sof_sdw_rt715.o sof_sdw_rt715_sdca.o \ sof_maxim_common.o \ sof_sdw_dmic.o sof_sdw_hdmi.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index ce7320916b22..1412a9941ed4 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -87,14 +87,14 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *chan = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); /* The ADSP will covert the FE rate to 48k, max 4-channels */ rate->min = rate->max = 48000; - channels->min = 2; - channels->max = 4; + chan->min = 2; + chan->max = 4; /* set SSP0 to 24 bit */ snd_mask_set_format(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 86e427e3822f..297871bcaf5d 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -140,13 +140,13 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *chan = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); /* The ADSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; - channels->min = channels->max = 2; + chan->min = chan->max = 2; /* set SSP0 to 16 bit */ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index f6399077d291..56972af13b6f 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -87,13 +87,13 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *chan = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); /* The ADSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; - channels->min = channels->max = 2; + chan->min = chan->max = 2; /* set SSP0 to 16 bit */ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 9cb42ba40c07..0b50b3646d55 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -99,7 +99,7 @@ static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dai_set_bclk_ratio(asoc_rtd_to_codec(rtd, 0), 50); - return ret; + return 0; } static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 1a6961592029..b6e63ea13d64 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -66,6 +66,10 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) int j; int ret = 0; + /* set spk pin by playback only */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return 0; + for_each_rtd_codec_dais(rtd, j, codec_dai) { struct snd_soc_component *component = codec_dai->component; struct snd_soc_dapm_context *dapm = @@ -86,9 +90,6 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - /* Make sure no streams are active before disable pin */ - if (snd_soc_dai_active(codec_dai) != 1) - break; ret = snd_soc_dapm_disable_pin(dapm, pin_name); if (!ret) snd_soc_dapm_sync(dapm); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0129d23694ed..9a6f10ede427 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -119,6 +119,19 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0)), }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Terrador"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98373_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, {} }; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2463d432bf4d..210b66d1f9a2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -123,6 +123,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | SOF_SDW_FOUR_SPK), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | + SOF_SDW_FOUR_SPK), + }, {} }; @@ -132,6 +141,10 @@ static struct snd_soc_codec_conf codec_conf[] = { .dlc = COMP_CODEC_CONF("sdw:0:25d:711:0"), .name_prefix = "rt711", }, + { + .dlc = COMP_CODEC_CONF("sdw:0:25d:711:1"), + .name_prefix = "rt711", + }, /* rt1308 w/ I2S connection */ { .dlc = COMP_CODEC_CONF("i2c-10EC1308:00"), @@ -173,6 +186,23 @@ static struct snd_soc_codec_conf codec_conf[] = { .dlc = COMP_CODEC_CONF("sdw:0:25d:5682:0"), .name_prefix = "rt5682", }, + /* rt5682 on link2 */ + { + .dlc = COMP_CODEC_CONF("sdw:2:25d:5682:0"), + .name_prefix = "rt5682", + }, + { + .dlc = COMP_CODEC_CONF("sdw:1:25d:1316:1"), + .name_prefix = "rt1316-1", + }, + { + .dlc = COMP_CODEC_CONF("sdw:2:25d:1316:1"), + .name_prefix = "rt1316-2", + }, + { + .dlc = COMP_CODEC_CONF("sdw:3:25d:714:1"), + .name_prefix = "rt714", + }, }; static struct snd_soc_dai_link_component dmic_component[] = { @@ -195,6 +225,84 @@ int sdw_startup(struct snd_pcm_substream *substream) return sdw_startup_stream(substream); } +static int sdw_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = asoc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_prepare_stream(sdw_stream); +} + +static int sdw_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + int ret; + + /* Find stream from first CPU DAI */ + dai = asoc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + return PTR_ERR(sdw_stream); + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = sdw_enable_stream(sdw_stream); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sdw_disable_stream(sdw_stream); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret); + + return ret; +} + +static int sdw_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = asoc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); + + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_deprepare_stream(sdw_stream); +} + void sdw_shutdown(struct snd_pcm_substream *substream) { sdw_shutdown_stream(substream); @@ -202,25 +310,37 @@ void sdw_shutdown(struct snd_pcm_substream *substream) static const struct snd_soc_ops sdw_ops = { .startup = sdw_startup, + .prepare = sdw_prepare, + .trigger = sdw_trigger, + .hw_free = sdw_hw_free, .shutdown = sdw_shutdown, }; static struct sof_sdw_codec_info codec_info_list[] = { { - .id = 0x700, + .part_id = 0x700, .direction = {true, true}, .dai_name = "rt700-aif1", .init = sof_sdw_rt700_init, }, { - .id = 0x711, + .part_id = 0x711, + .version_id = 3, + .direction = {true, true}, + .dai_name = "rt711-sdca-aif1", + .init = sof_sdw_rt711_sdca_init, + .exit = sof_sdw_rt711_sdca_exit, + }, + { + .part_id = 0x711, + .version_id = 2, .direction = {true, true}, .dai_name = "rt711-aif1", .init = sof_sdw_rt711_init, .exit = sof_sdw_rt711_exit, }, { - .id = 0x1308, + .part_id = 0x1308, .acpi_id = "10EC1308", .direction = {true, false}, .dai_name = "rt1308-aif", @@ -228,38 +348,57 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt1308_init, }, { - .id = 0x715, + .part_id = 0x1316, + .direction = {true, true}, + .dai_name = "rt1316-aif", + .init = sof_sdw_rt1316_init, + }, + { + .part_id = 0x714, + .direction = {false, true}, + .dai_name = "rt715-aif2", + .init = sof_sdw_rt715_sdca_init, + }, + { + .part_id = 0x715, .direction = {false, true}, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_init, }, { - .id = 0x8373, + .part_id = 0x8373, .direction = {true, true}, .dai_name = "max98373-aif1", .init = sof_sdw_mx8373_init, .codec_card_late_probe = sof_sdw_mx8373_late_probe, }, { - .id = 0x5682, + .part_id = 0x5682, .direction = {true, true}, .dai_name = "rt5682-sdw", .init = sof_sdw_rt5682_init, }, }; -static inline int find_codec_info_part(unsigned int part_id) +static inline int find_codec_info_part(u64 adr) { + unsigned int part_id, sdw_version; int i; + part_id = SDW_PART_ID(adr); + sdw_version = SDW_VERSION(adr); for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (part_id == codec_info_list[i].id) - break; + /* + * A codec info is for all sdw version with the part id if + * version_id is not specified in the codec info. + */ + if (part_id == codec_info_list[i].part_id && + (!codec_info_list[i].version_id || + sdw_version == codec_info_list[i].version_id)) + return i; - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + return -EINVAL; - return i; } static inline int find_codec_info_acpi(const u8 *acpi_id) @@ -305,13 +444,12 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, for (link = links; link->num_adr; link++) { const struct snd_soc_acpi_endpoint *endpoint; - int part_id, codec_index; + int codec_index; int stream; u64 adr; adr = link->adr_d->adr; - part_id = SDW_PART_ID(adr); - codec_index = find_codec_info_part(part_id); + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -439,7 +577,7 @@ static int create_codec_dai_name(struct device *dev, if (!codec[comp_index].name) return -ENOMEM; - codec_index = find_codec_info_part(part_id); + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -463,11 +601,9 @@ static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link, * same group. */ for (i = 0; i < link->num_adr; i++) { - unsigned int part_id; int codec_index; - part_id = SDW_PART_ID(link->adr_d[i].adr); - codec_index = find_codec_info_part(part_id); + codec_index = find_codec_info_part(link->adr_d[i].adr); if (codec_index < 0) return codec_index; @@ -571,7 +707,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index, struct snd_soc_dai_link_component *codecs; int cpu_dai_id[SDW_MAX_CPU_DAIS]; int cpu_dai_num, cpu_dai_index; - unsigned int part_id, group_id; + unsigned int group_id; int codec_idx = 0; int i = 0, j = 0; int codec_index; @@ -613,8 +749,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index, } /* find codec info to create BE DAI */ - part_id = SDW_PART_ID(link->adr_d[0].adr); - codec_index = find_codec_info_part(part_id); + codec_index = find_codec_info_part(link->adr_d[0].adr); if (codec_index < 0) return codec_index; @@ -1032,12 +1167,43 @@ static int mc_probe(struct platform_device *pdev) return ret; } +static int mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct snd_soc_dai_link *link; + int ret; + int i, j; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + if (!codec_info_list[i].exit) + continue; + /* + * We don't need to call .exit function if there is no matched + * dai link found. + */ + for_each_card_prelinks(card, j, link) { + if (!strcmp(link->codecs[0].dai_name, + codec_info_list[i].dai_name)) { + ret = codec_info_list[i].exit(&pdev->dev, link); + if (ret) + dev_warn(&pdev->dev, + "codec exit failed %d\n", + ret); + break; + } + } + } + + return 0; +} + static struct platform_driver sof_sdw_driver = { .driver = { .name = "sof_sdw", .pm = &snd_soc_pm_ops, }, .probe = mc_probe, + .remove = mc_remove, }; module_platform_driver(sof_sdw_driver); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 12e32439ba46..6a5d46589baf 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -51,7 +51,8 @@ enum { #define SOF_SDW_NO_AGGREGATION BIT(12) struct sof_sdw_codec_info { - const int id; + const int part_id; + const int version_id; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool direction[2]; // playback & capture support @@ -63,6 +64,7 @@ struct sof_sdw_codec_info { struct sof_sdw_codec_info *info, bool playback); + int (*exit)(struct device *dev, struct snd_soc_dai_link *dai_link); bool late_probe; int (*codec_card_late_probe)(struct snd_soc_card *card); }; @@ -94,6 +96,13 @@ int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, bool playback); int sof_sdw_rt711_exit(struct device *dev, struct snd_soc_dai_link *dai_link); +/* RT711-SDCA support */ +int sof_sdw_rt711_sdca_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); +int sof_sdw_rt711_sdca_exit(struct device *dev, struct snd_soc_dai_link *dai_link); + /* RT700 support */ int sof_sdw_rt700_init(const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, @@ -108,12 +117,24 @@ int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link, struct sof_sdw_codec_info *info, bool playback); +/* RT1316 support */ +int sof_sdw_rt1316_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + /* RT715 support */ int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, struct sof_sdw_codec_info *info, bool playback); +/* RT715-SDCA support */ +int sof_sdw_rt715_sdca_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + /* MAX98373 support */ int sof_sdw_mx8373_init(const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/intel/boards/sof_sdw_dmic.c index 89b0824b2381..19df0f7a1d85 100644 --- a/sound/soc/intel/boards/sof_sdw_dmic.c +++ b/sound/soc/intel/boards/sof_sdw_dmic.c @@ -7,6 +7,7 @@ #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include "sof_sdw_common.h" static const struct snd_soc_dapm_widget dmic_widgets[] = { diff --git a/sound/soc/intel/boards/sof_sdw_max98373.c b/sound/soc/intel/boards/sof_sdw_max98373.c index 6437872a9b3d..905582aaf58c 100644 --- a/sound/soc/intel/boards/sof_sdw_max98373.c +++ b/sound/soc/intel/boards/sof_sdw_max98373.c @@ -6,8 +6,10 @@ #include <linux/device.h> #include <linux/errno.h> +#include <sound/control.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include "sof_sdw_common.h" #include "sof_maxim_common.h" diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c index 3655e890acec..dba2fd28d77f 100644 --- a/sound/soc/intel/boards/sof_sdw_rt1308.c +++ b/sound/soc/intel/boards/sof_sdw_rt1308.c @@ -7,8 +7,10 @@ #include <linux/device.h> #include <linux/errno.h> +#include <sound/control.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include "sof_sdw_common.h" #include "../../codecs/rt1308.h" diff --git a/sound/soc/intel/boards/sof_sdw_rt1316.c b/sound/soc/intel/boards/sof_sdw_rt1316.c new file mode 100644 index 000000000000..2c566330f236 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt1316.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt1316 - Helpers to handle RT1316 from generic machine driver + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <sound/control.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> +#include "sof_sdw_common.h" + +static const struct snd_soc_dapm_widget rt1316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* + * dapm routes for rt1316 will be registered dynamically according + * to the number of rt1316 used. The first two entries will be registered + * for one codec case, and the last two entries are also registered + * if two 1316s are used. + */ +static const struct snd_soc_dapm_route rt1316_map[] = { + { "Speaker", NULL, "rt1316-1 SPOL" }, + { "Speaker", NULL, "rt1316-1 SPOR" }, + { "Speaker", NULL, "rt1316-2 SPOL" }, + { "Speaker", NULL, "rt1316-2 SPOR" }, +}; + +static const struct snd_kcontrol_new rt1316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int first_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_add_card_controls(card, rt1316_controls, + ARRAY_SIZE(rt1316_controls)); + if (ret) { + dev_err(card->dev, "rt1316 controls addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt1316_widgets, + ARRAY_SIZE(rt1316_widgets)); + if (ret) { + dev_err(card->dev, "rt1316 widgets addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map, 2); + if (ret) + dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); + + return ret; +} + +static int second_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map + 2, 2); + if (ret) + dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); + + return ret; +} + +static int all_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + + ret = first_spk_init(rtd); + if (ret) + return ret; + + return second_spk_init(rtd); +} + +int sof_sdw_rt1316_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* Count amp number and do init on playback link only. */ + if (!playback) + return 0; + + info->amp_num++; + if (info->amp_num == 1) + dai_links->init = first_spk_init; + + if (info->amp_num == 2) { + /* + * if two 1316s are in one dai link, the init function + * in this dai link will be first set for the first speaker, + * and it should be reset to initialize all speakers when + * the second speaker is found. + */ + if (dai_links->init) + dai_links->init = all_spk_init; + else + dai_links->init = second_spk_init; + } + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c index da354ba83939..5fa1a59615b6 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/intel/boards/sof_sdw_rt5682.c @@ -10,8 +10,10 @@ #include <linux/input.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <sound/control.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include <sound/jack.h> #include "sof_sdw_common.h" diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c index 5f50491ba5ee..bff69cfe27f4 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/intel/boards/sof_sdw_rt700.c @@ -8,8 +8,10 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/input.h> +#include <sound/control.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include <sound/jack.h> #include "sof_sdw_common.h" diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index 606009fa3901..04074c09dded 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -10,8 +10,10 @@ #include <linux/input.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <sound/control.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> #include <sound/jack.h> #include "sof_sdw_common.h" diff --git a/sound/soc/intel/boards/sof_sdw_rt711_sdca.c b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c new file mode 100644 index 000000000000..19496f0f9110 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt711_sdca.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/input.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/control.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include "sof_sdw_common.h" + +/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int rt711_sdca_add_codec_device_props(const char *sdw_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *sdw_dev; + int ret; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); + if (!sdw_dev) + return -EPROBE_DEFER; + + if (SOF_RT711_JDSRC(sof_sdw_quirk)) { + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", + SOF_RT711_JDSRC(sof_sdw_quirk)); + } + + ret = device_add_properties(sdw_dev, props); + put_device(sdw_dev); + + return ret; +} + +static const struct snd_soc_dapm_widget rt711_sdca_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route rt711_sdca_map[] = { + /* Headphones */ + { "Headphone", NULL, "rt711 HP" }, + { "rt711 MIC2", NULL, "Headset Mic" }, +}; + +static const struct snd_kcontrol_new rt711_sdca_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static struct snd_soc_jack_pin rt711_sdca_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int rt711_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s hs:rt711-sdca", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_add_card_controls(card, rt711_sdca_controls, + ARRAY_SIZE(rt711_sdca_controls)); + if (ret) { + dev_err(card->dev, "rt711-sdca controls addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt711_sdca_widgets, + ARRAY_SIZE(rt711_sdca_widgets)); + if (ret) { + dev_err(card->dev, "rt711-sdca widgets addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map, + ARRAY_SIZE(rt711_sdca_map)); + + if (ret) { + dev_err(card->dev, "rt711-sdca map addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt711_sdca_jack_pins, + ARRAY_SIZE(rt711_sdca_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +int sof_sdw_rt711_sdca_exit(struct device *dev, struct snd_soc_dai_link *dai_link) +{ + struct device *sdw_dev; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, + dai_link->codecs[0].name); + if (!sdw_dev) + return -EINVAL; + + device_remove_properties(sdw_dev); + put_device(sdw_dev); + + return 0; +} + +int sof_sdw_rt711_sdca_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + int ret; + + /* + * headset should be initialized once. + * Do it with dai link for playback. + */ + if (!playback) + return 0; + + ret = rt711_sdca_add_codec_device_props(dai_links->codecs[0].name); + if (ret < 0) + return ret; + + dai_links->init = rt711_sdca_rtd_init; + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c new file mode 100644 index 000000000000..c056e56a139b --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt715_sdca - Helpers to handle RT715-SDCA from generic machine driver + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "sof_sdw_common.h" + +static int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:rt715-sdca", + card->components); + if (!card->components) + return -ENOMEM; + + return 0; +} + +int sof_sdw_rt715_sdca_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* + * DAI ID is fixed at SDW_DMIC_DAI_ID for 715-SDCA to + * keep sdw DMIC and HDMI setting static in UCM + */ + if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) + dai_links->id = SDW_DMIC_DAI_ID; + + dai_links->init = rt715_sdca_rtd_init; + + return 0; +} diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index dee1f0fa998b..ec01884ef93d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -112,15 +112,15 @@ static const struct snd_soc_acpi_link_adr cml_rvp[] = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000010025D071100, + .adr = 0x000020025D071100, .num_endpoints = 1, .endpoints = &single_endpoint, } }; -static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { +static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { { - .adr = 0x000110025D130800, + .adr = 0x000120025D130800, .num_endpoints = 1, .endpoints = &single_endpoint, } @@ -128,7 +128,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000110025D130800, + .adr = 0x000120025D130800, .num_endpoints = 1, .endpoints = &spk_l_endpoint, } @@ -136,7 +136,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000210025D130800, + .adr = 0x000220025D130800, .num_endpoints = 1, .endpoints = &spk_r_endpoint, } @@ -144,7 +144,39 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000310025D071500, + .adr = 0x000320025D071500, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { + { + .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { + { + .adr = 0x000230025D131601, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { + { + .adr = 0x000330025D071401, .num_endpoints = 1, .endpoints = &single_endpoint, } @@ -182,8 +214,8 @@ static const struct snd_soc_acpi_link_adr cml_3_in_1_mono_amp[] = { }, { .mask = BIT(1), - .num_adr = ARRAY_SIZE(rt1308_1_adr), - .adr_d = rt1308_1_adr, + .num_adr = ARRAY_SIZE(rt1308_1_single_adr), + .adr_d = rt1308_1_single_adr, }, { .mask = BIT(3), @@ -193,6 +225,30 @@ static const struct snd_soc_acpi_link_adr cml_3_in_1_mono_amp[] = { {} }; +static const struct snd_soc_acpi_link_adr cml_3_in_1_sdca[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group1_adr), + .adr_d = rt1316_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group1_adr), + .adr_d = rt1316_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt714_3_adr), + .adr_d = rt714_3_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { { .link_mask = 0xF, /* 4 active links required */ @@ -202,6 +258,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { .sof_tplg_filename = "sof-cml-rt711-rt1308-rt715.tplg", }, { + .link_mask = 0xF, /* 4 active links required */ + .links = cml_3_in_1_sdca, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt711-rt1316-rt714.tplg", + }, + { /* * link_mask should be 0xB, but all links are enabled by BIOS. * This entry will be selected if there is no rt1308 exposed diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 6a0bcc1a8429..7d61e0da808b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -27,8 +27,39 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = { + { + .adr = 0x000220025D568200, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_link_adr up_extreme_rt5682_2[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt5682_2_adr), + .adr_d = rt5682_2_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[] = { - {}, + { + .link_mask = BIT(2), + .links = up_extreme_rt5682_2, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl-rt5682-sdw2.tplg" + }, + {} }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 6927bbbc66fc..ebe13197410f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -73,7 +73,7 @@ static const struct snd_soc_acpi_link_adr icl_rvp[] = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000010025D071100, + .adr = 0x000020025D071100, .num_endpoints = 1, .endpoints = &single_endpoint, } @@ -81,7 +81,7 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { { - .adr = 0x000110025D130800, + .adr = 0x000120025D130800, .num_endpoints = 1, .endpoints = &single_endpoint, } @@ -89,7 +89,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000110025D130800, + .adr = 0x000120025D130800, .num_endpoints = 1, .endpoints = &spk_l_endpoint, } @@ -97,7 +97,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000210025D130800, + .adr = 0x000220025D130800, .num_endpoints = 1, .endpoints = &spk_r_endpoint, } @@ -105,7 +105,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000310025D071500, + .adr = 0x000320025D071500, .num_endpoints = 1, .endpoints = &single_endpoint, } 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 2ffa608d987d..6816847bee40 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -37,13 +37,13 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000010025D071100, + .adr = 0x000020025D071100, .num_endpoints = 1, .endpoints = &single_endpoint, } }; -static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { +static const struct snd_soc_acpi_adr_device rt1308_1_dual_adr[] = { { .adr = 0x000120025D130800, .num_endpoints = 1, @@ -56,6 +56,38 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { + { + .adr = 0x000120025D130800, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { + { + .adr = 0x000120025D130800, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { + { + .adr = 0x000220025D130800, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { + { + .adr = 0x000320025D071500, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + static const struct snd_soc_acpi_adr_device mx8373_1_adr[] = { { .adr = 0x000123019F837300, @@ -77,6 +109,38 @@ static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { + { + .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { + { + .adr = 0x000230025D131601, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + } +}; + +static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { + { + .adr = 0x000330025D071401, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + static const struct snd_soc_acpi_link_adr tgl_i2s_rt1308[] = { { .mask = BIT(0), @@ -94,8 +158,8 @@ static const struct snd_soc_acpi_link_adr tgl_rvp[] = { }, { .mask = BIT(1), - .num_adr = ARRAY_SIZE(rt1308_1_adr), - .adr_d = rt1308_1_adr, + .num_adr = ARRAY_SIZE(rt1308_1_dual_adr), + .adr_d = rt1308_1_dual_adr, }, {} }; @@ -114,6 +178,73 @@ static const struct snd_soc_acpi_link_adr tgl_chromebook_base[] = { {} }; +static const struct snd_soc_acpi_link_adr tgl_3_in_1_default[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr_d = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_group1_adr), + .adr_d = rt1308_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1308_2_group1_adr), + .adr_d = rt1308_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr_d = rt715_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr tgl_3_in_1_mono_amp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr_d = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_single_adr), + .adr_d = rt1308_1_single_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr_d = rt715_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group1_adr), + .adr_d = rt1316_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group1_adr), + .adr_d = rt1316_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt714_3_adr), + .adr_d = rt714_3_adr, + }, + {} +}; + static struct snd_soc_acpi_codecs tgl_max98373_amp = { .num_codecs = 1, .codecs = {"MX98373"} @@ -151,6 +282,32 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_default, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + }, + { + /* + * link_mask should be 0xB, but all links are enabled by BIOS. + * This entry will be selected if there is no rt1308 exposed + * on link2 since it will fail to match the above entry. + */ + .link_mask = 0xF, + .links = tgl_3_in_1_mono_amp, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = 0xF, /* 4 active links required */ + .links = tgl_3_in_1_sdca, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1316-rt714.tplg", + }, + { .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */ .links = tgl_rvp, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 3d8765ce3e0d..9a760123b46f 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -344,7 +344,7 @@ void sst_fw_unload(struct sst_fw *sst_fw); /* Create/Free firmware modules */ struct sst_module *sst_module_new(struct sst_fw *sst_fw, struct sst_module_template *template, void *private); -void sst_module_free(struct sst_module *module); +void sst_module_free(struct sst_module *sst_module); struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); int sst_module_alloc_blocks(struct sst_module *module); int sst_module_free_blocks(struct sst_module *module); diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 604a80c5859b..d55014587415 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -268,15 +268,14 @@ void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp); /* Mailbox management */ -int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset, +int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, u32 outbox_offset, size_t outbox_size); -void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes); -void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); -void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); -void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); -void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); -int sst_dsp_register_poll(struct sst_dsp *dsp, u32 offset, u32 mask, - u32 expected_value, u32 timeout, char *operation); +void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes); +void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes); +void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes); +void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes); +int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, + u32 target, u32 time, char *operation); /* Debug */ void sst_dsp_dump(struct sst_dsp *sst); diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 0594f89ea7f2..1189ec37134e 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -130,7 +130,7 @@ static void block_list_remove(struct sst_dsp *dsp, err = block->ops->disable(block); if (err < 0) dev_err(dsp->dev, - "error: cant disable block %d:%d\n", + "error: can't disable block %d:%d\n", block->type, block->index); } } @@ -158,7 +158,7 @@ static int block_list_prepare(struct sst_dsp *dsp, ret = block->ops->enable(block); if (ret < 0) { dev_err(dsp->dev, - "error: cant disable block %d:%d\n", + "error: can't disable block %d:%d\n", block->type, block->index); goto err; } diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 0ff89ea96ccf..95a50265dff6 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -427,7 +427,7 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) u32 offset; u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; char *tmp[5], *pinfo; - int i = 0; + int i; offset = (header & 0x1FFFFFFF) << 3; @@ -1507,7 +1507,7 @@ static int sst_hsw_dx_state_dump(struct sst_hsw *hsw) ret = sst_dsp_dma_get_channel(sst, 0); if (ret < 0) { - dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); + dev_err(hsw->dev, "error: can't allocate dma channel %d\n", ret); return ret; } @@ -1587,7 +1587,7 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw) ret = sst_dsp_dma_get_channel(dsp, 0); if (ret < 0) { - dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); + dev_err(hsw->dev, "error: can't allocate dma channel %d\n", ret); return ret; } @@ -1616,7 +1616,7 @@ static int sst_hsw_dsp_restore(struct sst_hsw *hsw) ret = sst_dsp_dma_get_channel(dsp, 0); if (ret < 0) { - dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); + dev_err(hsw->dev, "error: can't allocate dma channel %d\n", ret); return ret; } @@ -1789,7 +1789,7 @@ int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf) int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf) { - u8 id = 0; + u8 id; /* read the first matching line from param buffer */ while (hsw->param_idx_r < WAVES_PARAM_LINES) { diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.h b/sound/soc/intel/haswell/sst-haswell-ipc.h index fdc70c77e688..646dbbba327b 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.h +++ b/sound/soc/intel/haswell/sst-haswell-ipc.h @@ -414,7 +414,7 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, /* Stream API */ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, - u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), + u32 (*notify_position)(struct sst_hsw_stream *stream, void *data), void *data); int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream); diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index 16f9fc4c663d..f54b710ee1c2 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -8,6 +8,8 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -17,7 +19,7 @@ #define PERIODS_MAX 48 #define PERIOD_BYTES_MIN 4096 #define BUFFER_BYTES_MAX (PERIODS_MAX * PERIOD_BYTES_MIN) -#define TDM_OPERATION 1 +#define TDM_OPERATION 5 #define I2S_OPERATION 0 #define DATA_WIDTH_CONFIG_BIT 6 #define TDM_CHANNEL_CONFIG_BIT 3 @@ -82,19 +84,25 @@ static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s, { unsigned int period_pos = rx_ptr % runtime->period_size; void __iomem *i2s_base = kmb_i2s->i2s_base; + int chan = kmb_i2s->config.chan_nr; void *buf = runtime->dma_area; - int i; + int i, j; /* KMB i2s uses two separate L/R FIFO */ for (i = 0; i < kmb_i2s->fifo_th; i++) { - if (kmb_i2s->config.data_width == 16) { - ((u16(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); - ((u16(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); - } else { - ((u32(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); - ((u32(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); + for (j = 0; j < chan / 2; j++) { + if (kmb_i2s->config.data_width == 16) { + ((u16 *)buf)[rx_ptr * chan + (j * 2)] = + readl(i2s_base + LRBR_LTHR(j)); + ((u16 *)buf)[rx_ptr * chan + ((j * 2) + 1)] = + readl(i2s_base + RRBR_RTHR(j)); + } else { + ((u32 *)buf)[rx_ptr * chan + (j * 2)] = + readl(i2s_base + LRBR_LTHR(j)); + ((u32 *)buf)[rx_ptr * chan + ((j * 2) + 1)] = + readl(i2s_base + RRBR_RTHR(j)); + } } - period_pos++; if (++rx_ptr >= runtime->buffer_size) @@ -238,6 +246,7 @@ static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id) struct kmb_i2s_info *kmb_i2s = dev_id; struct i2s_clk_config_data *config = &kmb_i2s->config; irqreturn_t ret = IRQ_NONE; + u32 tx_enabled = 0; u32 isr[4]; int i; @@ -246,22 +255,45 @@ static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id) kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK); kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE); + /* Only check TX interrupt if TX is active */ + tx_enabled = readl(kmb_i2s->i2s_base + ITER); + + /* + * Data available. Retrieve samples from FIFO + */ + + /* + * 8 channel audio will have isr[0..2] triggered, + * reading the specific isr based on the audio configuration, + * to avoid reading the buffers too early. + */ + switch (config->chan_nr) { + case 2: + if (isr[0] & ISR_RXDA) + kmb_pcm_operation(kmb_i2s, false); + ret = IRQ_HANDLED; + break; + case 4: + if (isr[1] & ISR_RXDA) + kmb_pcm_operation(kmb_i2s, false); + ret = IRQ_HANDLED; + break; + case 8: + if (isr[3] & ISR_RXDA) + kmb_pcm_operation(kmb_i2s, false); + ret = IRQ_HANDLED; + break; + } for (i = 0; i < config->chan_nr / 2; i++) { /* * Check if TX fifo is empty. If empty fill FIFO with samples */ - if ((isr[i] & ISR_TXFE)) { + if ((isr[i] & ISR_TXFE) && tx_enabled) { kmb_pcm_operation(kmb_i2s, true); ret = IRQ_HANDLED; } - /* - * Data available. Retrieve samples from FIFO - */ - if ((isr[i] & ISR_RXDA)) { - kmb_pcm_operation(kmb_i2s, false); - ret = IRQ_HANDLED; - } + /* Error Handling: TX */ if (isr[i] & ISR_TXFO) { dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i); @@ -445,7 +477,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, { struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); struct i2s_clk_config_data *config = &kmb_i2s->config; - u32 register_val, write_val; + u32 write_val; int ret; switch (params_format(hw_params)) { @@ -472,16 +504,34 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, config->chan_nr = params_channels(hw_params); switch (config->chan_nr) { - /* TODO: This switch case will handle up to TDM8 in the near future */ - case TWO_CHANNEL_SUPPORT: + case 8: + case 4: + /* + * Platform is not capable of providing clocks for + * multi channel audio + */ + if (kmb_i2s->master) + return -EINVAL; + write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | (config->data_width << DATA_WIDTH_CONFIG_BIT) | - MASTER_MODE | I2S_OPERATION; + TDM_OPERATION; writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0); + break; + case 2: + /* + * Platform is only capable of providing clocks need for + * 2 channel master mode + */ + if (!(kmb_i2s->master)) + return -EINVAL; + + write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | + (config->data_width << DATA_WIDTH_CONFIG_BIT) | + MASTER_MODE | I2S_OPERATION; - register_val = readl(kmb_i2s->pss_base + I2S_GEN_CFG_0); - dev_dbg(kmb_i2s->dev, "pss register = 0x%X", register_val); + writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0); break; default: dev_dbg(kmb_i2s->dev, "channel not supported\n"); @@ -529,9 +579,9 @@ static struct snd_soc_dai_ops kmb_dai_ops = { .set_fmt = kmb_set_dai_fmt, }; -static struct snd_soc_dai_driver intel_kmb_platform_dai[] = { +static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = { { - .name = "kmb-plat-dai", + .name = "intel_kmb_i2s", .playback = { .channels_min = 2, .channels_max = 2, @@ -547,10 +597,6 @@ static struct snd_soc_dai_driver intel_kmb_platform_dai[] = { .capture = { .channels_min = 2, .channels_max = 2, - /* - * .channels_max will be overwritten - * if provided by Device Tree - */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000, @@ -564,9 +610,35 @@ static struct snd_soc_dai_driver intel_kmb_platform_dai[] = { }, }; +static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = { + { + .name = "intel_kmb_tdm", + .capture = { + .channels_min = 4, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .formats = (SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S16_LE), + }, + .ops = &kmb_dai_ops, + }, +}; + +static const struct of_device_id kmb_plat_of_match[] = { + { .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai}, + { .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai}, + {} +}; + static int kmb_plat_dai_probe(struct platform_device *pdev) { struct snd_soc_dai_driver *kmb_i2s_dai; + const struct of_device_id *match; struct device *dev = &pdev->dev; struct kmb_i2s_info *kmb_i2s; int ret, irq; @@ -580,7 +652,12 @@ static int kmb_plat_dai_probe(struct platform_device *pdev) if (!kmb_i2s_dai) return -ENOMEM; - kmb_i2s_dai->ops = &kmb_dai_ops; + match = of_match_device(kmb_plat_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + kmb_i2s_dai = (struct snd_soc_dai_driver *) match->data; /* Prepare the related clocks */ kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk"); @@ -630,8 +707,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev) kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2; ret = devm_snd_soc_register_component(dev, &kmb_component, - intel_kmb_platform_dai, - ARRAY_SIZE(intel_kmb_platform_dai)); + kmb_i2s_dai, 1); if (ret) { dev_err(dev, "not able to register dai\n"); return ret; @@ -646,11 +722,6 @@ static int kmb_plat_dai_probe(struct platform_device *pdev) return ret; } -static const struct of_device_id kmb_plat_of_match[] = { - { .compatible = "intel,keembay-i2s", }, - {} -}; - static struct platform_driver kmb_plat_dai_driver = { .driver = { .name = "kmb-plat-dai", diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h index 7bd4d2a8fdfa..d3cf4bd1a070 100644 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ b/sound/soc/intel/skylake/cnl-sst-dsp.h @@ -82,8 +82,8 @@ struct sst_generic_ipc; #define CNL_ADSPCS_CPA_SHIFT 24 #define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT) -int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core); -int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core); +int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); +int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id); void cnl_dsp_free(struct sst_dsp *dsp); diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index d9c8f5cb389e..87c891c46291 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -200,7 +200,7 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, struct skl_ssp_clk *sclk, *sclkfs; struct nhlt_fmt_cfg *fmt_cfg; struct wav_fmt_ext *wav_fmt; - unsigned long rate = 0; + unsigned long rate; bool present = false; int rate_index = 0; u16 channels, bps; diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 36f697c61074..b91f7a652a2b 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -245,7 +245,7 @@ static int skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size, bool wait) { - int ret = 0; + int ret; bool start = true; unsigned int excess_bytes; u32 size; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 08ac31778325..aaaab3b3ec42 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -107,12 +107,12 @@ struct skl_ipc_d0ix_msg { irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); -int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, +int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); -int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); +int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); -int skl_ipc_set_pipeline_state(struct sst_generic_ipc *sst_ipc, +int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, u8 instance_id, enum skl_ipc_pipeline_state state); int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, @@ -120,10 +120,10 @@ int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); -int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc, +int skl_ipc_init_instance(struct sst_generic_ipc *ipc, struct skl_ipc_init_instance_msg *msg, void *param_data); -int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, +int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, struct skl_ipc_bind_unbind_msg *msg); int skl_ipc_load_modules(struct sst_generic_ipc *ipc, @@ -150,12 +150,12 @@ int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); -void skl_ipc_int_enable(struct sst_dsp *dsp); +void skl_ipc_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); -void skl_ipc_int_disable(struct sst_dsp *dsp); +void skl_ipc_int_disable(struct sst_dsp *ctx); -bool skl_ipc_int_status(struct sst_dsp *dsp); +bool skl_ipc_int_status(struct sst_dsp *ctx); void skl_ipc_free(struct sst_generic_ipc *ipc); int skl_ipc_init(struct device *dev, struct skl_dev *skl); void skl_clear_module_cnt(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index b233f89517c1..57ea815d3f04 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -237,7 +237,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, struct uuid_module *module; struct firmware stripped_fw; unsigned int safe_file; - int ret = 0; + int ret; /* Get the FW pointer to derive ADSP header */ stripped_fw.data = fw->data; diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 61a8e4756a2b..00a97cea58b4 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -354,7 +354,7 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, /* * if bytes_left > 0 then wait for BDL complete interrupt and * copy the next chunk till bytes_left is 0. if bytes_left is - * is zero, then wait for load module IPC reply + * zero, then wait for load module IPC reply */ while (bytes_left > 0) { curr_pos = size - bytes_left; diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b7d2d97d12a7..40bee10b0c65 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -550,8 +550,8 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { int ret = 0; - struct skl_pipe_module *w_module = NULL; - struct skl_module_cfg *mconfig = NULL; + struct skl_pipe_module *w_module; + struct skl_module_cfg *mconfig; list_for_each_entry(w_module, &pipe->w_list, node) { guid_t *uuid_mod; @@ -1893,7 +1893,7 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; int ret = -EIO; snd_soc_dapm_widget_for_each_sink_path(w, p) { @@ -2876,7 +2876,7 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, struct skl_module_cfg *mconfig) { struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size = 0, block_type, off = 0; + int num_blocks, block_size, block_type, off = 0; char *data; int ret; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 5e93ad85e06d..fb011862fb24 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -453,7 +453,7 @@ int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, struct skl_pipe_params *params, int stream); int skl_tplg_init(struct snd_soc_component *component, - struct hdac_bus *ebus); + struct hdac_bus *bus); void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus); struct skl_module_cfg *skl_tplg_fe_get_cpr_module( @@ -476,13 +476,13 @@ int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe); int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *module_config); +int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig); int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_module, struct skl_module_cfg *dst_module); + *src_mcfg, struct skl_module_cfg *dst_mcfg); int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_module, struct skl_module_cfg *dst_module); + *src_mcfg, struct skl_module_cfg *dst_mcfg); int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 63182bfd7941..ea00cf61d1a8 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -925,7 +925,7 @@ static int skl_first_init(struct hdac_bus *bus) /* check if PPCAP exists */ if (!bus->ppcap) { - dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n"); + dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n"); return -ENODEV; } @@ -986,7 +986,7 @@ static int skl_probe(struct pci_dev *pci, return -ENODEV; break; case SND_SKL_PCI_BIND_LEGACY: - dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n"); + dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n"); return -ENODEV; case SND_SKL_PCI_BIND_ASOC: dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n"); @@ -1021,7 +1021,7 @@ static int skl_probe(struct pci_dev *pci, err = -ENODEV; goto out_free; #else - dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n"); + dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n"); #endif } else { diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 26057f38a014..857ea17e3c9f 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -166,7 +166,7 @@ int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl_dev *skl, u32 instance, - u8 link_type, u8 s_fmt, u8 no_ch, + u8 link_type, u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn, u8 dev_type); int skl_nhlt_update_topology_bin(struct skl_dev *skl); diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index f7e8e9da68a0..cab7fa2851aa 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -398,7 +398,7 @@ void axg_tdm_stream_free(struct axg_tdm_stream *ts) /* * If the list is not empty, it would mean that one of the formatter * widget is still powered and attached to the interface while we - * we are removing the TDM DAI. It should not be possible + * are removing the TDM DAI. It should not be possible */ WARN_ON(!list_empty(&ts->formatter_list)); mutex_destroy(&ts->lock); diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 6a64ac01b5ca..300ac8be46ef 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -254,37 +254,6 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, return func(card, propname); } -static int meson_card_add_aux_devices(struct snd_soc_card *card) -{ - struct device_node *node = card->dev->of_node; - struct snd_soc_aux_dev *aux; - int num, i; - - num = of_count_phandle_with_args(node, "audio-aux-devs", NULL); - if (num == -ENOENT) { - return 0; - } else if (num < 0) { - dev_err(card->dev, "error getting auxiliary devices: %d\n", - num); - return num; - } - - aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL); - if (!aux) - return -ENOMEM; - card->aux_dev = aux; - card->num_aux_devs = num; - - for_each_card_pre_auxs(card, i, aux) { - aux->dlc.of_node = - of_parse_phandle(node, "audio-aux-devs", i); - if (!aux->dlc.of_node) - return -EINVAL; - } - - return 0; -} - static void meson_card_clean_references(struct meson_card *priv) { struct snd_soc_card *card = &priv->card; @@ -357,7 +326,7 @@ int meson_card_probe(struct platform_device *pdev) if (ret) goto out_err; - ret = meson_card_add_aux_devices(&priv->card); + ret = snd_soc_of_parse_aux_devs(&priv->card, "audio-aux-devs"); if (ret) goto out_err; diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 5d6b2466a2f2..a607ace8b089 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -1,11 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only -config SND_SOC_QCOM +menuconfig SND_SOC_QCOM tristate "ASoC support for QCOM platforms" depends on ARCH_QCOM || COMPILE_TEST help Say Y or M if you want to add support to use audio devices in Qualcomm Technologies SOC-based platforms. +if SND_SOC_QCOM + config SND_SOC_LPASS_CPU tristate select REGMAP_MMIO @@ -24,9 +26,13 @@ config SND_SOC_LPASS_APQ8016 select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM +config SND_SOC_LPASS_SC7180 + tristate + select SND_SOC_LPASS_CPU + select SND_SOC_LPASS_PLATFORM + config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help @@ -35,7 +41,6 @@ config SND_SOC_STORM config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM select SND_SOC_LPASS_APQ8016 select SND_SOC_QCOM_COMMON help @@ -110,3 +115,5 @@ config SND_SOC_SDM845 To add support for audio on Qualcomm Technologies Inc. SDM845 SoC-based systems. Say Y if you want to use audio device on this SoCs. + +endif #SND_SOC_QCOM diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 41b2c7a23a4d..7972c9479ab0 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -4,11 +4,13 @@ snd-soc-lpass-cpu-objs := lpass-cpu.o snd-soc-lpass-platform-objs := lpass-platform.o snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o snd-soc-lpass-apq8016-objs := lpass-apq8016.o +snd-soc-lpass-sc7180-objs := lpass-sc7180.o obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o +obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o # Machine snd-soc-storm-objs := storm.o diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 5194d90ddb96..fe6e778c31c0 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -39,6 +39,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return ret; } + ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); + if (ret) + return ret; + /* Populate links */ num_links = of_get_child_count(dev->of_node); diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index b3610d05b651..5c8ae225cd5d 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -161,44 +161,67 @@ static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) static int apq8016_lpass_init(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); + struct lpass_variant *variant = drvdata->variant; struct device *dev = &pdev->dev; - int ret; + int ret, i; - drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk"); - if (IS_ERR(drvdata->pcnoc_mport_clk)) { - dev_err(dev, "error getting pcnoc-mport-clk: %ld\n", - PTR_ERR(drvdata->pcnoc_mport_clk)); - return PTR_ERR(drvdata->pcnoc_mport_clk); + + drvdata->clks = devm_kcalloc(dev, variant->num_clks, + sizeof(*drvdata->clks), GFP_KERNEL); + if (!drvdata->clks) + return -ENOMEM; + drvdata->num_clks = variant->num_clks; + + for (i = 0; i < drvdata->num_clks; i++) + drvdata->clks[i].id = variant->clk_name[i]; + + ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks); + if (ret) { + dev_err(dev, "Failed to get clocks %d\n", ret); + return ret; } - ret = clk_prepare_enable(drvdata->pcnoc_mport_clk); + ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); if (ret) { - dev_err(dev, "Error enabling pcnoc-mport-clk: %d\n", ret); + dev_err(dev, "apq8016 clk_enable failed\n"); return ret; } - drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk"); - if (IS_ERR(drvdata->pcnoc_sway_clk)) { - dev_err(dev, "error getting pcnoc-sway-clk: %ld\n", - PTR_ERR(drvdata->pcnoc_sway_clk)); - return PTR_ERR(drvdata->pcnoc_sway_clk); + drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk"); + if (IS_ERR(drvdata->ahbix_clk)) { + dev_err(dev, "error getting ahbix-clk: %ld\n", + PTR_ERR(drvdata->ahbix_clk)); + ret = PTR_ERR(drvdata->ahbix_clk); + goto err_ahbix_clk; } - ret = clk_prepare_enable(drvdata->pcnoc_sway_clk); + ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY); if (ret) { - dev_err(dev, "Error enabling pcnoc_sway_clk: %d\n", ret); - return ret; + dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret); + goto err_ahbix_clk; + } + dev_dbg(dev, "set ahbix_clk rate to %lu\n", + clk_get_rate(drvdata->ahbix_clk)); + + ret = clk_prepare_enable(drvdata->ahbix_clk); + if (ret) { + dev_err(dev, "error enabling ahbix_clk: %d\n", ret); + goto err_ahbix_clk; } return 0; + +err_ahbix_clk: + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); + return ret; } static int apq8016_lpass_exit(struct platform_device *pdev) { struct lpass_data *drvdata = platform_get_drvdata(pdev); - clk_disable_unprepare(drvdata->pcnoc_mport_clk); - clk_disable_unprepare(drvdata->pcnoc_sway_clk); + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); + clk_disable_unprepare(drvdata->ahbix_clk); return 0; } @@ -219,6 +242,35 @@ static struct lpass_variant apq8016_data = { .wrdma_reg_stride = 0x1000, .wrdma_channel_start = 5, .wrdma_channels = 2, + .loopback = REG_FIELD_ID(0x1000, 15, 15, 4, 0x1000), + .spken = REG_FIELD_ID(0x1000, 14, 14, 4, 0x1000), + .spkmode = REG_FIELD_ID(0x1000, 10, 13, 4, 0x1000), + .spkmono = REG_FIELD_ID(0x1000, 9, 9, 4, 0x1000), + .micen = REG_FIELD_ID(0x1000, 8, 8, 4, 0x1000), + .micmode = REG_FIELD_ID(0x1000, 4, 7, 4, 0x1000), + .micmono = REG_FIELD_ID(0x1000, 3, 3, 4, 0x1000), + .wssrc = REG_FIELD_ID(0x1000, 2, 2, 4, 0x1000), + .bitwidth = REG_FIELD_ID(0x1000, 0, 0, 4, 0x1000), + + .rdma_dyncclk = REG_FIELD_ID(0x8400, 12, 12, 2, 0x1000), + .rdma_bursten = REG_FIELD_ID(0x8400, 11, 11, 2, 0x1000), + .rdma_wpscnt = REG_FIELD_ID(0x8400, 8, 10, 2, 0x1000), + .rdma_intf = REG_FIELD_ID(0x8400, 4, 7, 2, 0x1000), + .rdma_fifowm = REG_FIELD_ID(0x8400, 1, 3, 2, 0x1000), + .rdma_enable = REG_FIELD_ID(0x8400, 0, 0, 2, 0x1000), + + .wrdma_dyncclk = REG_FIELD_ID(0xB000, 12, 12, 2, 0x1000), + .wrdma_bursten = REG_FIELD_ID(0xB000, 11, 11, 2, 0x1000), + .wrdma_wpscnt = REG_FIELD_ID(0xB000, 8, 10, 2, 0x1000), + .wrdma_intf = REG_FIELD_ID(0xB000, 4, 7, 2, 0x1000), + .wrdma_fifowm = REG_FIELD_ID(0xB000, 1, 3, 2, 0x1000), + .wrdma_enable = REG_FIELD_ID(0xB000, 0, 0, 2, 0x1000), + + .clk_name = (const char*[]) { + "pcnoc-mport-clk", + "pcnoc-sway-clk", + }, + .num_clks = 2, .dai_driver = apq8016_lpass_cpu_dai_driver, .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), .dai_osr_clk_names = (const char *[]) { diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e00a4af29c13..1ee6d8b3f550 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -29,6 +29,32 @@ #define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0) #define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0) +static int lpass_cpu_init_i2sctl_bitfields(struct device *dev, + struct lpaif_i2sctl *i2sctl, struct regmap *map) +{ + struct lpass_data *drvdata = dev_get_drvdata(dev); + struct lpass_variant *v = drvdata->variant; + + i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback); + i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken); + i2sctl->spkmode = devm_regmap_field_alloc(dev, map, v->spkmode); + i2sctl->spkmono = devm_regmap_field_alloc(dev, map, v->spkmono); + i2sctl->micen = devm_regmap_field_alloc(dev, map, v->micen); + i2sctl->micmode = devm_regmap_field_alloc(dev, map, v->micmode); + i2sctl->micmono = devm_regmap_field_alloc(dev, map, v->micmono); + i2sctl->wssrc = devm_regmap_field_alloc(dev, map, v->wssrc); + i2sctl->bitwidth = devm_regmap_field_alloc(dev, map, v->bitwidth); + + if (IS_ERR(i2sctl->loopback) || IS_ERR(i2sctl->spken) || + IS_ERR(i2sctl->spkmode) || IS_ERR(i2sctl->spkmono) || + IS_ERR(i2sctl->micen) || IS_ERR(i2sctl->micmode) || + IS_ERR(i2sctl->micmono) || IS_ERR(i2sctl->wssrc) || + IS_ERR(i2sctl->bitwidth)) + return -EINVAL; + + return 0; +} + static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { @@ -79,6 +105,8 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + struct lpaif_i2sctl *i2sctl = drvdata->i2sctl; + unsigned int id = dai->driver->id; snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); @@ -92,28 +120,45 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return bitwidth; } - regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | - LPAIF_I2SCTL_WSSRC_INTERNAL; + ret = regmap_fields_write(i2sctl->loopback, id, + LPAIF_I2SCTL_LOOPBACK_DISABLE); + if (ret) { + dev_err(dai->dev, "error updating loopback field: %d\n", ret); + return ret; + } + + ret = regmap_fields_write(i2sctl->wssrc, id, + LPAIF_I2SCTL_WSSRC_INTERNAL); + if (ret) { + dev_err(dai->dev, "error updating wssrc field: %d\n", ret); + return ret; + } switch (bitwidth) { case 16: - regval |= LPAIF_I2SCTL_BITWIDTH_16; + regval = LPAIF_I2SCTL_BITWIDTH_16; break; case 24: - regval |= LPAIF_I2SCTL_BITWIDTH_24; + regval = LPAIF_I2SCTL_BITWIDTH_24; break; case 32: - regval |= LPAIF_I2SCTL_BITWIDTH_32; + regval = LPAIF_I2SCTL_BITWIDTH_32; break; default: dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth); return -EINVAL; } + ret = regmap_fields_write(i2sctl->bitwidth, id, regval); + if (ret) { + dev_err(dai->dev, "error updating bitwidth field: %d\n", ret); + return ret; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - mode = drvdata->mi2s_playback_sd_mode[dai->driver->id]; + mode = drvdata->mi2s_playback_sd_mode[id]; else - mode = drvdata->mi2s_capture_sd_mode[dai->driver->id]; + mode = drvdata->mi2s_capture_sd_mode[id]; if (!mode) { dev_err(dai->dev, "no line is assigned\n"); @@ -175,30 +220,42 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regval |= LPAIF_I2SCTL_SPKMODE(mode); - + ret = regmap_fields_write(i2sctl->spkmode, id, + LPAIF_I2SCTL_SPKMODE(mode)); + if (ret) { + dev_err(dai->dev, "error writing to i2sctl spkr mode: %d\n", + ret); + return ret; + } if (channels >= 2) - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + ret = regmap_fields_write(i2sctl->spkmono, id, + LPAIF_I2SCTL_SPKMONO_STEREO); else - regval |= LPAIF_I2SCTL_SPKMONO_MONO; + ret = regmap_fields_write(i2sctl->spkmono, id, + LPAIF_I2SCTL_SPKMONO_MONO); } else { - regval |= LPAIF_I2SCTL_MICMODE(mode); - + ret = regmap_fields_write(i2sctl->micmode, id, + LPAIF_I2SCTL_MICMODE(mode)); + if (ret) { + dev_err(dai->dev, "error writing to i2sctl mic mode: %d\n", + ret); + return ret; + } if (channels >= 2) - regval |= LPAIF_I2SCTL_MICMONO_STEREO; + ret = regmap_fields_write(i2sctl->micmono, id, + LPAIF_I2SCTL_MICMONO_STEREO); else - regval |= LPAIF_I2SCTL_MICMONO_MONO; + ret = regmap_fields_write(i2sctl->micmono, id, + LPAIF_I2SCTL_MICMONO_MONO); } - ret = regmap_write(drvdata->lpaif_map, - LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - regval); if (ret) { - dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); + dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n", + ret); return ret; } - ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id], + ret = clk_set_rate(drvdata->mi2s_bit_clk[id], rate * bitwidth * 2); if (ret) { dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n", @@ -209,41 +266,24 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return 0; } -static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); - int ret; - - ret = regmap_write(drvdata->lpaif_map, - LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - 0); - if (ret) - dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); - - return ret; -} - static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + struct lpaif_i2sctl *i2sctl = drvdata->i2sctl; + unsigned int id = dai->driver->id; int ret; - unsigned int val, mask; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val = LPAIF_I2SCTL_SPKEN_ENABLE; - mask = LPAIF_I2SCTL_SPKEN_MASK; - } else { - val = LPAIF_I2SCTL_MICEN_ENABLE; - mask = LPAIF_I2SCTL_MICEN_MASK; + ret = regmap_fields_write(i2sctl->spken, id, + LPAIF_I2SCTL_SPKEN_ENABLE); + } else { + ret = regmap_fields_write(i2sctl->micen, id, + LPAIF_I2SCTL_MICEN_ENABLE); } - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - mask, val); if (ret) - dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); + dev_err(dai->dev, "error writing to i2sctl enable: %d\n", ret); return ret; } @@ -252,25 +292,21 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + struct lpaif_i2sctl *i2sctl = drvdata->i2sctl; + unsigned int id = dai->driver->id; int ret = -EINVAL; - unsigned int val, mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val = LPAIF_I2SCTL_SPKEN_ENABLE; - mask = LPAIF_I2SCTL_SPKEN_MASK; + ret = regmap_fields_write(i2sctl->spken, id, + LPAIF_I2SCTL_SPKEN_ENABLE); } else { - val = LPAIF_I2SCTL_MICEN_ENABLE; - mask = LPAIF_I2SCTL_MICEN_MASK; + ret = regmap_fields_write(i2sctl->micen, id, + LPAIF_I2SCTL_MICEN_ENABLE); } - - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_I2SCTL_REG(drvdata->variant, - dai->driver->id), - mask, val); if (ret) dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); @@ -279,17 +315,12 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val = LPAIF_I2SCTL_SPKEN_DISABLE; - mask = LPAIF_I2SCTL_SPKEN_MASK; + ret = regmap_fields_write(i2sctl->spken, id, + LPAIF_I2SCTL_SPKEN_DISABLE); } else { - val = LPAIF_I2SCTL_MICEN_DISABLE; - mask = LPAIF_I2SCTL_MICEN_MASK; + ret = regmap_fields_write(i2sctl->micen, id, + LPAIF_I2SCTL_MICEN_DISABLE); } - - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_I2SCTL_REG(drvdata->variant, - dai->driver->id), - mask, val); if (ret) dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret); @@ -304,7 +335,6 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { .startup = lpass_cpu_daiops_startup, .shutdown = lpass_cpu_daiops_shutdown, .hw_params = lpass_cpu_daiops_hw_params, - .hw_free = lpass_cpu_daiops_hw_free, .prepare = lpass_cpu_daiops_prepare, .trigger = lpass_cpu_daiops_trigger, }; @@ -545,7 +575,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) of_lpass_cpu_parse_dai_data(dev, drvdata); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); drvdata->lpaif = devm_ioremap_resource(dev, res); if (IS_ERR((void const __force *)drvdata->lpaif)) { @@ -566,8 +596,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) return PTR_ERR(drvdata->lpaif_map); } - if (variant->init) - variant->init(pdev); + if (variant->init) { + ret = variant->init(pdev); + if (ret) { + dev_err(dev, "error initializing variant: %d\n", ret); + return ret; + } + } for (i = 0; i < variant->num_dai; i++) { dai_id = variant->dai_driver[i].id; @@ -594,24 +629,15 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) } } - drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk"); - if (IS_ERR(drvdata->ahbix_clk)) { - dev_err(dev, "error getting ahbix-clk: %ld\n", - PTR_ERR(drvdata->ahbix_clk)); - return PTR_ERR(drvdata->ahbix_clk); - } + /* Allocation for i2sctl regmap fields */ + drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl), + GFP_KERNEL); - ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY); + /* Initialize bitfields for dai I2SCTL register */ + ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl, + drvdata->lpaif_map); if (ret) { - dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret); - return ret; - } - dev_dbg(dev, "set ahbix_clk rate to %lu\n", - clk_get_rate(drvdata->ahbix_clk)); - - ret = clk_prepare_enable(drvdata->ahbix_clk); - if (ret) { - dev_err(dev, "error enabling ahbix_clk: %d\n", ret); + dev_err(dev, "error init i2sctl field: %d\n", ret); return ret; } @@ -621,19 +647,16 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) variant->num_dai); if (ret) { dev_err(dev, "error registering cpu driver: %d\n", ret); - goto err_clk; + goto err; } ret = asoc_qcom_lpass_platform_register(pdev); if (ret) { dev_err(dev, "error registering platform driver: %d\n", ret); - goto err_clk; + goto err; } - return 0; - -err_clk: - clk_disable_unprepare(drvdata->ahbix_clk); +err: return ret; } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe); @@ -645,7 +668,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) if (drvdata->variant->exit) drvdata->variant->exit(pdev); - clk_disable_unprepare(drvdata->ahbix_clk); return 0; } diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 1987605482f7..72f09b3a4f6b 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -55,6 +55,47 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .ops = &asoc_qcom_lpass_cpu_dai_ops, }; +static int ipq806x_lpass_init(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret; + + drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk"); + if (IS_ERR(drvdata->ahbix_clk)) { + dev_err(dev, "error getting ahbix-clk: %ld\n", + PTR_ERR(drvdata->ahbix_clk)); + ret = PTR_ERR(drvdata->ahbix_clk); + goto err_ahbix_clk; + } + + ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY); + if (ret) { + dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret); + goto err_ahbix_clk; + } + dev_dbg(dev, "set ahbix_clk rate to %lu\n", + clk_get_rate(drvdata->ahbix_clk)); + + ret = clk_prepare_enable(drvdata->ahbix_clk); + if (ret) { + dev_err(dev, "error enabling ahbix_clk: %d\n", ret); + goto err_ahbix_clk; + } + +err_ahbix_clk: + return ret; +} + +static int ipq806x_lpass_exit(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + clk_disable_unprepare(drvdata->ahbix_clk); + + return 0; +} + static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir) { if (dir == SNDRV_PCM_STREAM_PLAYBACK) @@ -82,6 +123,30 @@ static struct lpass_variant ipq806x_data = { .wrdma_reg_stride = 0x1000, .wrdma_channel_start = 5, .wrdma_channels = 4, + .loopback = REG_FIELD_ID(0x0010, 15, 15, 5, 0x4), + .spken = REG_FIELD_ID(0x0010, 14, 14, 5, 0x4), + .spkmode = REG_FIELD_ID(0x0010, 10, 13, 5, 0x4), + .spkmono = REG_FIELD_ID(0x0010, 9, 9, 5, 0x4), + .micen = REG_FIELD_ID(0x0010, 8, 8, 5, 0x4), + .micmode = REG_FIELD_ID(0x0010, 4, 7, 5, 0x4), + .micmono = REG_FIELD_ID(0x0010, 3, 3, 5, 0x4), + .wssrc = REG_FIELD_ID(0x0010, 2, 2, 5, 0x4), + .bitwidth = REG_FIELD_ID(0x0010, 0, 0, 5, 0x4), + + .rdma_dyncclk = REG_FIELD_ID(0x6000, 12, 12, 4, 0x1000), + .rdma_bursten = REG_FIELD_ID(0x6000, 11, 11, 4, 0x1000), + .rdma_wpscnt = REG_FIELD_ID(0x6000, 8, 10, 4, 0x1000), + .rdma_intf = REG_FIELD_ID(0x6000, 4, 7, 4, 0x1000), + .rdma_fifowm = REG_FIELD_ID(0x6000, 1, 3, 4, 0x1000), + .rdma_enable = REG_FIELD_ID(0x6000, 0, 0, 4, 0x1000), + + .wrdma_dyncclk = REG_FIELD_ID(0xB000, 12, 12, 4, 0x1000), + .wrdma_bursten = REG_FIELD_ID(0xB000, 11, 11, 4, 0x1000), + .wrdma_wpscnt = REG_FIELD_ID(0xB000, 8, 10, 4, 0x1000), + .wrdma_intf = REG_FIELD_ID(0xB000, 4, 7, 4, 0x1000), + .wrdma_fifowm = REG_FIELD_ID(0xB000, 1, 3, 4, 0x1000), + .wrdma_enable = REG_FIELD_ID(0xB000, 0, 0, 4, 0x1000), + .dai_driver = &ipq806x_lpass_cpu_dai_driver, .num_dai = 1, .dai_osr_clk_names = (const char *[]) { @@ -90,6 +155,8 @@ static struct lpass_variant ipq806x_data = { .dai_bit_clk_names = (const char *[]) { "mi2s-bit-clk", }, + .init = ipq806x_lpass_init, + .exit = ipq806x_lpass_exit, .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel, .free_dma_channel = ipq806x_lpass_free_dma_channel, }; diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 72a3e2f69572..5258e60d3646 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -12,15 +12,12 @@ (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port)) #define LPAIF_I2SCTL_REG(v, port) LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port)) -#define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000 -#define LPAIF_I2SCTL_LOOPBACK_SHIFT 15 -#define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT) -#define LPAIF_I2SCTL_LOOPBACK_ENABLE (1 << LPAIF_I2SCTL_LOOPBACK_SHIFT) -#define LPAIF_I2SCTL_SPKEN_MASK 0x4000 -#define LPAIF_I2SCTL_SPKEN_SHIFT 14 -#define LPAIF_I2SCTL_SPKEN_DISABLE (0 << LPAIF_I2SCTL_SPKEN_SHIFT) -#define LPAIF_I2SCTL_SPKEN_ENABLE (1 << LPAIF_I2SCTL_SPKEN_SHIFT) +#define LPAIF_I2SCTL_LOOPBACK_DISABLE 0 +#define LPAIF_I2SCTL_LOOPBACK_ENABLE 1 + +#define LPAIF_I2SCTL_SPKEN_DISABLE 0 +#define LPAIF_I2SCTL_SPKEN_ENABLE 1 #define LPAIF_I2SCTL_MODE_NONE 0 #define LPAIF_I2SCTL_MODE_SD0 1 @@ -31,40 +28,37 @@ #define LPAIF_I2SCTL_MODE_QUAD23 6 #define LPAIF_I2SCTL_MODE_6CH 7 #define LPAIF_I2SCTL_MODE_8CH 8 +#define LPAIF_I2SCTL_MODE_10CH 9 +#define LPAIF_I2SCTL_MODE_12CH 10 +#define LPAIF_I2SCTL_MODE_14CH 11 +#define LPAIF_I2SCTL_MODE_16CH 12 +#define LPAIF_I2SCTL_MODE_SD4 13 +#define LPAIF_I2SCTL_MODE_SD5 14 +#define LPAIF_I2SCTL_MODE_SD6 15 +#define LPAIF_I2SCTL_MODE_SD7 16 +#define LPAIF_I2SCTL_MODE_QUAD45 17 +#define LPAIF_I2SCTL_MODE_QUAD47 18 +#define LPAIF_I2SCTL_MODE_8CH_2 19 -#define LPAIF_I2SCTL_SPKMODE_MASK 0x3C00 -#define LPAIF_I2SCTL_SPKMODE_SHIFT 10 -#define LPAIF_I2SCTL_SPKMODE(mode) ((mode) << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE(mode) mode -#define LPAIF_I2SCTL_SPKMONO_MASK 0x0200 -#define LPAIF_I2SCTL_SPKMONO_SHIFT 9 -#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT) -#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT) +#define LPAIF_I2SCTL_SPKMONO_STEREO 0 +#define LPAIF_I2SCTL_SPKMONO_MONO 1 -#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8) -#define LPAIF_I2SCTL_MICEN_SHIFT 8 -#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT) -#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT) +#define LPAIF_I2SCTL_MICEN_DISABLE 0 +#define LPAIF_I2SCTL_MICEN_ENABLE 1 -#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4) -#define LPAIF_I2SCTL_MICMODE_SHIFT 4 -#define LPAIF_I2SCTL_MICMODE(mode) ((mode) << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE(mode) mode -#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3) -#define LPAIF_I2SCTL_MICMONO_SHIFT 3 -#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT) -#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT) +#define LPAIF_I2SCTL_MICMONO_STEREO 0 +#define LPAIF_I2SCTL_MICMONO_MONO 1 -#define LPAIF_I2SCTL_WSSRC_MASK 0x0004 -#define LPAIF_I2SCTL_WSSRC_SHIFT 2 -#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT) -#define LPAIF_I2SCTL_WSSRC_EXTERNAL (1 << LPAIF_I2SCTL_WSSRC_SHIFT) +#define LPAIF_I2SCTL_WSSRC_INTERNAL 0 +#define LPAIF_I2SCTL_WSSRC_EXTERNAL 1 -#define LPAIF_I2SCTL_BITWIDTH_MASK 0x0003 -#define LPAIF_I2SCTL_BITWIDTH_SHIFT 0 -#define LPAIF_I2SCTL_BITWIDTH_16 (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT) -#define LPAIF_I2SCTL_BITWIDTH_24 (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT) -#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT) +#define LPAIF_I2SCTL_BITWIDTH_16 0 +#define LPAIF_I2SCTL_BITWIDTH_24 1 +#define LPAIF_I2SCTL_BITWIDTH_32 2 /* LPAIF IRQ */ #define LPAIF_IRQ_REG_ADDR(v, addr, port) \ @@ -121,42 +115,59 @@ #define LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER) #define LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT) -#define LPAIF_DMACTL_BURSTEN_MASK 0x800 -#define LPAIF_DMACTL_BURSTEN_SHIFT 11 -#define LPAIF_DMACTL_BURSTEN_SINGLE (0 << LPAIF_DMACTL_BURSTEN_SHIFT) -#define LPAIF_DMACTL_BURSTEN_INCR4 (1 << LPAIF_DMACTL_BURSTEN_SHIFT) - -#define LPAIF_DMACTL_WPSCNT_MASK 0x700 -#define LPAIF_DMACTL_WPSCNT_SHIFT 8 -#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT) -#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT) -#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT) -#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT) -#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT) -#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT) - -#define LPAIF_DMACTL_AUDINTF_MASK 0x0F0 -#define LPAIF_DMACTL_AUDINTF_SHIFT 4 -#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT) - -#define LPAIF_DMACTL_FIFOWM_MASK 0x00E -#define LPAIF_DMACTL_FIFOWM_SHIFT 1 -#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT) -#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT) - -#define LPAIF_DMACTL_ENABLE_MASK 0x1 -#define LPAIF_DMACTL_ENABLE_SHIFT 0 -#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT) -#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT) - -#define LPAIF_DMACTL_DYNCLK_MASK BIT(12) -#define LPAIF_DMACTL_DYNCLK_SHIFT 12 -#define LPAIF_DMACTL_DYNCLK_OFF (0 << LPAIF_DMACTL_DYNCLK_SHIFT) -#define LPAIF_DMACTL_DYNCLK_ON (1 << LPAIF_DMACTL_DYNCLK_SHIFT) +#define LPAIF_DMACTL_BURSTEN_SINGLE 0 +#define LPAIF_DMACTL_BURSTEN_INCR4 1 + +#define LPAIF_DMACTL_WPSCNT_ONE 0 +#define LPAIF_DMACTL_WPSCNT_TWO 1 +#define LPAIF_DMACTL_WPSCNT_THREE 2 +#define LPAIF_DMACTL_WPSCNT_FOUR 3 +#define LPAIF_DMACTL_WPSCNT_SIX 5 +#define LPAIF_DMACTL_WPSCNT_EIGHT 7 +#define LPAIF_DMACTL_WPSCNT_TEN 9 +#define LPAIF_DMACTL_WPSCNT_TWELVE 11 +#define LPAIF_DMACTL_WPSCNT_FOURTEEN 13 +#define LPAIF_DMACTL_WPSCNT_SIXTEEN 15 + +#define LPAIF_DMACTL_AUDINTF(id) id + +#define LPAIF_DMACTL_FIFOWM_1 0 +#define LPAIF_DMACTL_FIFOWM_2 1 +#define LPAIF_DMACTL_FIFOWM_3 2 +#define LPAIF_DMACTL_FIFOWM_4 3 +#define LPAIF_DMACTL_FIFOWM_5 4 +#define LPAIF_DMACTL_FIFOWM_6 5 +#define LPAIF_DMACTL_FIFOWM_7 6 +#define LPAIF_DMACTL_FIFOWM_8 7 +#define LPAIF_DMACTL_FIFOWM_9 8 +#define LPAIF_DMACTL_FIFOWM_10 9 +#define LPAIF_DMACTL_FIFOWM_11 10 +#define LPAIF_DMACTL_FIFOWM_12 11 +#define LPAIF_DMACTL_FIFOWM_13 12 +#define LPAIF_DMACTL_FIFOWM_14 13 +#define LPAIF_DMACTL_FIFOWM_15 14 +#define LPAIF_DMACTL_FIFOWM_16 15 +#define LPAIF_DMACTL_FIFOWM_17 16 +#define LPAIF_DMACTL_FIFOWM_18 17 +#define LPAIF_DMACTL_FIFOWM_19 18 +#define LPAIF_DMACTL_FIFOWM_20 19 +#define LPAIF_DMACTL_FIFOWM_21 20 +#define LPAIF_DMACTL_FIFOWM_22 21 +#define LPAIF_DMACTL_FIFOWM_23 22 +#define LPAIF_DMACTL_FIFOWM_24 23 +#define LPAIF_DMACTL_FIFOWM_25 24 +#define LPAIF_DMACTL_FIFOWM_26 25 +#define LPAIF_DMACTL_FIFOWM_27 26 +#define LPAIF_DMACTL_FIFOWM_28 27 +#define LPAIF_DMACTL_FIFOWM_29 28 +#define LPAIF_DMACTL_FIFOWM_30 29 +#define LPAIF_DMACTL_FIFOWM_31 30 +#define LPAIF_DMACTL_FIFOWM_32 31 + +#define LPAIF_DMACTL_ENABLE_OFF 0 +#define LPAIF_DMACTL_ENABLE_ON 1 + +#define LPAIF_DMACTL_DYNCLK_OFF 0 +#define LPAIF_DMACTL_DYNCLK_ON 1 + #endif /* __LPASS_LPAIF_REG_H__ */ diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 01179bc0e5e5..df692ed95503 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -50,6 +50,53 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = { .fifo_size = 0, }; +static int lpass_platform_alloc_dmactl_fields(struct device *dev, + struct regmap *map) +{ + struct lpass_data *drvdata = dev_get_drvdata(dev); + struct lpass_variant *v = drvdata->variant; + struct lpaif_dmactl *rd_dmactl, *wr_dmactl; + + drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), + GFP_KERNEL); + if (drvdata->rd_dmactl == NULL) + return -ENOMEM; + + drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), + GFP_KERNEL); + if (drvdata->wr_dmactl == NULL) + return -ENOMEM; + + rd_dmactl = drvdata->rd_dmactl; + wr_dmactl = drvdata->wr_dmactl; + + rd_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->rdma_bursten); + rd_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->rdma_wpscnt); + rd_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->rdma_fifowm); + rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf); + rd_dmactl->enable = devm_regmap_field_alloc(dev, map, v->rdma_enable); + rd_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->rdma_dyncclk); + + if (IS_ERR(rd_dmactl->bursten) || IS_ERR(rd_dmactl->wpscnt) || + IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->intf) || + IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->dyncclk)) + return -EINVAL; + + wr_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->wrdma_bursten); + wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->wrdma_wpscnt); + wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->wrdma_fifowm); + wr_dmactl->intf = devm_regmap_field_alloc(dev, map, v->wrdma_intf); + wr_dmactl->enable = devm_regmap_field_alloc(dev, map, v->wrdma_enable); + wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->wrdma_dyncclk); + + if (IS_ERR(wr_dmactl->bursten) || IS_ERR(wr_dmactl->wpscnt) || + IS_ERR(wr_dmactl->fifowm) || IS_ERR(wr_dmactl->intf) || + IS_ERR(wr_dmactl->enable) || IS_ERR(wr_dmactl->dyncclk)) + return -EINVAL; + + return 0; +} + static int lpass_platform_pcmops_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -61,7 +108,7 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component, int ret, dma_ch, dir = substream->stream; struct lpass_pcm_data *data; - data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -118,6 +165,7 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component, if (v->free_dma_channel) v->free_dma_channel(drvdata, data->dma_ch); + kfree(data); return 0; } @@ -133,11 +181,18 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; - int ch, dir = substream->stream; + struct lpaif_dmactl *dmactl; + int id, dir = substream->stream; int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; - ch = pcm_data->dma_ch; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + dmactl = drvdata->rd_dmactl; + id = pcm_data->dma_ch; + } else { + dmactl = drvdata->wr_dmactl; + id = pcm_data->dma_ch - v->wrdma_channel_start; + } bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { @@ -146,25 +201,39 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, return bitwidth; } - regval = LPAIF_DMACTL_BURSTEN_INCR4 | - LPAIF_DMACTL_AUDINTF(dma_port) | - LPAIF_DMACTL_FIFOWM_8; + ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4); + if (ret) { + dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret); + return ret; + } + + regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8); + if (ret) { + dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret); + return ret; + } + + regmap_fields_write(dmactl->intf, id, LPAIF_DMACTL_AUDINTF(dma_port)); + if (ret) { + dev_err(soc_runtime->dev, "error updating audintf field: %d\n", ret); + return ret; + } switch (bitwidth) { case 16: switch (channels) { case 1: case 2: - regval |= LPAIF_DMACTL_WPSCNT_ONE; + regval = LPAIF_DMACTL_WPSCNT_ONE; break; case 4: - regval |= LPAIF_DMACTL_WPSCNT_TWO; + regval = LPAIF_DMACTL_WPSCNT_TWO; break; case 6: - regval |= LPAIF_DMACTL_WPSCNT_THREE; + regval = LPAIF_DMACTL_WPSCNT_THREE; break; case 8: - regval |= LPAIF_DMACTL_WPSCNT_FOUR; + regval = LPAIF_DMACTL_WPSCNT_FOUR; break; default: dev_err(soc_runtime->dev, @@ -177,19 +246,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, case 32: switch (channels) { case 1: - regval |= LPAIF_DMACTL_WPSCNT_ONE; + regval = LPAIF_DMACTL_WPSCNT_ONE; break; case 2: - regval |= LPAIF_DMACTL_WPSCNT_TWO; + regval = LPAIF_DMACTL_WPSCNT_TWO; break; case 4: - regval |= LPAIF_DMACTL_WPSCNT_FOUR; + regval = LPAIF_DMACTL_WPSCNT_FOUR; break; case 6: - regval |= LPAIF_DMACTL_WPSCNT_SIX; + regval = LPAIF_DMACTL_WPSCNT_SIX; break; case 8: - regval |= LPAIF_DMACTL_WPSCNT_EIGHT; + regval = LPAIF_DMACTL_WPSCNT_EIGHT; break; default: dev_err(soc_runtime->dev, @@ -204,10 +273,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, return -EINVAL; } - ret = regmap_write(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, ch, dir), regval); + ret = regmap_fields_write(dmactl->wpscnt, id, regval); if (ret) { - dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", + dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n", ret); return ret; } @@ -244,9 +312,17 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; - int ret, ch, dir = substream->stream; + struct lpaif_dmactl *dmactl; + int ret, id, ch, dir = substream->stream; ch = pcm_data->dma_ch; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + dmactl = drvdata->rd_dmactl; + id = pcm_data->dma_ch; + } else { + dmactl = drvdata->wr_dmactl; + id = pcm_data->dma_ch - v->wrdma_channel_start; + } ret = regmap_write(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), @@ -275,9 +351,7 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component, return ret; } - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, ch, dir), - LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON); + ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret); @@ -296,9 +370,18 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, struct snd_pcm_runtime *rt = substream->runtime; struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_variant *v = drvdata->variant; - int ret, ch, dir = substream->stream; + struct lpaif_dmactl *dmactl; + int ret, ch, id; + int dir = substream->stream; ch = pcm_data->dma_ch; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + dmactl = drvdata->rd_dmactl; + id = pcm_data->dma_ch; + } else { + dmactl = drvdata->wr_dmactl; + id = pcm_data->dma_ch - v->wrdma_channel_start; + } switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -324,10 +407,8 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, return ret; } - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, ch, dir), - LPAIF_DMACTL_ENABLE_MASK, - LPAIF_DMACTL_ENABLE_ON); + ret = regmap_fields_write(dmactl->enable, id, + LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret); @@ -337,10 +418,8 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, ch, dir), - LPAIF_DMACTL_ENABLE_MASK, - LPAIF_DMACTL_ENABLE_OFF); + ret = regmap_fields_write(dmactl->enable, id, + LPAIF_DMACTL_ENABLE_OFF); if (ret) { dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret); @@ -400,9 +479,8 @@ static int lpass_platform_pcmops_mmap(struct snd_soc_component *component, { struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_coherent(substream->pcm->card->dev, vma, - runtime->dma_area, runtime->dma_addr, - runtime->dma_bytes); + return dma_mmap_coherent(component->dev, vma, runtime->dma_area, + runtime->dma_addr, runtime->dma_bytes); } static irqreturn_t lpass_dma_interrupt_handler( @@ -560,7 +638,7 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) struct lpass_variant *v = drvdata->variant; int ret; - drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); + drvdata->lpaif_irq = platform_get_irq(pdev, 0); if (drvdata->lpaif_irq < 0) return -ENODEV; @@ -580,6 +658,13 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) return ret; } + ret = lpass_platform_alloc_dmactl_fields(&pdev->dev, + drvdata->lpaif_map); + if (ret) { + dev_err(&pdev->dev, + "error initializing dmactl fields: %d\n", ret); + return ret; + } return devm_snd_soc_register_component(&pdev->dev, &lpass_component_driver, NULL, 0); diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c new file mode 100644 index 000000000000..167bf2cbc556 --- /dev/null +++ b/sound/soc/qcom/lpass-sc7180.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <dt-bindings/sound/sc7180-lpass.h> +#include <sound/pcm.h> +#include <sound/soc.h> + +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { + [MI2S_PRIMARY] = { + .id = MI2S_PRIMARY, + .name = "Primary MI2S", + .playback = { + .stream_name = "Primary Playback", + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .stream_name = "Primary Capture", + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, + + [MI2S_SECONDARY] = { + .id = MI2S_SECONDARY, + .name = "Secondary MI2S", + .playback = { + .stream_name = "Secondary Playback", + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, +}; + +static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata, + int direction) +{ + struct lpass_variant *v = drvdata->variant; + int chan = 0; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, + v->rdma_channels); + + if (chan >= v->rdma_channels) + return -EBUSY; + } else { + chan = find_next_zero_bit(&drvdata->dma_ch_bit_map, + v->wrdma_channel_start + + v->wrdma_channels, + v->wrdma_channel_start); + + if (chan >= v->wrdma_channel_start + v->wrdma_channels) + return -EBUSY; + } + + set_bit(chan, &drvdata->dma_ch_bit_map); + + return chan; +} + +static int sc7180_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) +{ + clear_bit(chan, &drvdata->dma_ch_bit_map); + + return 0; +} + +static int sc7180_lpass_init(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + struct lpass_variant *variant = drvdata->variant; + struct device *dev = &pdev->dev; + int ret, i; + + drvdata->clks = devm_kcalloc(dev, variant->num_clks, + sizeof(*drvdata->clks), GFP_KERNEL); + drvdata->num_clks = variant->num_clks; + + for (i = 0; i < drvdata->num_clks; i++) + drvdata->clks[i].id = variant->clk_name[i]; + + ret = devm_clk_bulk_get(dev, drvdata->num_clks, drvdata->clks); + if (ret) { + dev_err(dev, "Failed to get clocks %d\n", ret); + return ret; + } + + ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); + if (ret) { + dev_err(dev, "sc7180 clk_enable failed\n"); + return ret; + } + + return 0; +} + +static int sc7180_lpass_exit(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clks); + + return 0; +} + +static struct lpass_variant sc7180_data = { + .i2sctrl_reg_base = 0x1000, + .i2sctrl_reg_stride = 0x1000, + .i2s_ports = 3, + .irq_reg_base = 0x9000, + .irq_reg_stride = 0x1000, + .irq_ports = 3, + .rdma_reg_base = 0xC000, + .rdma_reg_stride = 0x1000, + .rdma_channels = 5, + .dmactl_audif_start = 1, + .wrdma_reg_base = 0x18000, + .wrdma_reg_stride = 0x1000, + .wrdma_channel_start = 5, + .wrdma_channels = 4, + + .loopback = REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000), + .spken = REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000), + .spkmode = REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000), + .spkmono = REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000), + .micen = REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000), + .micmode = REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000), + .micmono = REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000), + .wssrc = REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000), + .bitwidth = REG_FIELD_ID(0x1000, 0, 0, 3, 0x1000), + + .rdma_dyncclk = REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000), + .rdma_bursten = REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000), + .rdma_wpscnt = REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000), + .rdma_intf = REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000), + .rdma_fifowm = REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000), + .rdma_enable = REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000), + + .wrdma_dyncclk = REG_FIELD_ID(0x18000, 22, 22, 4, 0x1000), + .wrdma_bursten = REG_FIELD_ID(0x18000, 21, 21, 4, 0x1000), + .wrdma_wpscnt = REG_FIELD_ID(0x18000, 17, 20, 4, 0x1000), + .wrdma_intf = REG_FIELD_ID(0x18000, 12, 16, 4, 0x1000), + .wrdma_fifowm = REG_FIELD_ID(0x18000, 1, 5, 4, 0x1000), + .wrdma_enable = REG_FIELD_ID(0x18000, 0, 0, 4, 0x1000), + + .clk_name = (const char*[]) { + "pcnoc-sway-clk", + "audio-core", + "pcnoc-mport-clk", + }, + .num_clks = 3, + .dai_driver = sc7180_lpass_cpu_dai_driver, + .num_dai = ARRAY_SIZE(sc7180_lpass_cpu_dai_driver), + .dai_osr_clk_names = (const char *[]) { + "mclk0", + "null", + }, + .dai_bit_clk_names = (const char *[]) { + "mi2s-bit-clk0", + "mi2s-bit-clk1", + }, + .init = sc7180_lpass_init, + .exit = sc7180_lpass_exit, + .alloc_dma_channel = sc7180_lpass_alloc_dma_channel, + .free_dma_channel = sc7180_lpass_free_dma_channel, +}; + +static const struct of_device_id sc7180_lpass_cpu_device_id[] = { + {.compatible = "qcom,sc7180-lpass-cpu", .data = &sc7180_data}, + {} +}; + +static struct platform_driver sc7180_lpass_cpu_platform_driver = { + .driver = { + .name = "sc7180-lpass-cpu", + .of_match_table = of_match_ptr(sc7180_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, + .remove = asoc_qcom_lpass_cpu_platform_remove, +}; + +module_platform_driver(sc7180_lpass_cpu_platform_driver); + +MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index bd19ec57c73d..51c9991a0edf 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -17,6 +17,28 @@ #define LPASS_MAX_MI2S_PORTS (8) #define LPASS_MAX_DMA_CHANNELS (8) +struct lpaif_i2sctl { + struct regmap_field *loopback; + struct regmap_field *spken; + struct regmap_field *spkmode; + struct regmap_field *spkmono; + struct regmap_field *micen; + struct regmap_field *micmode; + struct regmap_field *micmono; + struct regmap_field *wssrc; + struct regmap_field *bitwidth; +}; + + +struct lpaif_dmactl { + struct regmap_field *bursten; + struct regmap_field *wpscnt; + struct regmap_field *intf; + struct regmap_field *fifowm; + struct regmap_field *enable; + struct regmap_field *dyncclk; +}; + /* Both the CPU DAI and platform drivers will access this data */ struct lpass_data { @@ -51,10 +73,14 @@ struct lpass_data { /* used it for handling interrupt per dma channel */ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS]; - /* 8016 specific */ - struct clk *pcnoc_mport_clk; - struct clk *pcnoc_sway_clk; + /* SOC specific clock list */ + struct clk_bulk_data *clks; + int num_clks; + /* Regmap fields of I2SCTL & DMACTL registers bitfields */ + struct lpaif_i2sctl *i2sctl; + struct lpaif_dmactl *rd_dmactl; + struct lpaif_dmactl *wr_dmactl; }; /* Vairant data per each SOC */ @@ -72,6 +98,33 @@ struct lpass_variant { u32 wrdma_reg_stride; u32 wrdma_channels; + /* I2SCTL Register fields */ + struct reg_field loopback; + struct reg_field spken; + struct reg_field spkmode; + struct reg_field spkmono; + struct reg_field micen; + struct reg_field micmode; + struct reg_field micmono; + struct reg_field wssrc; + struct reg_field bitwidth; + + /* RD_DMA Register fields */ + struct reg_field rdma_bursten; + struct reg_field rdma_wpscnt; + struct reg_field rdma_intf; + struct reg_field rdma_fifowm; + struct reg_field rdma_enable; + struct reg_field rdma_dyncclk; + + /* WR_DMA Register fields */ + struct reg_field wrdma_bursten; + struct reg_field wrdma_wpscnt; + struct reg_field wrdma_intf; + struct reg_field wrdma_fifowm; + struct reg_field wrdma_enable; + struct reg_field wrdma_dyncclk; + /** * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x @@ -89,6 +142,10 @@ struct lpass_variant { int num_dai; const char * const *dai_osr_clk_names; const char * const *dai_bit_clk_names; + + /* SOC specific clocks configuration */ + const char **clk_name; + int num_clks; }; /* register the platform driver from the CPU DAI driver */ diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 9b7b218f2a20..a1dd31f306ce 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -50,7 +50,7 @@ enum stream_state { struct q6asm_dai_rtd { struct snd_pcm_substream *substream; struct snd_compr_stream *cstream; - struct snd_compr_params codec_param; + struct snd_codec codec; struct snd_dma_buffer dma_buffer; spinlock_t lock; phys_addr_t phys; @@ -64,8 +64,14 @@ struct q6asm_dai_rtd { uint16_t bits_per_sample; uint16_t source; /* Encoding source bit mask */ struct audio_client *audio_client; + uint32_t next_track_stream_id; + bool next_track; + uint32_t stream_id; uint16_t session_id; enum stream_state state; + uint32_t initial_samples_drop; + uint32_t trailing_samples_drop; + bool notify_on_drain; }; struct q6asm_dai_data { @@ -181,8 +187,8 @@ static void event_handler(uint32_t opcode, uint32_t token, switch (opcode) { case ASM_CLIENT_EVENT_CMD_RUN_DONE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - q6asm_write_async(prtd->audio_client, - prtd->pcm_count, 0, 0, NO_TIMESTAMP); + q6asm_write_async(prtd->audio_client, prtd->stream_id, + prtd->pcm_count, 0, 0, 0); break; case ASM_CLIENT_EVENT_CMD_EOS_DONE: prtd->state = Q6ASM_STREAM_STOPPED; @@ -191,8 +197,8 @@ static void event_handler(uint32_t opcode, uint32_t token, prtd->pcm_irq_pos += prtd->pcm_count; snd_pcm_period_elapsed(substream); if (prtd->state == Q6ASM_STREAM_RUNNING) - q6asm_write_async(prtd->audio_client, - prtd->pcm_count, 0, 0, NO_TIMESTAMP); + q6asm_write_async(prtd->audio_client, prtd->stream_id, + prtd->pcm_count, 0, 0, 0); break; } @@ -200,7 +206,7 @@ static void event_handler(uint32_t opcode, uint32_t token, prtd->pcm_irq_pos += prtd->pcm_count; snd_pcm_period_elapsed(substream); if (prtd->state == Q6ASM_STREAM_RUNNING) - q6asm_read(prtd->audio_client); + q6asm_read(prtd->audio_client, prtd->stream_id); break; default: @@ -233,7 +239,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, /* rate and channels are sent to audio driver */ if (prtd->state) { /* clear the previous setup if any */ - q6asm_cmd(prtd->audio_client, CMD_CLOSE); + q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); q6asm_unmap_memory_regions(substream->stream, prtd->audio_client); q6routing_stream_close(soc_prtd->dai_link->id, @@ -252,11 +258,13 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM, - 0, prtd->bits_per_sample); + ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, + FORMAT_LINEAR_PCM, + 0, prtd->bits_per_sample, false); } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM, - prtd->bits_per_sample); + ret = q6asm_open_read(prtd->audio_client, prtd->stream_id, + FORMAT_LINEAR_PCM, + prtd->bits_per_sample); } if (ret < 0) { @@ -276,17 +284,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = q6asm_media_format_block_multi_ch_pcm( - prtd->audio_client, runtime->rate, - runtime->channels, NULL, + prtd->audio_client, prtd->stream_id, + runtime->rate, runtime->channels, NULL, prtd->bits_per_sample); } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client, - runtime->rate, runtime->channels, - prtd->bits_per_sample); + prtd->stream_id, + runtime->rate, + runtime->channels, + prtd->bits_per_sample); /* Queue the buffers */ for (i = 0; i < runtime->periods; i++) - q6asm_read(prtd->audio_client); + q6asm_read(prtd->audio_client, prtd->stream_id); } if (ret < 0) @@ -308,15 +318,18 @@ static int q6asm_dai_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id, + 0, 0, 0); break; case SNDRV_PCM_TRIGGER_STOP: prtd->state = Q6ASM_STREAM_STOPPED; - ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_EOS); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_PAUSE); break; default: ret = -EINVAL; @@ -361,6 +374,9 @@ static int q6asm_dai_open(struct snd_soc_component *component, return ret; } + /* DSP expects stream id from 1 */ + prtd->stream_id = 1; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = q6asm_dai_hardware_playback; else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -427,7 +443,8 @@ static int q6asm_dai_close(struct snd_soc_component *component, if (prtd->audio_client) { if (prtd->state) - q6asm_cmd(prtd->audio_client, CMD_CLOSE); + q6asm_cmd(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); q6asm_unmap_memory_regions(substream->stream, prtd->audio_client); @@ -493,14 +510,21 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, struct q6asm_dai_rtd *prtd = priv; struct snd_compr_stream *substream = prtd->cstream; unsigned long flags; + u32 wflags = 0; uint64_t avail; + uint32_t bytes_written, bytes_to_write; + bool is_last_buffer = false; switch (opcode) { case ASM_CLIENT_EVENT_CMD_RUN_DONE: spin_lock_irqsave(&prtd->lock, flags); if (!prtd->bytes_sent) { - q6asm_write_async(prtd->audio_client, prtd->pcm_count, - 0, 0, NO_TIMESTAMP); + q6asm_stream_remove_initial_silence(prtd->audio_client, + prtd->stream_id, + prtd->initial_samples_drop); + + q6asm_write_async(prtd->audio_client, prtd->stream_id, + prtd->pcm_count, 0, 0, 0); prtd->bytes_sent += prtd->pcm_count; } @@ -508,13 +532,37 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, break; case ASM_CLIENT_EVENT_CMD_EOS_DONE: - prtd->state = Q6ASM_STREAM_STOPPED; + spin_lock_irqsave(&prtd->lock, flags); + if (prtd->notify_on_drain) { + if (substream->partial_drain) { + /* + * Close old stream and make it stale, switch + * the active stream now! + */ + q6asm_cmd_nowait(prtd->audio_client, + prtd->stream_id, + CMD_CLOSE); + /* + * vaild stream ids start from 1, So we are + * toggling this between 1 and 2. + */ + prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1); + } + + snd_compr_drain_notify(prtd->cstream); + prtd->notify_on_drain = false; + + } else { + prtd->state = Q6ASM_STREAM_STOPPED; + } + spin_unlock_irqrestore(&prtd->lock, flags); break; case ASM_CLIENT_EVENT_DATA_WRITE_DONE: spin_lock_irqsave(&prtd->lock, flags); - prtd->copied_total += prtd->pcm_count; + bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT; + prtd->copied_total += bytes_written; snd_compr_fragment_elapsed(substream); if (prtd->state != Q6ASM_STREAM_RUNNING) { @@ -523,13 +571,32 @@ static void compress_event_handler(uint32_t opcode, uint32_t token, } avail = prtd->bytes_received - prtd->bytes_sent; + if (avail > prtd->pcm_count) { + bytes_to_write = prtd->pcm_count; + } else { + if (substream->partial_drain || prtd->notify_on_drain) + is_last_buffer = true; + bytes_to_write = avail; + } - if (avail >= prtd->pcm_count) { - q6asm_write_async(prtd->audio_client, - prtd->pcm_count, 0, 0, NO_TIMESTAMP); - prtd->bytes_sent += prtd->pcm_count; + if (bytes_to_write) { + if (substream->partial_drain && is_last_buffer) { + wflags |= ASM_LAST_BUFFER_FLAG; + q6asm_stream_remove_trailing_silence(prtd->audio_client, + prtd->stream_id, + prtd->trailing_samples_drop); + } + + q6asm_write_async(prtd->audio_client, prtd->stream_id, + bytes_to_write, 0, 0, wflags); + + prtd->bytes_sent += bytes_to_write; } + if (prtd->notify_on_drain && is_last_buffer) + q6asm_cmd_nowait(prtd->audio_client, + prtd->stream_id, CMD_EOS); + spin_unlock_irqrestore(&prtd->lock, flags); break; @@ -560,6 +627,9 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component, if (!prtd) return -ENOMEM; + /* DSP expects stream id from 1 */ + prtd->stream_id = 1; + prtd->cstream = stream; prtd->audio_client = q6asm_audio_client_alloc(dev, (q6asm_cb)compress_event_handler, @@ -606,8 +676,15 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd = stream->private_data; if (prtd->audio_client) { - if (prtd->state) - q6asm_cmd(prtd->audio_client, CMD_CLOSE); + if (prtd->state) { + q6asm_cmd(prtd->audio_client, prtd->stream_id, + CMD_CLOSE); + if (prtd->next_track_stream_id) { + q6asm_cmd(prtd->audio_client, + prtd->next_track_stream_id, + CMD_CLOSE); + } + } snd_dma_free_pages(&prtd->dma_buffer); q6asm_unmap_memory_regions(stream->direction, @@ -621,15 +698,13 @@ static int q6asm_dai_compr_free(struct snd_soc_component *component, return 0; } -static int q6asm_dai_compr_set_params(struct snd_soc_component *component, - struct snd_compr_stream *stream, - struct snd_compr_params *params) +static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component, + struct snd_compr_stream *stream, + struct snd_codec *codec, + int stream_id) { struct snd_compr_runtime *runtime = stream->runtime; struct q6asm_dai_rtd *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = stream->private_data; - int dir = stream->direction; - struct q6asm_dai_data *pdata; struct q6asm_flac_cfg flac_cfg; struct q6asm_wma_cfg wma_cfg; struct q6asm_alac_cfg alac_cfg; @@ -643,52 +718,18 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, struct snd_dec_alac *alac; struct snd_dec_ape *ape; - codec_options = &(prtd->codec_param.codec.options); - - - memcpy(&prtd->codec_param, params, sizeof(*params)); - - pdata = snd_soc_component_get_drvdata(component); - if (!pdata) - return -EINVAL; - - if (!prtd || !prtd->audio_client) { - dev_err(dev, "private data null or audio client freed\n"); - return -EINVAL; - } - - prtd->periods = runtime->fragments; - prtd->pcm_count = runtime->fragment_size; - prtd->pcm_size = runtime->fragments * runtime->fragment_size; - prtd->bits_per_sample = 16; - if (dir == SND_COMPRESS_PLAYBACK) { - ret = q6asm_open_write(prtd->audio_client, params->codec.id, - params->codec.profile, prtd->bits_per_sample); - - if (ret < 0) { - dev_err(dev, "q6asm_open_write failed\n"); - q6asm_audio_client_free(prtd->audio_client); - prtd->audio_client = NULL; - return ret; - } - } + codec_options = &(prtd->codec.options); - prtd->session_id = q6asm_get_session_id(prtd->audio_client); - ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE, - prtd->session_id, dir); - if (ret) { - dev_err(dev, "Stream reg failed ret:%d\n", ret); - return ret; - } + memcpy(&prtd->codec, codec, sizeof(*codec)); - switch (params->codec.id) { + switch (codec->id) { case SND_AUDIOCODEC_FLAC: memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg)); flac = &codec_options->flac_d; - flac_cfg.ch_cfg = params->codec.ch_in; - flac_cfg.sample_rate = params->codec.sample_rate; + flac_cfg.ch_cfg = codec->ch_in; + flac_cfg.sample_rate = codec->sample_rate; flac_cfg.stream_info_present = 1; flac_cfg.sample_size = flac->sample_size; flac_cfg.min_blk_size = flac->min_blk_size; @@ -697,6 +738,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, flac_cfg.min_frame_size = flac->min_frame_size; ret = q6asm_stream_media_format_block_flac(prtd->audio_client, + stream_id, &flac_cfg); if (ret < 0) { dev_err(dev, "FLAC CMD Format block failed:%d\n", ret); @@ -709,10 +751,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg)); - wma_cfg.sample_rate = params->codec.sample_rate; - wma_cfg.num_channels = params->codec.ch_in; - wma_cfg.bytes_per_sec = params->codec.bit_rate / 8; - wma_cfg.block_align = params->codec.align; + wma_cfg.sample_rate = codec->sample_rate; + wma_cfg.num_channels = codec->ch_in; + wma_cfg.bytes_per_sec = codec->bit_rate / 8; + wma_cfg.block_align = codec->align; wma_cfg.bits_per_sample = prtd->bits_per_sample; wma_cfg.enc_options = wma->encoder_option; wma_cfg.adv_enc_options = wma->adv_encoder_option; @@ -726,7 +768,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, return -EINVAL; /* check the codec profile */ - switch (params->codec.profile) { + switch (codec->profile) { case SND_AUDIOPROFILE_WMA9: wma_cfg.fmtag = 0x161; wma_v9 = 1; @@ -750,16 +792,18 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, default: dev_err(dev, "Unknown WMA profile:%x\n", - params->codec.profile); + codec->profile); return -EIO; } if (wma_v9) ret = q6asm_stream_media_format_block_wma_v9( - prtd->audio_client, &wma_cfg); + prtd->audio_client, stream_id, + &wma_cfg); else ret = q6asm_stream_media_format_block_wma_v10( - prtd->audio_client, &wma_cfg); + prtd->audio_client, stream_id, + &wma_cfg); if (ret < 0) { dev_err(dev, "WMA9 CMD failed:%d\n", ret); return -EIO; @@ -770,10 +814,10 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, memset(&alac_cfg, 0x0, sizeof(alac_cfg)); alac = &codec_options->alac_d; - alac_cfg.sample_rate = params->codec.sample_rate; - alac_cfg.avg_bit_rate = params->codec.bit_rate; + alac_cfg.sample_rate = codec->sample_rate; + alac_cfg.avg_bit_rate = codec->bit_rate; alac_cfg.bit_depth = prtd->bits_per_sample; - alac_cfg.num_channels = params->codec.ch_in; + alac_cfg.num_channels = codec->ch_in; alac_cfg.frame_length = alac->frame_length; alac_cfg.pb = alac->pb; @@ -783,7 +827,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, alac_cfg.compatible_version = alac->compatible_version; alac_cfg.max_frame_bytes = alac->max_frame_bytes; - switch (params->codec.ch_in) { + switch (codec->ch_in) { case 1: alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO; break; @@ -792,6 +836,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, break; } ret = q6asm_stream_media_format_block_alac(prtd->audio_client, + stream_id, &alac_cfg); if (ret < 0) { dev_err(dev, "ALAC CMD Format block failed:%d\n", ret); @@ -803,8 +848,8 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, memset(&ape_cfg, 0x0, sizeof(ape_cfg)); ape = &codec_options->ape_d; - ape_cfg.sample_rate = params->codec.sample_rate; - ape_cfg.num_channels = params->codec.ch_in; + ape_cfg.sample_rate = codec->sample_rate; + ape_cfg.num_channels = codec->ch_in; ape_cfg.bits_per_sample = prtd->bits_per_sample; ape_cfg.compatible_version = ape->compatible_version; @@ -816,6 +861,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, ape_cfg.seek_table_present = ape->seek_table_present; ret = q6asm_stream_media_format_block_ape(prtd->audio_client, + stream_id, &ape_cfg); if (ret < 0) { dev_err(dev, "APE CMD Format block failed:%d\n", ret); @@ -827,6 +873,64 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, break; } + return 0; +} + +static int q6asm_dai_compr_set_params(struct snd_soc_component *component, + struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct snd_compr_runtime *runtime = stream->runtime; + struct q6asm_dai_rtd *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = stream->private_data; + int dir = stream->direction; + struct q6asm_dai_data *pdata; + struct device *dev = component->dev; + int ret; + + pdata = snd_soc_component_get_drvdata(component); + if (!pdata) + return -EINVAL; + + if (!prtd || !prtd->audio_client) { + dev_err(dev, "private data null or audio client freed\n"); + return -EINVAL; + } + + prtd->periods = runtime->fragments; + prtd->pcm_count = runtime->fragment_size; + prtd->pcm_size = runtime->fragments * runtime->fragment_size; + prtd->bits_per_sample = 16; + + if (dir == SND_COMPRESS_PLAYBACK) { + ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id, + params->codec.profile, prtd->bits_per_sample, + true); + + if (ret < 0) { + dev_err(dev, "q6asm_open_write failed\n"); + q6asm_audio_client_free(prtd->audio_client); + prtd->audio_client = NULL; + return ret; + } + } + + prtd->session_id = q6asm_get_session_id(prtd->audio_client); + ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE, + prtd->session_id, dir); + if (ret) { + dev_err(dev, "Stream reg failed ret:%d\n", ret); + return ret; + } + + ret = __q6asm_dai_compr_set_codec_params(component, stream, + ¶ms->codec, + prtd->stream_id); + if (ret) { + dev_err(dev, "codec param setup failed ret:%d\n", ret); + return ret; + } + ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, (prtd->pcm_size / prtd->periods), prtd->periods); @@ -841,6 +945,55 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component, return 0; } +static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component, + struct snd_compr_stream *stream, + struct snd_compr_metadata *metadata) +{ + struct snd_compr_runtime *runtime = stream->runtime; + struct q6asm_dai_rtd *prtd = runtime->private_data; + int ret = 0; + + switch (metadata->key) { + case SNDRV_COMPRESS_ENCODER_PADDING: + prtd->trailing_samples_drop = metadata->value[0]; + break; + case SNDRV_COMPRESS_ENCODER_DELAY: + prtd->initial_samples_drop = metadata->value[0]; + if (prtd->next_track_stream_id) { + ret = q6asm_open_write(prtd->audio_client, + prtd->next_track_stream_id, + prtd->codec.id, + prtd->codec.profile, + prtd->bits_per_sample, + true); + if (ret < 0) { + dev_err(component->dev, "q6asm_open_write failed\n"); + return ret; + } + ret = __q6asm_dai_compr_set_codec_params(component, stream, + &prtd->codec, + prtd->next_track_stream_id); + if (ret < 0) { + dev_err(component->dev, "q6asm_open_write failed\n"); + return ret; + } + + ret = q6asm_stream_remove_initial_silence(prtd->audio_client, + prtd->next_track_stream_id, + prtd->initial_samples_drop); + prtd->next_track_stream_id = 0; + + } + + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + static int q6asm_dai_compr_trigger(struct snd_soc_component *component, struct snd_compr_stream *stream, int cmd) { @@ -852,15 +1005,26 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id, + 0, 0, 0); break; case SNDRV_PCM_TRIGGER_STOP: prtd->state = Q6ASM_STREAM_STOPPED; - ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS); + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_EOS); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE); + ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id, + CMD_PAUSE); + break; + case SND_COMPR_TRIGGER_NEXT_TRACK: + prtd->next_track = true; + prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1); + break; + case SND_COMPR_TRIGGER_DRAIN: + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + prtd->notify_on_drain = true; break; default: ret = -EINVAL; @@ -888,16 +1052,71 @@ static int q6asm_dai_compr_pointer(struct snd_soc_component *component, return 0; } -static int q6asm_dai_compr_ack(struct snd_soc_component *component, - struct snd_compr_stream *stream, - size_t count) +static int q6asm_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *stream, char __user *buf, + size_t count) { struct snd_compr_runtime *runtime = stream->runtime; struct q6asm_dai_rtd *prtd = runtime->private_data; unsigned long flags; + u32 wflags = 0; + int avail, bytes_in_flight = 0; + void *dstn; + size_t copy; + u32 app_pointer; + u32 bytes_received; + + bytes_received = prtd->bytes_received; + + /** + * Make sure that next track data pointer is aligned at 32 bit boundary + * This is a Mandatory requirement from DSP data buffers alignment + */ + if (prtd->next_track) + bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count); + + app_pointer = bytes_received/prtd->pcm_size; + app_pointer = bytes_received - (app_pointer * prtd->pcm_size); + dstn = prtd->dma_buffer.area + app_pointer; + + if (count < prtd->pcm_size - app_pointer) { + if (copy_from_user(dstn, buf, count)) + return -EFAULT; + } else { + copy = prtd->pcm_size - app_pointer; + if (copy_from_user(dstn, buf, copy)) + return -EFAULT; + if (copy_from_user(prtd->dma_buffer.area, buf + copy, + count - copy)) + return -EFAULT; + } spin_lock_irqsave(&prtd->lock, flags); - prtd->bytes_received += count; + + bytes_in_flight = prtd->bytes_received - prtd->copied_total; + + if (prtd->next_track) { + prtd->next_track = false; + prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count); + prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count); + } + + prtd->bytes_received = bytes_received + count; + + /* Kick off the data to dsp if its starving!! */ + if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) { + uint32_t bytes_to_write = prtd->pcm_count; + + avail = prtd->bytes_received - prtd->bytes_sent; + + if (avail < prtd->pcm_count) + bytes_to_write = avail; + + q6asm_write_async(prtd->audio_client, prtd->stream_id, + bytes_to_write, 0, 0, wflags); + prtd->bytes_sent += bytes_to_write; + } + spin_unlock_irqrestore(&prtd->lock, flags); return count; @@ -954,12 +1173,13 @@ static struct snd_compress_ops q6asm_dai_compress_ops = { .open = q6asm_dai_compr_open, .free = q6asm_dai_compr_free, .set_params = q6asm_dai_compr_set_params, + .set_metadata = q6asm_dai_compr_set_metadata, .pointer = q6asm_dai_compr_pointer, .trigger = q6asm_dai_compr_trigger, .get_caps = q6asm_dai_compr_get_caps, .get_codec_caps = q6asm_dai_compr_get_codec_caps, .mmap = q6asm_dai_compr_mmap, - .ack = q6asm_dai_compr_ack, + .copy = q6asm_compr_copy, }; static int q6asm_dai_pcm_new(struct snd_soc_component *component, diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 755062eadcc8..d745a02fcd5f 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -51,6 +51,8 @@ #define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D #define ASM_MEDIA_FMT_ALAC 0x00012f31 #define ASM_MEDIA_FMT_APE 0x00012f32 +#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67 +#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68 #define ASM_LEGACY_STREAM_SESSION 0 @@ -270,7 +272,6 @@ struct audio_client { wait_queue_head_t cmd_wait; struct aprv2_ibasic_rsp_result_t result; int perf_mode; - int stream_id; struct q6asm *q6asm; struct device *dev; }; @@ -640,6 +641,8 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, case ASM_STREAM_CMD_OPEN_READWRITE_V2: case ASM_STREAM_CMD_SET_ENCDEC_PARAM: case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: + case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: + case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: if (result->status != 0) { dev_err(ac->dev, "cmd = 0x%x returned error = 0x%x\n", @@ -671,6 +674,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, if (ac->io_mode & ASM_SYNC_IO_MODE) { phys_addr_t phys; unsigned long flags; + int token = hdr->token & ASM_WRITE_TOKEN_MASK; spin_lock_irqsave(&ac->lock, flags); @@ -682,12 +686,12 @@ static int32_t q6asm_stream_callback(struct apr_device *adev, goto done; } - phys = port->buf[hdr->token].phys; + phys = port->buf[token].phys; if (lower_32_bits(phys) != result->opcode || upper_32_bits(phys) != result->status) { dev_err(ac->dev, "Expected addr %pa\n", - &port->buf[hdr->token].phys); + &port->buf[token].phys); spin_unlock_irqrestore(&ac->lock, flags); ret = -EINVAL; goto done; @@ -828,21 +832,21 @@ EXPORT_SYMBOL_GPL(q6asm_get_session_id); * @dev: Pointer to asm child device. * @cb: event callback. * @priv: private data associated with this client. - * @stream_id: stream id + * @session_id: session id * @perf_mode: performace mode for this client * * Return: Will be an error pointer on error or a valid audio client * on success. */ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, - void *priv, int stream_id, + void *priv, int session_id, int perf_mode) { struct q6asm *a = dev_get_drvdata(dev->parent); struct audio_client *ac; unsigned long flags; - ac = q6asm_get_audio_client(a, stream_id + 1); + ac = q6asm_get_audio_client(a, session_id + 1); if (ac) { dev_err(dev, "Audio Client already active\n"); return ac; @@ -853,17 +857,15 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, return ERR_PTR(-ENOMEM); spin_lock_irqsave(&a->slock, flags); - a->session[stream_id + 1] = ac; + a->session[session_id + 1] = ac; spin_unlock_irqrestore(&a->slock, flags); - ac->session = stream_id + 1; + ac->session = session_id + 1; ac->cb = cb; ac->dev = dev; ac->q6asm = a; ac->priv = priv; ac->io_mode = ASM_SYNC_IO_MODE; ac->perf_mode = perf_mode; - /* DSP expects stream id from 1 */ - ac->stream_id = 1; ac->adev = a->adev; kref_init(&ac->refcount); @@ -919,8 +921,9 @@ err: * * Return: Will be an negative value on error or zero on success */ -int q6asm_open_write(struct audio_client *ac, uint32_t format, - u32 codec_profile, uint16_t bits_per_sample) +int q6asm_open_write(struct audio_client *ac, uint32_t stream_id, + uint32_t format, u32 codec_profile, + uint16_t bits_per_sample, bool is_gapless) { struct asm_stream_cmd_open_write_v3 *open; struct apr_pkt *pkt; @@ -935,11 +938,13 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format, pkt = p; open = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; open->mode_flags = 0x00; open->mode_flags |= ASM_LEGACY_STREAM_SESSION; + if (is_gapless) + open->mode_flags |= BIT(ASM_SHIFT_GAPLESS_MODE_FLAG); /* source endpoint : matrix */ open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; @@ -998,8 +1003,9 @@ err: } EXPORT_SYMBOL_GPL(q6asm_open_write); -static int __q6asm_run(struct audio_client *ac, uint32_t flags, - uint32_t msw_ts, uint32_t lsw_ts, bool wait) +static int __q6asm_run(struct audio_client *ac, uint32_t stream_id, + uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts, + bool wait) { struct asm_session_cmd_run_v2 *run; struct apr_pkt *pkt; @@ -1014,7 +1020,7 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags, pkt = p; run = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; run->flags = flags; @@ -1042,10 +1048,10 @@ static int __q6asm_run(struct audio_client *ac, uint32_t flags, * * Return: Will be an negative value on error or zero on success */ -int q6asm_run(struct audio_client *ac, uint32_t flags, +int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts) { - return __q6asm_run(ac, flags, msw_ts, lsw_ts, true); + return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, true); } EXPORT_SYMBOL_GPL(q6asm_run); @@ -1053,16 +1059,17 @@ EXPORT_SYMBOL_GPL(q6asm_run); * q6asm_run_nowait() - start the audio client withou blocking * * @ac: audio client pointer + * @stream_id: stream id * @flags: flags associated with write * @msw_ts: timestamp msw * @lsw_ts: timestamp lsw * * Return: Will be an negative value on error or zero on success */ -int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, - uint32_t msw_ts, uint32_t lsw_ts) +int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id, + uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts) { - return __q6asm_run(ac, flags, msw_ts, lsw_ts, false); + return __q6asm_run(ac, stream_id, flags, msw_ts, lsw_ts, false); } EXPORT_SYMBOL_GPL(q6asm_run_nowait); @@ -1070,6 +1077,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait); * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration * * @ac: audio client pointer + * @stream_id: stream id * @rate: audio sample rate * @channels: number of audio channels. * @channel_map: channel map pointer @@ -1078,6 +1086,7 @@ EXPORT_SYMBOL_GPL(q6asm_run_nowait); * Return: Will be an negative value on error or zero on success */ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t stream_id, uint32_t rate, uint32_t channels, u8 channel_map[PCM_MAX_NUM_CHANNEL], uint16_t bits_per_sample) @@ -1096,7 +1105,7 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1125,8 +1134,8 @@ err: } EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); - int q6asm_stream_media_format_block_flac(struct audio_client *ac, + uint32_t stream_id, struct q6asm_flac_cfg *cfg) { struct asm_flac_fmt_blk_v2 *fmt; @@ -1142,7 +1151,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1163,6 +1172,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac, EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, + uint32_t stream_id, struct q6asm_wma_cfg *cfg) { struct asm_wmastdv9_fmt_blk_v2 *fmt; @@ -1178,7 +1188,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1200,6 +1210,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9); int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, + uint32_t stream_id, struct q6asm_wma_cfg *cfg) { struct asm_wmaprov10_fmt_blk_v2 *fmt; @@ -1215,7 +1226,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1238,6 +1249,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10); int q6asm_stream_media_format_block_alac(struct audio_client *ac, + uint32_t stream_id, struct q6asm_alac_cfg *cfg) { struct asm_alac_fmt_blk_v2 *fmt; @@ -1253,7 +1265,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1279,6 +1291,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac, EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac); int q6asm_stream_media_format_block_ape(struct audio_client *ac, + uint32_t stream_id, struct q6asm_ape_cfg *cfg) { struct asm_ape_fmt_blk_v2 *fmt; @@ -1294,7 +1307,7 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac, pkt = p; fmt = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); @@ -1317,10 +1330,60 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac, } EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape); +static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_id, + uint32_t cmd, + uint32_t num_samples) +{ + uint32_t *samples; + struct apr_pkt *pkt; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(uint32_t); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + samples = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); + + pkt->hdr.opcode = cmd; + *samples = num_samples; + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + + kfree(pkt); + + return rc; +} + +int q6asm_stream_remove_initial_silence(struct audio_client *ac, + uint32_t stream_id, + uint32_t initial_samples) +{ + return q6asm_stream_remove_silence(ac, stream_id, + ASM_DATA_CMD_REMOVE_INITIAL_SILENCE, + initial_samples); +} +EXPORT_SYMBOL_GPL(q6asm_stream_remove_initial_silence); + +int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t stream_id, + uint32_t trailing_samples) +{ + return q6asm_stream_remove_silence(ac, stream_id, + ASM_DATA_CMD_REMOVE_TRAILING_SILENCE, + trailing_samples); +} +EXPORT_SYMBOL_GPL(q6asm_stream_remove_trailing_silence); + /** * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture * * @ac: audio client pointer + * @stream_id: stream id * @rate: audio sample rate * @channels: number of audio channels. * @bits_per_sample: bits per sample @@ -1328,7 +1391,9 @@ EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape); * Return: Will be an negative value on error or zero on success */ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, - uint32_t rate, uint32_t channels, uint16_t bits_per_sample) + uint32_t stream_id, uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample) { struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; struct apr_pkt *pkt; @@ -1344,7 +1409,7 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, pkt = p; enc_cfg = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; @@ -1376,10 +1441,11 @@ EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); * q6asm_read() - read data of period size from audio client * * @ac: audio client pointer + * @stream_id: stream id * * Return: Will be an negative value on error or zero on success */ -int q6asm_read(struct audio_client *ac) +int q6asm_read(struct audio_client *ac, uint32_t stream_id) { struct asm_data_cmd_read_v2 *read; struct audio_port_data *port; @@ -1400,7 +1466,7 @@ int q6asm_read(struct audio_client *ac) spin_lock_irqsave(&ac->lock, flags); port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); ab = &port->buf[port->dsp_buf]; pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; read->buf_addr_lsw = lower_32_bits(ab->phys); @@ -1428,7 +1494,7 @@ int q6asm_read(struct audio_client *ac) } EXPORT_SYMBOL_GPL(q6asm_read); -static int __q6asm_open_read(struct audio_client *ac, +static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id, uint32_t format, uint16_t bits_per_sample) { struct asm_stream_cmd_open_read_v3 *open; @@ -1444,7 +1510,7 @@ static int __q6asm_open_read(struct audio_client *ac, pkt = p; open = p + APR_HDR_SIZE; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, stream_id); pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; /* Stream prio : High, provide meta info with encoded frames */ open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; @@ -1475,15 +1541,16 @@ static int __q6asm_open_read(struct audio_client *ac, * q6asm_open_read() - Open audio client for reading * * @ac: audio client pointer + * @stream_id: stream id * @format: audio sample format * @bits_per_sample: bits per sample * * Return: Will be an negative value on error or zero on success */ -int q6asm_open_read(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample) +int q6asm_open_read(struct audio_client *ac, uint32_t stream_id, + uint32_t format, uint16_t bits_per_sample) { - return __q6asm_open_read(ac, format, bits_per_sample); + return __q6asm_open_read(ac, stream_id, format, bits_per_sample); } EXPORT_SYMBOL_GPL(q6asm_open_read); @@ -1491,6 +1558,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read); * q6asm_write_async() - non blocking write * * @ac: audio client pointer + * @stream_id: stream id * @len: length in bytes * @msw_ts: timestamp msw * @lsw_ts: timestamp lsw @@ -1498,8 +1566,8 @@ EXPORT_SYMBOL_GPL(q6asm_open_read); * * Return: Will be an negative value on error or zero on success */ -int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, - uint32_t lsw_ts, uint32_t wflags) +int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len, + uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags) { struct asm_data_cmd_write_v2 *write; struct audio_port_data *port; @@ -1520,10 +1588,10 @@ int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, spin_lock_irqsave(&ac->lock, flags); port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; - q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, stream_id); ab = &port->buf[port->dsp_buf]; - pkt->hdr.token = port->dsp_buf; + pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT); pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; write->buf_addr_lsw = lower_32_bits(ab->phys); write->buf_addr_msw = upper_32_bits(ab->phys); @@ -1534,10 +1602,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, write->mem_map_handle = ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; - if (wflags == NO_TIMESTAMP) - write->flags = (wflags & 0x800000FF); - else - write->flags = (0x80000000 | wflags); + write->flags = wflags; port->dsp_buf++; @@ -1567,9 +1632,9 @@ static void q6asm_reset_buf_state(struct audio_client *ac) spin_unlock_irqrestore(&ac->lock, flags); } -static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait) +static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd, + bool wait) { - int stream_id = ac->stream_id; struct apr_pkt pkt; int rc; @@ -1616,13 +1681,14 @@ static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait) * q6asm_cmd() - run cmd on audio client * * @ac: audio client pointer + * @stream_id: stream id * @cmd: command to run on audio client. * * Return: Will be an negative value on error or zero on success */ -int q6asm_cmd(struct audio_client *ac, int cmd) +int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd) { - return __q6asm_cmd(ac, cmd, true); + return __q6asm_cmd(ac, stream_id, cmd, true); } EXPORT_SYMBOL_GPL(q6asm_cmd); @@ -1630,13 +1696,14 @@ EXPORT_SYMBOL_GPL(q6asm_cmd); * q6asm_cmd_nowait() - non blocking, run cmd on audio client * * @ac: audio client pointer + * @stream_id: stream id * @cmd: command to run on audio client. * * Return: Will be an negative value on error or zero on success */ -int q6asm_cmd_nowait(struct audio_client *ac, int cmd) +int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd) { - return __q6asm_cmd(ac, cmd, false); + return __q6asm_cmd(ac, stream_id, cmd, false); } EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 38a207d6cd95..82e584aa534f 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -20,6 +20,9 @@ #define ASM_CLIENT_EVENT_CMD_RUN_DONE 0x1008 #define ASM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009 #define ASM_CLIENT_EVENT_DATA_READ_DONE 0x100a +#define ASM_WRITE_TOKEN_MASK GENMASK(15, 0) +#define ASM_WRITE_TOKEN_LEN_MASK GENMASK(31, 16) +#define ASM_WRITE_TOKEN_LEN_SHIFT 16 enum { LEGACY_PCM_MODE = 0, @@ -29,8 +32,8 @@ enum { }; #define MAX_SESSIONS 8 -#define NO_TIMESTAMP 0xFF00 #define FORMAT_LINEAR_PCM 0x0000 +#define ASM_LAST_BUFFER_FLAG BIT(30) struct q6asm_flac_cfg { u32 sample_rate; @@ -93,37 +96,53 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, void *priv, int session_id, int perf_mode); void q6asm_audio_client_free(struct audio_client *ac); -int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, - uint32_t lsw_ts, uint32_t flags); -int q6asm_open_write(struct audio_client *ac, uint32_t format, - u32 codec_profile, uint16_t bits_per_sample); +int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len, + uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags); +int q6asm_open_write(struct audio_client *ac, uint32_t stream_id, + uint32_t format, u32 codec_profile, + uint16_t bits_per_sample, bool is_gapless); -int q6asm_open_read(struct audio_client *ac, uint32_t format, - uint16_t bits_per_sample); +int q6asm_open_read(struct audio_client *ac, uint32_t stream_id, + uint32_t format, uint16_t bits_per_sample); int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, - uint32_t rate, uint32_t channels, uint16_t bits_per_sample); -int q6asm_read(struct audio_client *ac); + uint32_t stream_id, uint32_t rate, + uint32_t channels, + uint16_t bits_per_sample); + +int q6asm_read(struct audio_client *ac, uint32_t stream_id); int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t stream_id, uint32_t rate, uint32_t channels, u8 channel_map[PCM_MAX_NUM_CHANNEL], uint16_t bits_per_sample); int q6asm_stream_media_format_block_flac(struct audio_client *ac, + uint32_t stream_id, struct q6asm_flac_cfg *cfg); int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac, + uint32_t stream_id, struct q6asm_wma_cfg *cfg); int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac, + uint32_t stream_id, struct q6asm_wma_cfg *cfg); int q6asm_stream_media_format_block_alac(struct audio_client *ac, + uint32_t stream_id, struct q6asm_alac_cfg *cfg); int q6asm_stream_media_format_block_ape(struct audio_client *ac, + uint32_t stream_id, struct q6asm_ape_cfg *cfg); -int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, - uint32_t lsw_ts); -int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, - uint32_t lsw_ts); -int q6asm_cmd(struct audio_client *ac, int cmd); -int q6asm_cmd_nowait(struct audio_client *ac, int cmd); +int q6asm_run(struct audio_client *ac, uint32_t stream_id, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts); +int q6asm_run_nowait(struct audio_client *ac, uint32_t stream_id, + uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts); +int q6asm_stream_remove_initial_silence(struct audio_client *ac, + uint32_t stream_id, + uint32_t initial_samples); +int q6asm_stream_remove_trailing_silence(struct audio_client *ac, + uint32_t stream_id, + uint32_t trailing_samples); +int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd); +int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd); int q6asm_get_session_id(struct audio_client *ac); int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index b8f0057a0510..8aa78ff640f5 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -15,9 +15,6 @@ #include <sound/jack.h> #include "regs-iis.h" -#include <asm/mach-types.h> - -#include <mach/gpio-samsung.h> #include "s3c24xx-i2s.h" static const unsigned int rates[] = { @@ -31,6 +28,8 @@ static const struct snd_pcm_hw_constraint_list hw_rates = { .list = rates, }; +static struct gpio_desc *gpiod_speaker_power; + static struct snd_soc_jack hp_jack; static struct snd_soc_jack_pin hp_jack_pins[] = { @@ -47,7 +46,6 @@ static struct snd_soc_jack_pin hp_jack_pins[] = { static struct snd_soc_jack_gpio hp_jack_gpios[] = { { - .gpio = S3C2410_GPG(4), .name = "hp-gpio", .report = SND_JACK_HEADPHONE, .invert = 1, @@ -123,9 +121,9 @@ static int h1940_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(S3C_GPIO_END + 9, 1); + gpiod_set_value(gpiod_speaker_power, 1); else - gpio_set_value(S3C_GPIO_END + 9, 0); + gpiod_set_value(gpiod_speaker_power, 0); return 0; } @@ -151,8 +149,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"VINM", NULL, "Mic Jack"}, }; -static struct platform_device *s3c24xx_snd_device; - static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) { snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, @@ -194,55 +190,34 @@ static struct snd_soc_card h1940_asoc = { .num_dapm_routes = ARRAY_SIZE(audio_map), }; -static int __init h1940_init(void) +static int h1940_probe(struct platform_device *pdev) { - int ret; + struct device *dev = &pdev->dev; - if (!machine_is_h1940()) - return -ENODEV; + h1940_asoc.dev = dev; + hp_jack_gpios[0].gpiod_dev = dev; + gpiod_speaker_power = devm_gpiod_get(&pdev->dev, "speaker-power", + GPIOD_OUT_LOW); - /* configure some gpios */ - ret = gpio_request(S3C_GPIO_END + 9, "speaker-power"); - if (ret) - goto err_out; - - ret = gpio_direction_output(S3C_GPIO_END + 9, 0); - if (ret) - goto err_gpio; - - s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); - if (!s3c24xx_snd_device) { - ret = -ENOMEM; - goto err_gpio; + if (IS_ERR(gpiod_speaker_power)) { + dev_err(dev, "Could not get gpio\n"); + return PTR_ERR(gpiod_speaker_power); } - platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc); - ret = platform_device_add(s3c24xx_snd_device); - - if (ret) - goto err_plat; - - return 0; - -err_plat: - platform_device_put(s3c24xx_snd_device); -err_gpio: - gpio_free(S3C_GPIO_END + 9); - -err_out: - return ret; -} - -static void __exit h1940_exit(void) -{ - platform_device_unregister(s3c24xx_snd_device); - gpio_free(S3C_GPIO_END + 9); + return devm_snd_soc_register_card(dev, &h1940_asoc); } -module_init(h1940_init); -module_exit(h1940_exit); +static struct platform_driver h1940_audio_driver = { + .driver = { + .name = "h1940-audio", + .pm = &snd_soc_pm_ops, + }, + .probe = h1940_probe, +}; +module_platform_driver(h1940_audio_driver); /* Module information */ MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick"); MODULE_DESCRIPTION("ALSA SoC H1940"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:h1940-audio"); diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 54317e0f68f8..9266070e0181 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -11,14 +11,11 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <sound/soc.h> -#include <mach/gpio-samsung.h> -#include <asm/mach-types.h> #include "regs-iis.h" - #include "../codecs/wm8753.h" #include "s3c24xx-i2s.h" @@ -166,6 +163,7 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, }; +static struct gpio_desc *gpiod_hp_in, *gpiod_amp_shut; static int gta02_speaker_enabled; static int lm4853_set_spk(struct snd_kcontrol *kcontrol, @@ -173,7 +171,7 @@ static int lm4853_set_spk(struct snd_kcontrol *kcontrol, { gta02_speaker_enabled = ucontrol->value.integer.value[0]; - gpio_set_value(S3C2410_GPJ(2), !gta02_speaker_enabled); + gpiod_set_value(gpiod_hp_in, !gta02_speaker_enabled); return 0; } @@ -188,7 +186,7 @@ static int lm4853_get_spk(struct snd_kcontrol *kcontrol, static int lm4853_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(S3C2410_GPJ(1), SND_SOC_DAPM_EVENT_OFF(event)); + gpiod_set_value(gpiod_amp_shut, SND_SOC_DAPM_EVENT_OFF(event)); return 0; } @@ -308,13 +306,8 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = { }, }; -static const struct gpio neo1973_gta02_gpios[] = { - { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, - { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, -}; - static struct snd_soc_card neo1973 = { - .name = "neo1973", + .name = "neo1973gta02", .owner = THIS_MODULE, .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), @@ -332,62 +325,36 @@ static struct snd_soc_card neo1973 = { .fully_routed = true, }; -static struct platform_device *neo1973_snd_device; - -static int __init neo1973_init(void) +static int neo1973_probe(struct platform_device *pdev) { - int ret; - - if (!machine_is_neo1973_gta02()) - return -ENODEV; + struct device *dev = &pdev->dev; - if (machine_is_neo1973_gta02()) { - neo1973.name = "neo1973gta02"; - neo1973.num_aux_devs = 1; - - ret = gpio_request_array(neo1973_gta02_gpios, - ARRAY_SIZE(neo1973_gta02_gpios)); - if (ret) - return ret; + gpiod_hp_in = devm_gpiod_get(dev, "hp", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_hp_in)) { + dev_err(dev, "missing gpio %s\n", "hp"); + return PTR_ERR(gpiod_hp_in); } - - neo1973_snd_device = platform_device_alloc("soc-audio", -1); - if (!neo1973_snd_device) { - ret = -ENOMEM; - goto err_gpio_free; + gpiod_amp_shut = devm_gpiod_get(dev, "amp-shut", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_amp_shut)) { + dev_err(dev, "missing gpio %s\n", "amp-shut"); + return PTR_ERR(gpiod_amp_shut); } - platform_set_drvdata(neo1973_snd_device, &neo1973); - ret = platform_device_add(neo1973_snd_device); - - if (ret) - goto err_put_device; - - return 0; - -err_put_device: - platform_device_put(neo1973_snd_device); -err_gpio_free: - if (machine_is_neo1973_gta02()) { - gpio_free_array(neo1973_gta02_gpios, - ARRAY_SIZE(neo1973_gta02_gpios)); - } - return ret; + neo1973.dev = dev; + return devm_snd_soc_register_card(dev, &neo1973); } -module_init(neo1973_init); - -static void __exit neo1973_exit(void) -{ - platform_device_unregister(neo1973_snd_device); - if (machine_is_neo1973_gta02()) { - gpio_free_array(neo1973_gta02_gpios, - ARRAY_SIZE(neo1973_gta02_gpios)); - } -} -module_exit(neo1973_exit); +struct platform_driver neo1973_audio = { + .driver = { + .name = "neo1973-audio", + .pm = &snd_soc_pm_ops, + }, + .probe = neo1973_probe, +}; +module_platform_driver(neo1973_audio); /* Module information */ MODULE_AUTHOR("Graeme Gregory, [email protected], www.openmoko.org"); MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:neo1973-audio"); diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 08f7c82aedb6..400a7f77c711 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -12,16 +12,13 @@ // Vasily Khoruzhick <[email protected]> #include <linux/types.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include <sound/soc.h> #include <sound/jack.h> -#include <mach/gpio-samsung.h> #include "regs-iis.h" -#include <asm/mach-types.h> - #include "s3c24xx-i2s.h" static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); @@ -58,7 +55,6 @@ static struct snd_soc_jack_pin hp_jack_pins[] = { static struct snd_soc_jack_gpio hp_jack_gpios[] = { [0] = { - .gpio = S3C2410_GPG(12), .name = "hp-gpio", .report = SND_JACK_HEADPHONE, .invert = 1, @@ -123,8 +119,6 @@ static struct snd_soc_card rx1950_asoc = { .num_dapm_routes = ARRAY_SIZE(audio_map), }; -static struct platform_device *s3c24xx_snd_device; - static int rx1950_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -134,13 +128,15 @@ static int rx1950_startup(struct snd_pcm_substream *substream) &hw_rates); } +struct gpio_desc *gpiod_speaker_power; + static int rx1950_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(S3C2410_GPA(1), 1); + gpiod_set_value(gpiod_speaker_power, 1); else - gpio_set_value(S3C2410_GPA(1), 0); + gpiod_set_value(gpiod_speaker_power, 0); return 0; } @@ -214,57 +210,35 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int __init rx1950_init(void) +static int rx1950_probe(struct platform_device *pdev) { - int ret; - - if (!machine_is_rx1950()) - return -ENODEV; + struct device *dev = &pdev->dev; /* configure some gpios */ - ret = gpio_request(S3C2410_GPA(1), "speaker-power"); - if (ret) - goto err_gpio; - - ret = gpio_direction_output(S3C2410_GPA(1), 0); - if (ret) - goto err_gpio_conf; - - s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); - if (!s3c24xx_snd_device) { - ret = -ENOMEM; - goto err_plat_alloc; - } - - platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc); - ret = platform_device_add(s3c24xx_snd_device); - - if (ret) { - platform_device_put(s3c24xx_snd_device); - goto err_plat_add; + gpiod_speaker_power = devm_gpiod_get(dev, "speaker-power", GPIOD_OUT_LOW); + if (IS_ERR(gpiod_speaker_power)) { + dev_err(dev, "cannot get gpio\n"); + return PTR_ERR(gpiod_speaker_power); } - return 0; - -err_plat_add: -err_plat_alloc: -err_gpio_conf: - gpio_free(S3C2410_GPA(1)); + hp_jack_gpios[0].gpiod_dev = dev; + rx1950_asoc.dev = dev; -err_gpio: - return ret; + return devm_snd_soc_register_card(dev, &rx1950_asoc); } -static void __exit rx1950_exit(void) -{ - platform_device_unregister(s3c24xx_snd_device); - gpio_free(S3C2410_GPA(1)); -} +struct platform_driver rx1950_audio = { + .driver = { + .name = "rx1950-audio", + .pm = &snd_soc_pm_ops, + }, + .probe = rx1950_probe, +}; -module_init(rx1950_init); -module_exit(rx1950_exit); +module_platform_driver(rx1950_audio); /* Module information */ MODULE_AUTHOR("Vasily Khoruzhick"); MODULE_DESCRIPTION("ALSA SoC RX1950"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rx1950-audio"); diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index ed21786104a1..e9481187a08c 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -616,8 +616,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate); int s3c_i2sv2_probe(struct snd_soc_dai *dai, - struct s3c_i2sv2_info *i2s, - unsigned long base) + struct s3c_i2sv2_info *i2s) { struct device *dev = dai->dev; unsigned int iismod; diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index fe42b77999fd..8c6fc0d3d77e 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -83,8 +83,7 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, * @base: The base address for the registers. */ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, - struct s3c_i2sv2_info *i2s, - unsigned long base); + struct s3c_i2sv2_info *i2s); /** * s3c_i2sv2_cleanup - cleanup resources allocated in s3c_i2sv2_probe diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index b35d828c1cfe..edfa9d11d2e5 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -49,7 +49,7 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) snd_soc_dai_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out, &s3c2412_i2s_pcm_stereo_in); - ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS); + ret = s3c_i2sv2_probe(dai, &s3c2412_i2s); if (ret) return ret; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2fe1b2ec7c8f..681df493bb98 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -44,8 +44,6 @@ #define CREATE_TRACE_POINTS #include <trace/events/asoc.h> -#define NAME_SIZE 32 - static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); static LIST_HEAD(unbind_card_list); @@ -834,6 +832,19 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); +struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc) +{ + struct snd_soc_dai *dai; + + mutex_lock(&client_mutex); + dai = snd_soc_find_dai(dlc); + mutex_unlock(&client_mutex); + + return dai; +} +EXPORT_SYMBOL_GPL(snd_soc_find_dai_with_mutex); + static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { @@ -2218,13 +2229,14 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_card); */ static char *fmt_single_name(struct device *dev, int *id) { - char *found, name[NAME_SIZE]; + const char *devname = dev_name(dev); + char *found, *name; int id1, id2; - if (dev_name(dev) == NULL) + if (devname == NULL) return NULL; - strlcpy(name, dev_name(dev), NAME_SIZE); + name = devm_kstrdup(dev, devname, GFP_KERNEL); /* are we a "%s.%d" name (platform and SPI components) */ found = strstr(name, dev->driver->name); @@ -2237,23 +2249,21 @@ static char *fmt_single_name(struct device *dev, int *id) found[strlen(dev->driver->name)] = '\0'; } - } else { - /* I2C component devices are named "bus-addr" */ - if (sscanf(name, "%x-%x", &id1, &id2) == 2) { - char tmp[NAME_SIZE]; + /* I2C component devices are named "bus-addr" */ + } else if (sscanf(name, "%x-%x", &id1, &id2) == 2) { - /* create unique ID number from I2C addr and bus */ - *id = ((id1 & 0xffff) << 16) + id2; + /* create unique ID number from I2C addr and bus */ + *id = ((id1 & 0xffff) << 16) + id2; - /* sanitize component name for DAI link creation */ - snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, - name); - strlcpy(name, tmp, NAME_SIZE); - } else - *id = 0; + devm_kfree(dev, name); + + /* sanitize component name for DAI link creation */ + name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", dev->driver->name, devname); + } else { + *id = 0; } - return devm_kstrdup(dev, name, GFP_KERNEL); + return name; } /* @@ -2827,6 +2837,37 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); +int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname) +{ + struct device_node *node = card->dev->of_node; + struct snd_soc_aux_dev *aux; + int num, i; + + num = of_count_phandle_with_args(node, propname, NULL); + if (num == -ENOENT) { + return 0; + } else if (num < 0) { + dev_err(card->dev, "ASOC: Property '%s' could not be read: %d\n", + propname, num); + return num; + } + + aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL); + if (!aux) + return -ENOMEM; + card->aux_dev = aux; + card->num_aux_devs = num; + + for_each_card_pre_auxs(card, i, aux) { + aux->dlc.of_node = of_parse_phandle(node, propname, i); + if (!aux->dlc.of_node) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs); + unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, struct device_node **bitclkmaster, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 91a2551e4cef..0dbd312aad08 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -412,14 +412,14 @@ void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link) supported_codec = false; for_each_link_cpus(dai_link, i, cpu) { - dai = snd_soc_find_dai(cpu); + dai = snd_soc_find_dai_with_mutex(cpu); if (dai && snd_soc_dai_stream_valid(dai, direction)) { supported_cpu = true; break; } } for_each_link_codecs(dai_link, i, codec) { - dai = snd_soc_find_dai(codec); + dai = snd_soc_find_dai_with_mutex(codec); if (dai && snd_soc_dai_stream_valid(dai, direction)) { supported_codec = true; break; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index cee998671318..28faaf58326e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -603,10 +603,11 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, sbe->get = ext_ops[i].get; } - if (sbe->put && sbe->get) - return 0; - else + if ((k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) && !sbe->get) return -EINVAL; + if ((k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) && !sbe->put) + return -EINVAL; + return 0; } /* try and map vendor specific kcontrol handlers first */ diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 4dda4b62509f..8c1f0829de40 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -73,7 +73,7 @@ config SND_SOC_SOF_NOCODEC_SUPPORT option if no known codec is detected. This is typically only enabled for developers or devices where the sound card is controlled externally - This option is mutually exclusive with the Intel HDaudio support, + This option is mutually exclusive with the Intel HDAudio support, selecting it may have negative impacts and prevent e.g. microphone functionality from being enabled on Intel CoffeeLake and later platforms. diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 186eea105bb1..d5e2966cafac 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -353,6 +353,64 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return 0; } +int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, + unsigned int size) +{ + struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_soc_component *scomp = scontrol->scomp; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_ctl_tlv header; + struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; + size_t data_size; + int ret; + int err; + + ret = pm_runtime_get_sync(scomp->dev); + if (ret < 0) { + dev_err_ratelimited(scomp->dev, "error: bytes_ext get failed to resume %d\n", ret); + pm_runtime_put_noidle(scomp->dev); + return ret; + } + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + /* get all the component data from DSP */ + ret = snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_GET_DATA, SOF_CTRL_TYPE_DATA_GET, + scontrol->cmd, false); + if (ret < 0) + goto out; + + /* check data size doesn't exceed max coming from topology */ + if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { + dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", + cdata->data->size, + be->max - sizeof(const struct sof_abi_hdr)); + ret = -EINVAL; + goto out; + } + + data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + + header.numid = scontrol->cmd; + header.length = data_size; + if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { + ret = -EFAULT; + goto out; + } + + if (copy_to_user(tlvd->tlv, cdata->data, data_size)) + ret = -EFAULT; +out: + pm_runtime_mark_last_busy(scomp->dev); + err = pm_runtime_put_autosuspend(scomp->dev); + if (err < 0) + dev_err_ratelimited(scomp->dev, "error: bytes_ext get failed to idle %d\n", err); + + return ret; +} + int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, unsigned int size) diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 8230285baa43..23bfd79d09c3 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -30,6 +30,7 @@ config SND_SOC_SOF_IMX8_SUPPORT config SND_SOC_SOF_IMX8 tristate + select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -44,6 +45,7 @@ config SND_SOC_SOF_IMX8M_SUPPORT config SND_SOC_SOF_IMX8M tristate + select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index bc0628c7b88c..3b9ffc760cb5 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -126,7 +126,7 @@ static struct imx_dsp_ops dsp_ops = { static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + struct imx8_priv *priv = sdev->pdata->hw_pdata; sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); @@ -140,7 +140,7 @@ static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) */ static int imx8x_run(struct snd_sof_dev *sdev) { - struct imx8_priv *dsp_priv = (struct imx8_priv *)sdev->private; + struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; int ret; ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, @@ -180,7 +180,7 @@ static int imx8x_run(struct snd_sof_dev *sdev) static int imx8_run(struct snd_sof_dev *sdev) { - struct imx8_priv *dsp_priv = (struct imx8_priv *)sdev->private; + struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; int ret; ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, @@ -213,7 +213,7 @@ static int imx8_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; - sdev->private = priv; + sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; @@ -339,7 +339,7 @@ exit_unroll_pm: static int imx8_remove(struct snd_sof_dev *sdev) { - struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + struct imx8_priv *priv = sdev->pdata->hw_pdata; int i; platform_device_unregister(priv->ipc_dev); @@ -424,6 +424,9 @@ struct snd_sof_dsp_ops sof_imx8_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Firmware ops */ + .arch_ops = &sof_xtensa_arch_ops, + /* DAI drivers */ .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), @@ -464,6 +467,9 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Firmware ops */ + .arch_ops = &sof_xtensa_arch_ops, + /* DAI drivers */ .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), @@ -477,4 +483,5 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { }; EXPORT_SYMBOL(sof_imx8x_ops); +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 86320941fcee..ca23ac99a63d 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -99,7 +99,7 @@ static struct imx_dsp_ops imx8m_dsp_ops = { static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private; + struct imx8m_priv *priv = sdev->pdata->hw_pdata; sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); @@ -133,7 +133,7 @@ static int imx8m_probe(struct snd_sof_dev *sdev) if (!priv) return -ENOMEM; - sdev->private = priv; + sdev->pdata->hw_pdata = priv; priv->dev = sdev->dev; priv->sdev = sdev; @@ -209,7 +209,7 @@ exit_pdev_unregister: static int imx8m_remove(struct snd_sof_dev *sdev) { - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private; + struct imx8m_priv *priv = sdev->pdata->hw_pdata; platform_device_unregister(priv->ipc_dev); @@ -277,6 +277,9 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Firmware ops */ + .arch_ops = &sof_xtensa_arch_ops, + /* DAI drivers */ .drv = imx8m_dai, .num_drv = ARRAY_SIZE(imx8m_dai), @@ -289,4 +292,5 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { }; EXPORT_SYMBOL(sof_imx8m_ops); +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 3aaf25e4f766..a066e08860cb 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -166,6 +166,7 @@ config SND_SOC_SOF_CANNONLAKE_SUPPORT config SND_SOC_SOF_CANNONLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -181,6 +182,7 @@ config SND_SOC_SOF_COFFEELAKE_SUPPORT config SND_SOC_SOF_COFFEELAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -196,6 +198,7 @@ config SND_SOC_SOF_ICELAKE_SUPPORT config SND_SOC_SOF_ICELAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -203,6 +206,7 @@ config SND_SOC_SOF_ICELAKE config SND_SOC_SOF_COMETLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -229,6 +233,7 @@ config SND_SOC_SOF_TIGERLAKE_SUPPORT config SND_SOC_SOF_TIGERLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -244,6 +249,7 @@ config SND_SOC_SOF_ELKHARTLAKE_SUPPORT config SND_SOC_SOF_ELKHARTLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -305,7 +311,7 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 bool "SOF enable DMI Link L1" help This option enables DMI L1 for both playback and capture - and disables known workarounds for specific HDaudio platforms. + and disables known workarounds for specific HDAudio platforms. Only use to look into power optimizations on platforms not affected by DMI L1 issues. This option is not recommended. Say Y if you want to enable DMI Link L1 @@ -329,6 +335,29 @@ config SND_SOC_SOF_HDA This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK + bool "SOF support for SoundWire" + depends on SOUNDWIRE && ACPI + help + This adds support for SoundWire with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enable SoundWire links with SOF. + If unsure select "N". + +config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + tristate + select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_SOUNDWIRE + tristate + select SOUNDWIRE_INTEL + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + endif ## SND_SOC_SOF_INTEL_PCI endif ## SND_SOC_SOF_INTEL_TOPLEVEL diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index f7e9358f1f06..72d85b25df7d 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ - apl.o cnl.o + apl.o cnl.o tgl.o snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o snd-sof-intel-hda-objs := hda-codec.o diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 16db0f50d139..70f14b2aa954 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -29,7 +29,7 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { static void cnl_ipc_host_done(struct snd_sof_dev *sdev); static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); -static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) +irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; u32 hipci; @@ -163,8 +163,7 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, return false; } -static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) +int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc_cmd_hdr *hdr; @@ -202,7 +201,7 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, * IPCs are sent at a high-rate. mod_delayed_work() * modifies the timer if the work is pending. * Also, a new delayed work should not be queued after the - * the CTX_SAVE IPC, which is sent before the DSP enters D3. + * CTX_SAVE IPC, which is sent before the DSP enters D3. */ if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) mod_delayed_work(system_wq, &hdev->d0i3_work, @@ -211,7 +210,7 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, return 0; } -static void cnl_ipc_dump(struct snd_sof_dev *sdev) +void cnl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcctl; u32 hipcida; @@ -369,22 +368,6 @@ const struct sof_intel_dsp_desc icl_chip_info = { }; EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -const struct sof_intel_dsp_desc tgl_chip_info = { - /* Tigerlake */ - .cores_num = 4, - .init_core_mask = 1, - .cores_mask = HDA_DSP_CORE_MASK(0), - .ipc_req = CNL_DSP_REG_HIPCIDR, - .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, - .ipc_ack = CNL_DSP_REG_HIPCIDA, - .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, - .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, - .ssp_base_offset = CNL_SSP_BASE_OFFSET, -}; -EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); - const struct sof_intel_dsp_desc ehl_chip_info = { /* Elkhartlake */ .cores_num = 4, diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 2c5c451fa19d..f6ba3b593e1f 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -116,10 +116,10 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; + struct hda_codec *codec; #endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; - struct hda_codec *codec; u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -151,7 +151,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, if (!hdev->bus->audio_component) { dev_dbg(sdev->dev, "iDisp hw present but no driver\n"); - return -ENOENT; + goto error; } hda_priv->need_display_power = true; } @@ -174,10 +174,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, * other return codes without modification */ if (ret == 0) - ret = -ENOENT; + goto error; } return ret; + +error: + snd_hdac_ext_bus_device_exit(hdev); + return -ENOENT; + #else hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h index ade4c3191a39..10fbca5939db 100644 --- a/sound/soc/sof/intel/hda-ipc.h +++ b/sound/soc/sof/intel/hda-ipc.h @@ -48,4 +48,8 @@ #define HDA_PM_PG_STREAMING BIT(1) #define HDA_PM_PG_RSVD BIT(0) +irqreturn_t cnl_ipc_irq_thread(int irq, void *context); +int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); +void cnl_ipc_dump(struct snd_sof_dev *sdev); + #endif diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 441d05cda604..70727495fdbf 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -17,31 +17,28 @@ #include <linux/firmware.h> #include <sound/hdaudio_ext.h> +#include <sound/hda_register.h> #include <sound/sof.h> #include "../ops.h" #include "hda.h" #define HDA_FW_BOOT_ATTEMPTS 3 +#define HDA_CL_STREAM_FORMAT 0x40 -static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab, - int direction) +static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, + unsigned int size, struct snd_dma_buffer *dmab, + int direction) { struct hdac_ext_stream *dsp_stream; struct hdac_stream *hstream; struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; - if (direction != SNDRV_PCM_STREAM_PLAYBACK) { - dev_err(sdev->dev, "error: code loading DMA is playback only\n"); - return -EINVAL; - } - dsp_stream = hda_dsp_stream_get(sdev, direction); if (!dsp_stream) { dev_err(sdev->dev, "error: no stream available\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } hstream = &dsp_stream->hstream; hstream->substream = NULL; @@ -57,20 +54,27 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, hstream->format_val = format; hstream->bufsize = size; - ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); - if (ret < 0) { - dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); - goto error; + if (direction == SNDRV_PCM_STREAM_CAPTURE) { + ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret); + goto error; + } + } else { + ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + goto error; + } + hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); } - hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); - - return hstream->stream_tag; + return dsp_stream; error: hda_dsp_stream_put(sdev, direction, hstream->stream_tag); snd_dma_free_pages(dmab); - return ret; + return ERR_PTR(ret); } /* @@ -78,8 +82,7 @@ error: * status on core 1, so power up core 1 also momentarily, keep it in * reset/stall and then turn it off */ -static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, - u32 fwsize, int stream_tag) +static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -90,7 +93,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, /* step 1: power up corex */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); if (ret < 0) { - dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); + if (iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); goto err; } @@ -112,7 +116,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, /* step 3: unset core 0 reset state & unstall/run core 0 */ ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); if (ret < 0) { - dev_err(sdev->dev, "error: dsp core start failed %d\n", ret); + if (iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, + "error: dsp core start failed %d\n", ret); ret = -EIO; goto err; } @@ -126,8 +132,10 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(sdev->dev, "error: %s: timeout for HIPCIE done\n", - __func__); + if (iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, + "error: %s: timeout for HIPCIE done\n", + __func__); goto err; } @@ -141,7 +149,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, ret = hda_dsp_core_power_down(sdev, chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); if (ret < 0) { - dev_err(sdev->dev, "error: dsp core x power down failed\n"); + if (iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, + "error: dsp core x power down failed\n"); goto err; } @@ -159,9 +169,10 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, if (!ret) return 0; - dev_err(sdev->dev, - "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", - __func__); + if (iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); @@ -197,34 +208,20 @@ static int cl_trigger(struct snd_sof_dev *sdev, } } -static struct hdac_ext_stream *get_stream_with_tag(struct snd_sof_dev *sdev, - int tag) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_stream *s; - - /* get stream with tag */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && - s->stream_tag == tag) { - return stream_to_hdac_ext_stream(s); - } - } - - return NULL; -} - static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_ext_stream *stream) { struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); - int ret; + int ret = 0; - ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) + ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + else + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_SD_CTL_DMA_START, 0); - hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK, - hstream->stream_tag); + hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); hstream->running = 0; hstream->substream = NULL; @@ -282,6 +279,54 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) return status; } +int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct hdac_ext_stream *iccmax_stream; + struct hdac_bus *bus = sof_to_bus(sdev); + struct firmware stripped_firmware; + int ret, ret1; + u8 original_gb; + + /* save the original LTRP guardband value */ + original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; + + if (plat_data->fw->size <= plat_data->fw_offset) { + dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); + return -EINVAL; + } + + stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; + + /* prepare capture stream for ICCMAX */ + iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, + &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); + if (IS_ERR(iccmax_stream)) { + dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); + return PTR_ERR(iccmax_stream); + } + + ret = hda_dsp_cl_boot_firmware(sdev); + + /* + * Perform iccmax stream cleanup. This should be done even if firmware loading fails. + * If the cleanup also fails, we return the initial error + */ + ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream); + if (ret1 < 0) { + dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); + + /* set return value to indicate cleanup failure */ + if (!ret) + ret = ret1; + } + + /* restore the original guardband value after FW boot */ + snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb); + + return ret; +} + int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; @@ -289,7 +334,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) const struct sof_intel_dsp_desc *chip_info; struct hdac_ext_stream *stream; struct firmware stripped_firmware; - int ret, ret1, tag, i; + int ret, ret1, i; chip_info = desc->chip_info; @@ -305,23 +350,11 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->boot_wait); /* prepare DMA for code loader stream */ - tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size, - &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); - - if (tag < 0) { - dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n", - tag); - return tag; - } - - /* get stream with tag */ - stream = get_stream_with_tag(sdev, tag); - if (!stream) { - dev_err(sdev->dev, - "error: could not get stream with stream tag %d\n", - tag); - ret = -ENODEV; - goto err; + stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, + &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); + if (IS_ERR(stream)) { + dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); + return PTR_ERR(stream); } memcpy(sdev->dmab.area, stripped_firmware.data, @@ -329,25 +362,24 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) /* try ROM init a few times before giving up */ for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { - ret = cl_dsp_init(sdev, stripped_firmware.data, - stripped_firmware.size, tag); + dev_dbg(sdev->dev, + "Attempting iteration %d of Core En/ROM load...\n", i); + + ret = cl_dsp_init(sdev, stream->hstream.stream_tag, i + 1); /* don't retry anymore if successful */ if (!ret) break; + } - dev_dbg(sdev->dev, "iteration %d of Core En/ROM load failed: %d\n", + if (i == HDA_FW_BOOT_ATTEMPTS) { + dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", i, ret); - dev_dbg(sdev->dev, "Error code=0x%x: FW status=0x%x\n", + dev_err(sdev->dev, "ROM error=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS)); - } - - if (i == HDA_FW_BOOT_ATTEMPTS) { - dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", - i, ret); goto cleanup; } @@ -402,7 +434,6 @@ cleanup: return chip_info->init_core_mask; /* dump dsp registers and disable DSP upon error */ -err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); /* disable DSP */ diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 1bda14c3590c..0e09ede922c7 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -23,6 +23,8 @@ #include "../sof-audio.h" #include "hda.h" +#define HDA_LTRP_GB_VALUE_US 95 + /* * set up one of BDL entries for a stream */ @@ -322,6 +324,73 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, return 0; } +/* minimal recommended programming for ICCMAX stream */ +int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret; + u32 mask = 0x1 << hstream->index; + + if (!stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + + if (hstream->posbuf) + *hstream->posbuf = 0; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + 0x0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + 0x0); + + hstream->frags = 0; + + ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream); + if (ret < 0) { + dev_err(sdev->dev, "error: set up of BDL failed\n"); + return ret; + } + + /* program BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + (u32)hstream->bdl.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + upper_32_bits(hstream->bdl.addr)); + + /* program cyclic buffer length */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + hstream->bufsize); + + /* program last valid index */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + 0xffff, (hstream->frags - 1)); + + /* decouple host and link DMA, enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + + /* Follow HW recommendation to set the guardband value to 95us during FW boot */ + snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US); + + /* start DMA */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_SD_CTL_DMA_START, SOF_HDA_SD_CTL_DMA_START); + + return 0; +} + /* * prepare for common hdac registers settings, for both code loader * and normal stream. diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 63ca920c8e6e..de8e85920402 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -37,6 +37,7 @@ #include "shim.h" #define EXCEPT_MAX_HDR_SIZE 0x400 +#define HDA_EXT_ROM_STATUS_SIZE 8 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) @@ -414,6 +415,22 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) } } +/* dump the first 8 dwords representing the extended ROM status */ +static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev) +{ + char msg[128]; + int len = 0; + u32 value; + int i; + + for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) { + value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS + i * 0x4); + len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value); + } + + dev_err(sdev->dev, "error: extended rom status:%s", msg); +} + void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { struct sof_ipc_dsp_oops_xtensa xoops; @@ -437,6 +454,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) } else { dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", status, panic); + hda_dsp_dump_ext_rom_status(sdev); hda_dsp_get_status(sdev); } } @@ -544,7 +562,7 @@ static int check_nhlt_dmic(struct snd_sof_dev *sdev) if (nhlt) { dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); intel_nhlt_free(nhlt); - if (dmic_num == 2 || dmic_num == 4) + if (dmic_num >= 1 && dmic_num <= 4) return dmic_num; } @@ -992,9 +1010,15 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) dmic_num = hda_dmic_num; switch (dmic_num) { + case 1: + dmic_str = "-1ch"; + break; case 2: dmic_str = "-2ch"; break; + case 3: + dmic_str = "-3ch"; + break; case 4: dmic_str = "-4ch"; break; @@ -1179,7 +1203,13 @@ void hda_machine_select(struct snd_sof_dev *sdev) mach = snd_soc_acpi_find_machine(desc->machines); if (mach) { - sof_pdata->tplg_filename = mach->sof_tplg_filename; + /* + * If tplg file name is overridden, use it instead of + * the one set in mach table + */ + if (!sof_pdata->tplg_filename) + sof_pdata->tplg_filename = mach->sof_tplg_filename; + sof_pdata->machine = mach; if (mach->link_mask) { @@ -1207,3 +1237,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index fe452f0d0ec7..5ee2f8354051 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -246,6 +246,7 @@ /* Intel Vendor Specific Registers */ #define HDA_VS_INTEL_EM2 0x1030 #define HDA_VS_INTEL_EM2_L1SEN BIT(13) +#define HDA_VS_INTEL_LTRP_GB_MASK 0x3F /* HIPCI */ #define HDA_DSP_REG_HIPCI_BUSY BIT(31) @@ -546,6 +547,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params); +int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params); int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int cmd); irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); @@ -608,6 +612,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); * DSP Code loader. */ 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_skl(struct snd_sof_dev *sdev); /* pre and post fw run ops */ @@ -728,6 +733,7 @@ extern struct snd_soc_dai_driver skl_dai[]; */ extern const struct snd_sof_dsp_ops sof_apl_ops; extern const struct snd_sof_dsp_ops sof_cnl_ops; +extern const struct snd_sof_dsp_ops sof_tgl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c new file mode 100644 index 000000000000..d0e84b7747a0 --- /dev/null +++ b/sound/soc/sof/intel/tgl.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Authors: Ranjani Sridharan <[email protected]> +// + +/* + * Hardware interface for audio DSP on Tigerlake. + */ + +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" + +static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +/* Tigerlake ops */ +const struct snd_sof_dsp_ops sof_tgl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_thread = cnl_ipc_irq_thread, + + /* ipc */ + .send_msg = cnl_ipc_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, + + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + + /* machine driver */ + .machine_select = hda_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = hda_set_mach_params, + + /* debug */ + .debug_map = tgl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + .ipc_dump = cnl_ipc_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) + /* probe callbacks */ + .probe_assign = hda_probe_compr_assign, + .probe_free = hda_probe_compr_free, + .probe_set_params = hda_probe_compr_set_params, + .probe_trigger = hda_probe_compr_trigger, + .probe_pointer = hda_probe_compr_pointer, +#endif + + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_raw, + + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware_iccmax, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, + .runtime_idle = hda_dsp_runtime_idle, + .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + + .arch_ops = &sof_xtensa_arch_ops, +}; +EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc tgl_chip_info = { + /* Tigerlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 36e2d4d43da4..fd2b96ae4943 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -54,6 +54,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) u8 *str2 = NULL; u32 glb; u32 type; + bool vdbg = false; glb = cmd & SOF_GLB_TYPE_MASK; type = cmd & SOF_CMD_TYPE_MASK; @@ -146,6 +147,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) case SOF_IPC_STREAM_TRIG_XRUN: str2 = "TRIG_XRUN"; break; case SOF_IPC_STREAM_POSITION: + vdbg = true; str2 = "POSITION"; break; case SOF_IPC_STREAM_VORBIS_PARAMS: str2 = "VORBIS_PARAMS"; break; @@ -183,10 +185,14 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str = "unknown GLB command"; break; } - if (str2) - dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); - else + if (str2) { + if (vdbg) + dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + else + dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + } else { dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); + } } #else static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) @@ -449,8 +455,8 @@ 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)); - dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", - posn.host_posn, posn.dai_posn, posn.wallclock); + dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", + posn.host_posn, posn.dai_posn, posn.wallclock); memcpy(&stream->posn, &posn, sizeof(posn)); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index b94fa5f5d480..68ed454f7ddf 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -20,13 +20,12 @@ static int get_ext_windows(struct snd_sof_dev *sdev, { const struct sof_ipc_window *w = container_of(ext_hdr, struct sof_ipc_window, ext_hdr); - size_t w_size = struct_size(w, window, w->num_windows); if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) return -EINVAL; if (sdev->info_window) { - if (memcmp(sdev->info_window, w, w_size)) { + if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) { dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox"); return -EINVAL; } @@ -34,7 +33,8 @@ static int get_ext_windows(struct snd_sof_dev *sdev, } /* keep a local copy of the data */ - sdev->info_window = kmemdup(w, w_size, GFP_KERNEL); + sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, + GFP_KERNEL); if (!sdev->info_window) return -ENOMEM; @@ -176,6 +176,22 @@ static int ext_man_get_cc_info(struct snd_sof_dev *sdev, return get_cc_info(sdev, &cc->cc_version.ext_hdr); } +static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + const struct ext_man_dbg_abi *dbg_abi = + container_of(hdr, struct ext_man_dbg_abi, hdr); + + if (sdev->first_boot) + dev_dbg(sdev->dev, + "Firmware: DBG_ABI %d:%d:%d\n", + SOF_ABI_VERSION_MAJOR(dbg_abi->dbg_abi.abi_dbg_version), + SOF_ABI_VERSION_MINOR(dbg_abi->dbg_abi.abi_dbg_version), + SOF_ABI_VERSION_PATCH(dbg_abi->dbg_abi.abi_dbg_version)); + + return 0; +} + static ssize_t snd_sof_ext_man_size(const struct firmware *fw) { const struct sof_ext_man_header *head; @@ -255,6 +271,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_CC_VERSION: ret = ext_man_get_cc_info(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_DBG_ABI: + ret = ext_man_get_dbg_abi_info(sdev, elem_hdr); + break; default: dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); @@ -291,6 +310,8 @@ static void sof_get_windows(struct snd_sof_dev *sdev) u32 outbox_size = 0; u32 stream_size = 0; u32 inbox_size = 0; + u32 debug_size = 0; + u32 debug_offset = 0; int window_offset; int bar; int i; @@ -344,6 +365,8 @@ static void sof_get_windows(struct snd_sof_dev *sdev) 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 + @@ -393,12 +416,17 @@ static void sof_get_windows(struct snd_sof_dev *sdev) sdev->stream_box.offset = stream_offset; sdev->stream_box.size = stream_size; + sdev->debug_box.offset = debug_offset; + sdev->debug_box.size = debug_size; + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", inbox_offset, inbox_size); dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", outbox_offset, outbox_size); dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", stream_offset, stream_size); + dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n", + debug_offset, debug_size); } /* check for ABI compatibility and create memory windows on first boot */ diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d730e437e4ba..4c5082b7eea9 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -446,9 +446,9 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, dai = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.dai_posn); - dev_dbg(component->dev, - "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", - spcm->pcm.pcm_id, substream->stream, host, dai); + dev_vdbg(component->dev, + "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", + spcm->pcm.pcm_id, substream->stream, host, dai); return host; } @@ -704,7 +704,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, break; case SOF_DAI_INTEL_HDA: /* - * HDaudio does not follow the default trigger + * HDAudio does not follow the default trigger * sequence due to firmware implementation */ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 92e5f9b15f3a..a5f7c7f024a1 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -256,6 +256,7 @@ suspend: /* reset FW state */ sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; + sdev->enabled_cores_mask = 0; return ret; } diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 8aecc46b3647..a78b76ef37b2 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -106,6 +106,8 @@ static const struct dev_pm_ops sof_acpi_pm = { static void sof_acpi_probe_complete(struct device *dev) { + dev_dbg(dev, "Completing SOF ACPI probe"); + if (sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME) return; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 1c7698f8edd6..cd506a4bfc4b 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -29,7 +29,7 @@ bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) continue; /* - * substream->runtime being not NULL indicates that + * substream->runtime being not NULL indicates * that the stream is open. No need to check the * stream state. */ @@ -142,6 +142,22 @@ static int sof_restore_kcontrols(struct device *dev) return 0; } +const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev, + int pipeline_id) +{ + const struct snd_sof_widget *swidget; + + list_for_each_entry(swidget, &sdev->widget_list, list) + if (swidget->id == snd_soc_dapm_scheduler) { + const struct sof_ipc_pipe_new *pipeline = + swidget->private; + if (pipeline->pipeline_id == pipeline_id) + return pipeline; + } + + return NULL; +} + int sof_restore_pipelines(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); @@ -149,8 +165,9 @@ int sof_restore_pipelines(struct device *dev) struct snd_sof_route *sroute; struct sof_ipc_pipe_new *pipeline; struct snd_sof_dai *dai; - struct sof_ipc_comp_dai *comp_dai; struct sof_ipc_cmd_hdr *hdr; + struct sof_ipc_comp *comp; + size_t ipc_size; int ret; /* restore pipeline components */ @@ -161,15 +178,36 @@ int sof_restore_pipelines(struct device *dev) if (!swidget->private) continue; + ret = sof_pipeline_core_enable(sdev, swidget); + if (ret < 0) { + dev_err(dev, + "error: failed to enable target core: %d\n", + ret); + + return ret; + } + switch (swidget->id) { case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: + ipc_size = sizeof(struct sof_ipc_comp_dai) + + sizeof(struct sof_ipc_comp_ext); + comp = kzalloc(ipc_size, GFP_KERNEL); + if (!comp) + return -ENOMEM; + dai = swidget->private; - comp_dai = &dai->comp_dai; - ret = sof_ipc_tx_message(sdev->ipc, - comp_dai->comp.hdr.cmd, - comp_dai, sizeof(*comp_dai), + memcpy(comp, &dai->comp_dai, + sizeof(struct sof_ipc_comp_dai)); + + /* append extended data to the end of the component */ + memcpy((u8 *)comp + sizeof(struct sof_ipc_comp_dai), + &swidget->comp_ext, sizeof(swidget->comp_ext)); + + ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, + comp, ipc_size, &r, sizeof(r)); + kfree(comp); break; case snd_soc_dapm_scheduler: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 9629994fe463..9f645a2e5a6c 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -83,11 +83,15 @@ struct snd_sof_widget { int comp_id; int pipeline_id; int complete; + int core; int id; struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ + /* extended data for UUID components */ + struct sof_ipc_comp_ext comp_ext; + void *private; /* core does not touch this */ }; @@ -138,6 +142,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, unsigned int size); +int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, + unsigned int size); /* * Topology. @@ -151,6 +157,8 @@ int snd_sof_complete_pipeline(struct device *dev, int sof_load_pipeline_ipc(struct device *dev, struct sof_ipc_pipe_new *pipeline, struct sof_ipc_comp_reply *r); +int sof_pipeline_core_enable(struct snd_sof_dev *sdev, + const struct snd_sof_widget *swidget); /* * Stream IPC @@ -190,6 +198,8 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, int *direction); struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp, unsigned int pcm_id); +const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev, + int pipeline_id); void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_period_elapsed_work(struct work_struct *work); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index aa3532ba1434..ec62d9337d68 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -35,8 +35,28 @@ static int sof_pci_debug; module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); +static const char *sof_override_tplg_name; + #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) +static int sof_tplg_cb(const struct dmi_system_id *id) +{ + sof_override_tplg_name = id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_tplg_table[] = { + { + .callback = sof_tplg_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Terrador"), + }, + .driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg", + }, + {} +}; + static const struct dmi_system_id community_key_platforms[] = { { .ident = "Up Squared", @@ -201,7 +221,7 @@ static const struct sof_dev_desc tgl_desc = { .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-tgl.ri", .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", - .ops = &sof_cnl_ops, + .ops = &sof_tgl_ops, }; #endif @@ -282,10 +302,10 @@ static int sof_pci_probe(struct pci_dev *pci, int ret; ret = snd_intel_dsp_driver_probe(pci); - if (ret != SND_INTEL_DSP_DRIVER_ANY && - ret != SND_INTEL_DSP_DRIVER_SOF) + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { + dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n"); return -ENODEV; - + } dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ @@ -347,6 +367,10 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; + dmi_check_system(sof_tplg_table); + if (sof_override_tplg_name) + sof_pdata->tplg_filename = sof_override_tplg_name; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) /* set callback to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_pci_probe_complete; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 64f28e082049..1c51d99f0459 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -54,6 +54,9 @@ extern int sof_core_debug; (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \ IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)) +/* So far the primary core on all DSPs has ID 0 */ +#define SOF_DSP_PRIMARY_CORE 0 + /* DSP power state */ enum sof_dsp_power_states { SOF_DSP_PM_D0, @@ -370,7 +373,7 @@ struct snd_sof_dev { /* DSP firmware boot */ wait_queue_head_t boot_wait; enum snd_sof_fw_state fw_state; - u32 first_boot; + bool first_boot; /* work queue in case the probe is implemented in two steps */ struct work_struct probe_work; @@ -383,6 +386,7 @@ struct snd_sof_dev { struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */ struct snd_sof_mailbox host_box; /* Host initiated IPC */ struct snd_sof_mailbox stream_box; /* Stream position update */ + struct snd_sof_mailbox debug_box; /* Debug info updates */ struct snd_sof_ipc_msg *msg; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ @@ -431,10 +435,10 @@ struct snd_sof_dev { int dma_trace_pages; wait_queue_head_t trace_sleep; u32 host_offset; - u32 dtrace_is_supported; /* set with Kconfig or module parameter */ - u32 dtrace_is_enabled; - u32 dtrace_error; - u32 dtrace_draining; + bool dtrace_is_supported; /* set with Kconfig or module parameter */ + bool dtrace_is_enabled; + bool dtrace_error; + bool dtrace_draining; bool msi_enabled; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 13e10a0c0b05..d5efac3af5c2 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -8,6 +8,9 @@ // Author: Liam Girdwood <[email protected]> // +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/errno.h> #include <linux/firmware.h> #include <linux/workqueue.h> #include <sound/tlv.h> @@ -489,6 +492,16 @@ static int get_token_u16(void *elem, void *object, u32 offset, u32 size) return 0; } +static int get_token_uuid(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_uuid_elem *velem = elem; + u8 *dst = (u8 *)object + offset; + + memcpy(dst, velem->uuid, UUID_SIZE); + + return 0; +} + static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_string_elem *velem = elem; @@ -715,6 +728,20 @@ static const struct sof_topology_token sai_tokens[] = { offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0}, }; +/* Core tokens */ +static const struct sof_topology_token core_tokens[] = { + {SOF_TKN_COMP_CORE_ID, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp, core), 0}, +}; + +/* Component extended tokens */ +static const struct sof_topology_token comp_ext_tokens[] = { + {SOF_TKN_COMP_UUID, + SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, + offsetof(struct sof_ipc_comp_ext, uuid), 0}, +}; + /* * DMIC PDM Tokens * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token @@ -1278,6 +1305,73 @@ static int sof_control_unload(struct snd_soc_component *scomp, * DAI Topology */ +/* Static DSP core power management so far, should be extended in the future */ +static int sof_core_enable(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc_pm_core_config pm_core_config = { + .hdr = { + .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE, + .size = sizeof(pm_core_config), + }, + .enable_mask = sdev->enabled_cores_mask | BIT(core), + }; + int ret; + + if (sdev->enabled_cores_mask & BIT(core)) + return 0; + + /* power up the core if it is host managed */ + ret = snd_sof_dsp_core_power_up(sdev, BIT(core)); + if (ret < 0) { + dev_err(sdev->dev, "error: %d powering up core %d\n", + ret, core); + return ret; + } + + /* Now notify DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); + if (ret < 0) { + dev_err(sdev->dev, "error: core %d enable ipc failure %d\n", + core, ret); + goto err; + } + + /* update enabled cores mask */ + sdev->enabled_cores_mask |= BIT(core); + + return ret; +err: + /* power down core if it is host managed and return the original error if this fails too */ + if (snd_sof_dsp_core_power_down(sdev, BIT(core)) < 0) + dev_err(sdev->dev, "error: powering down core %d\n", core); + + return ret; +} + +int sof_pipeline_core_enable(struct snd_sof_dev *sdev, + const struct snd_sof_widget *swidget) +{ + const struct sof_ipc_pipe_new *pipeline; + int ret; + + if (swidget->id == snd_soc_dapm_scheduler) { + pipeline = swidget->private; + } else { + pipeline = snd_sof_pipeline_find(sdev, swidget->pipeline_id); + if (!pipeline) + return -ENOENT; + } + + /* First enable the pipeline core */ + ret = sof_core_enable(sdev, pipeline->core); + if (ret < 0) + return ret; + + return sof_core_enable(sdev, swidget->core); +} + static int sof_connect_dai_widget(struct snd_soc_component *scomp, struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tw, @@ -1359,56 +1453,110 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, return 0; } +/** + * sof_comp_alloc - allocate and initialize buffer for a new component + * @swidget: pointer to struct snd_sof_widget containing extended data + * @ipc_size: IPC payload size that will be updated depending on valid + * extended data. + * @index: ID of the pipeline the component belongs to + * @core: index of the DSP core that the component should run on + * + * Return: The pointer to the new allocated component, NULL if failed. + */ +static struct sof_ipc_comp *sof_comp_alloc(struct snd_sof_widget *swidget, + size_t *ipc_size, int index, + int core) +{ + u8 nil_uuid[SOF_UUID_SIZE] = {0}; + struct sof_ipc_comp *comp; + size_t total_size = *ipc_size; + + /* only non-zero UUID is valid */ + if (memcmp(&swidget->comp_ext, nil_uuid, SOF_UUID_SIZE)) + total_size += sizeof(swidget->comp_ext); + + comp = kzalloc(total_size, GFP_KERNEL); + if (!comp) + return NULL; + + /* configure comp new IPC message */ + comp->hdr.size = total_size; + comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + comp->id = swidget->comp_id; + comp->pipeline_id = index; + comp->core = core; + + /* handle the extended data if needed */ + if (total_size > *ipc_size) { + /* append extended data to the end of the component */ + memcpy((u8 *)comp + *ipc_size, &swidget->comp_ext, sizeof(swidget->comp_ext)); + comp->ext_data_length = sizeof(swidget->comp_ext); + } + + /* update ipc_size and return */ + *ipc_size = total_size; + return comp; +} + static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r, struct snd_sof_dai *dai) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_dai comp_dai; + struct sof_ipc_comp_dai *comp_dai; + size_t ipc_size = sizeof(*comp_dai); int ret; + comp_dai = (struct sof_ipc_comp_dai *) + sof_comp_alloc(swidget, &ipc_size, index, core); + if (!comp_dai) + return -ENOMEM; + /* configure dai IPC message */ - memset(&comp_dai, 0, sizeof(comp_dai)); - comp_dai.comp.hdr.size = sizeof(comp_dai); - comp_dai.comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - comp_dai.comp.id = swidget->comp_id; - comp_dai.comp.type = SOF_COMP_DAI; - comp_dai.comp.pipeline_id = index; - comp_dai.config.hdr.size = sizeof(comp_dai.config); - - ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens, + comp_dai->comp.type = SOF_COMP_DAI; + comp_dai->config.hdr.size = sizeof(comp_dai->config); + + ret = sof_parse_tokens(scomp, comp_dai, dai_tokens, ARRAY_SIZE(dai_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { dev_err(scomp->dev, "error: parse dai tokens failed %d\n", le32_to_cpu(private->size)); - return ret; + goto finish; } - ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens, + ret = sof_parse_tokens(scomp, &comp_dai->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n", private->size); - return ret; + goto finish; } dev_dbg(scomp->dev, "dai %s: type %d index %d\n", - swidget->widget->name, comp_dai.type, comp_dai.dai_index); - sof_dbg_comp_config(scomp, &comp_dai.config); + swidget->widget->name, comp_dai->type, comp_dai->dai_index); + sof_dbg_comp_config(scomp, &comp_dai->config); - ret = sof_ipc_tx_message(sdev->ipc, comp_dai.comp.hdr.cmd, - &comp_dai, sizeof(comp_dai), r, sizeof(*r)); + ret = sof_ipc_tx_message(sdev->ipc, comp_dai->comp.hdr.cmd, + comp_dai, ipc_size, r, sizeof(*r)); if (ret == 0 && dai) { dai->scomp = scomp; - memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai)); + + /* + * copy only the sof_ipc_comp_dai to avoid collapsing + * the snd_sof_dai, the extended data is kept in the + * snd_sof_widget. + */ + memcpy(&dai->comp_dai, comp_dai, sizeof(*comp_dai)); } +finish: + kfree(comp_dai); return ret; } @@ -1417,7 +1565,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, */ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { @@ -1436,6 +1584,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, buffer->comp.id = swidget->comp_id; buffer->comp.type = SOF_COMP_BUFFER; buffer->comp.pipeline_id = index; + buffer->comp.core = core; ret = sof_parse_tokens(scomp, buffer, buffer_tokens, ARRAY_SIZE(buffer_tokens), private->array, @@ -1487,7 +1636,7 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, */ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, enum sof_ipc_stream_direction dir, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) @@ -1495,18 +1644,16 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_host *host; + size_t ipc_size = sizeof(*host); int ret; - host = kzalloc(sizeof(*host), GFP_KERNEL); + host = (struct sof_ipc_comp_host *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!host) return -ENOMEM; /* configure host comp IPC message */ - host->comp.hdr.size = sizeof(*host); - host->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - host->comp.id = swidget->comp_id; host->comp.type = SOF_COMP_HOST; - host->comp.pipeline_id = index; host->direction = dir; host->config.hdr.size = sizeof(host->config); @@ -1534,7 +1681,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, swidget->private = host; ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host, - sizeof(*host), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: @@ -1550,50 +1697,21 @@ int sof_load_pipeline_ipc(struct device *dev, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - struct sof_ipc_pm_core_config pm_core_config; - int ret; - - ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, - sizeof(*pipeline), r, sizeof(*r)); - if (ret < 0) { - dev_err(dev, "error: load pipeline ipc failure\n"); - return ret; - } + int ret = sof_core_enable(sdev, pipeline->core); - /* power up the core that this pipeline is scheduled on */ - ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core); - if (ret < 0) { - dev_err(dev, "error: powering up pipeline schedule core %d\n", - pipeline->core); + if (ret < 0) return ret; - } - - /* update enabled cores mask */ - sdev->enabled_cores_mask |= 1 << pipeline->core; - /* - * Now notify DSP that the core that this pipeline is scheduled on - * has been powered up - */ - memset(&pm_core_config, 0, sizeof(pm_core_config)); - pm_core_config.enable_mask = sdev->enabled_cores_mask; - - /* configure CORE_ENABLE ipc message */ - pm_core_config.hdr.size = sizeof(pm_core_config); - pm_core_config.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE; - - /* send ipc */ - ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, - &pm_core_config, sizeof(pm_core_config), - &pm_core_config, sizeof(pm_core_config)); + ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, + sizeof(*pipeline), r, sizeof(*r)); if (ret < 0) - dev_err(dev, "error: core enable ipc failure\n"); + dev_err(dev, "error: load pipeline ipc failure\n"); return ret; } -static int sof_widget_load_pipeline(struct snd_soc_component *scomp, - int index, struct snd_sof_widget *swidget, +static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { @@ -1655,25 +1773,23 @@ err: */ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_mixer *mixer; + size_t ipc_size = sizeof(*mixer); int ret; - mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + mixer = (struct sof_ipc_comp_mixer *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!mixer) return -ENOMEM; /* configure mixer IPC message */ - mixer->comp.hdr.size = sizeof(*mixer); - mixer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - mixer->comp.id = swidget->comp_id; mixer->comp.type = SOF_COMP_MIXER; - mixer->comp.pipeline_id = index; mixer->config.hdr.size = sizeof(mixer->config); ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens, @@ -1691,7 +1807,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, swidget->private = mixer; ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer, - sizeof(*mixer), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret < 0) kfree(mixer); @@ -1702,25 +1818,23 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, * Mux topology */ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_mux *mux; + size_t ipc_size = sizeof(*mux); int ret; - mux = kzalloc(sizeof(*mux), GFP_KERNEL); + mux = (struct sof_ipc_comp_mux *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!mux) return -ENOMEM; /* configure mux IPC message */ - mux->comp.hdr.size = sizeof(*mux); - mux->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - mux->comp.id = swidget->comp_id; mux->comp.type = SOF_COMP_MUX; - mux->comp.pipeline_id = index; mux->config.hdr.size = sizeof(mux->config); ret = sof_parse_tokens(scomp, &mux->config, comp_tokens, @@ -1738,7 +1852,7 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, swidget->private = mux; ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux, - sizeof(*mux), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret < 0) kfree(mux); @@ -1750,7 +1864,7 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, */ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { @@ -1758,11 +1872,13 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_volume *volume; struct snd_sof_control *scontrol; + size_t ipc_size = sizeof(*volume); int min_step; int max_step; int ret; - volume = kzalloc(sizeof(*volume), GFP_KERNEL); + volume = (struct sof_ipc_comp_volume *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!volume) return -ENOMEM; @@ -1774,11 +1890,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, } /* configure volume IPC message */ - volume->comp.hdr.size = sizeof(*volume); - volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - volume->comp.id = swidget->comp_id; volume->comp.type = SOF_COMP_VOLUME; - volume->comp.pipeline_id = index; volume->config.hdr.size = sizeof(volume->config); ret = sof_parse_tokens(scomp, volume, volume_tokens, @@ -1815,7 +1927,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, } ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, - sizeof(*volume), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: @@ -1828,25 +1940,23 @@ err: */ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_src *src; + size_t ipc_size = sizeof(*src); int ret; - src = kzalloc(sizeof(*src), GFP_KERNEL); + src = (struct sof_ipc_comp_src *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!src) return -ENOMEM; /* configure src IPC message */ - src->comp.hdr.size = sizeof(*src); - src->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - src->comp.id = swidget->comp_id; src->comp.type = SOF_COMP_SRC; - src->comp.pipeline_id = index; src->config.hdr.size = sizeof(src->config); ret = sof_parse_tokens(scomp, src, src_tokens, @@ -1874,7 +1984,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, swidget->private = src; ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src, - sizeof(*src), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: @@ -1887,25 +1997,23 @@ err: */ static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_asrc *asrc; + size_t ipc_size = sizeof(*asrc); int ret; - asrc = kzalloc(sizeof(*asrc), GFP_KERNEL); + asrc = (struct sof_ipc_comp_asrc *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!asrc) return -ENOMEM; /* configure ASRC IPC message */ - asrc->comp.hdr.size = sizeof(*asrc); - asrc->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - asrc->comp.id = swidget->comp_id; asrc->comp.type = SOF_COMP_ASRC; - asrc->comp.pipeline_id = index; asrc->config.hdr.size = sizeof(asrc->config); ret = sof_parse_tokens(scomp, asrc, asrc_tokens, @@ -1935,7 +2043,7 @@ static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index, swidget->private = asrc; ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc, - sizeof(*asrc), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: @@ -1948,25 +2056,23 @@ err: */ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_tone *tone; + size_t ipc_size = sizeof(*tone); int ret; - tone = kzalloc(sizeof(*tone), GFP_KERNEL); + tone = (struct sof_ipc_comp_tone *) + sof_comp_alloc(swidget, &ipc_size, index, core); if (!tone) return -ENOMEM; /* configure siggen IPC message */ - tone->comp.hdr.size = sizeof(*tone); - tone->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - tone->comp.id = swidget->comp_id; tone->comp.type = SOF_COMP_TONE; - tone->comp.pipeline_id = index; tone->config.hdr.size = sizeof(tone->config); ret = sof_parse_tokens(scomp, tone, tone_tokens, @@ -1994,7 +2100,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, swidget->private = tone; ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone, - sizeof(*tone), r, sizeof(*r)); + ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: @@ -2083,20 +2189,14 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_dapm_widget *widget = swidget->widget; struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_process *process = NULL; + struct sof_ipc_comp_process *process; struct sof_widget_data *wdata = NULL; size_t ipc_data_size = 0; size_t ipc_size; int offset = 0; - int ret = 0; + int ret; int i; - if (type == SOF_COMP_NONE) { - dev_err(scomp->dev, "error: invalid process comp type %d\n", - type); - return -EINVAL; - } - /* allocate struct for widget control data sizes and types */ if (widget->num_kcontrols) { wdata = kcalloc(widget->num_kcontrols, @@ -2114,9 +2214,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, goto out; } - ipc_size = sizeof(struct sof_ipc_comp_process) + - le32_to_cpu(private->size) + - ipc_data_size; + ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size; /* we are exceeding max ipc size, config needs to be sent separately */ if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { @@ -2124,18 +2222,15 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ipc_data_size = 0; } - process = kzalloc(ipc_size, GFP_KERNEL); + process = (struct sof_ipc_comp_process *) + sof_comp_alloc(swidget, &ipc_size, index, 0); if (!process) { ret = -ENOMEM; goto out; } /* configure iir IPC message */ - process->comp.hdr.size = ipc_size; - process->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - process->comp.id = swidget->comp_id; process->comp.type = type; - process->comp.pipeline_id = index; process->config.hdr.size = sizeof(process->config); ret = sof_parse_tokens(scomp, &process->config, comp_tokens, @@ -2206,7 +2301,7 @@ out: */ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, + struct snd_sof_widget *swidget, int core, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { @@ -2221,6 +2316,7 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, } memset(&config, 0, sizeof(config)); + config.comp.core = core; /* get the process token */ ret = sof_parse_tokens(scomp, &config, process_tokens, @@ -2285,6 +2381,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_sof_dai *dai; struct sof_ipc_comp_reply reply; struct snd_sof_control *scontrol; + struct sof_ipc_comp comp = { + .core = SOF_DSP_PRIMARY_CORE, + }; int ret = 0; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); @@ -2305,6 +2404,36 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? tw->sname : "none"); + ret = sof_parse_tokens(scomp, &comp, core_tokens, + ARRAY_SIZE(core_tokens), tw->priv.array, + le32_to_cpu(tw->priv.size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parsing core tokens failed %d\n", + ret); + kfree(swidget); + return ret; + } + + swidget->core = comp.core; + + /* default is primary core, safe to call for already enabled cores */ + ret = sof_core_enable(sdev, comp.core); + if (ret < 0) { + dev_err(scomp->dev, "error: enable core: %d\n", ret); + kfree(swidget); + return ret; + } + + ret = sof_parse_tokens(scomp, &swidget->comp_ext, comp_ext_tokens, + ARRAY_SIZE(comp_ext_tokens), tw->priv.array, + le32_to_cpu(tw->priv.size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parsing comp_ext_tokens failed %d\n", + ret); + kfree(swidget); + return ret; + } + /* handle any special case widgets */ switch (w->id) { case snd_soc_dapm_dai_in: @@ -2315,8 +2444,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, return -ENOMEM; } - ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply, - dai); + ret = sof_widget_load_dai(scomp, index, swidget, comp.core, + tw, &reply, dai); if (ret == 0) { sof_connect_dai_widget(scomp, w, tw, dai); list_add(&dai->list, &sdev->dai_list); @@ -2326,10 +2455,12 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, } break; case snd_soc_dapm_mixer: - ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_mixer(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_pga: - ret = sof_widget_load_pga(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_pga(scomp, index, swidget, comp.core, + tw, &reply); /* Find scontrol for this pga and set readback offset*/ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { if (scontrol->comp_id == swidget->comp_id) { @@ -2339,43 +2470,47 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, } break; case snd_soc_dapm_buffer: - ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_buffer(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_scheduler: - ret = sof_widget_load_pipeline(scomp, index, swidget, tw, - &reply); + ret = sof_widget_load_pipeline(scomp, index, swidget, + tw, &reply); break; case snd_soc_dapm_aif_out: - ret = sof_widget_load_pcm(scomp, index, swidget, + ret = sof_widget_load_pcm(scomp, index, swidget, comp.core, SOF_IPC_STREAM_CAPTURE, tw, &reply); break; case snd_soc_dapm_aif_in: - ret = sof_widget_load_pcm(scomp, index, swidget, + ret = sof_widget_load_pcm(scomp, index, swidget, comp.core, SOF_IPC_STREAM_PLAYBACK, tw, &reply); break; case snd_soc_dapm_src: - ret = sof_widget_load_src(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_src(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_asrc: - ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_asrc(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_siggen: - ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_siggen(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_effect: - ret = sof_widget_load_process(scomp, index, swidget, tw, - &reply); + ret = sof_widget_load_process(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_mux: case snd_soc_dapm_demux: - ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_mux(scomp, index, swidget, comp.core, + tw, &reply); break; case snd_soc_dapm_switch: case snd_soc_dapm_dai_link: case snd_soc_dapm_kcontrol: default: - dev_warn(scomp->dev, "warning: widget type %d name %s not handled\n", - swidget->id, tw->name); + dev_dbg(scomp->dev, "widget type %d name %s not handled\n", swidget->id, tw->name); break; } @@ -2944,14 +3079,6 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, return ret; } - /* - * alloc memory for private member - * Used to track the pdm config array index currently being parsed - */ - sdev->private = kzalloc(sizeof(u32), GFP_KERNEL); - if (!sdev->private) - return -ENOMEM; - /* get DMIC PDM tokens */ ret = sof_parse_token_sets(scomp, &config->dmic.pdm[0], dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens), private->array, @@ -2962,7 +3089,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, if (ret != 0) { dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n", le32_to_cpu(private->size)); - goto err; + return ret; } /* set IPC header size */ @@ -3007,9 +3134,6 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n", config->dai_index); -err: - kfree(sdev->private); - return ret; } @@ -3564,6 +3688,7 @@ static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = { /* vendor specific bytes ext handlers available for binding */ static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = { {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_ext_get, snd_sof_bytes_ext_put}, + {SOF_TPLG_KCTL_BYTES_VOLATILE_RO, snd_sof_bytes_ext_volatile_get}, }; static struct snd_soc_tplg_ops sof_tplg_ops = { diff --git a/sound/soc/sprd/sprd-pcm-compress.c b/sound/soc/sprd/sprd-pcm-compress.c index 749dcb7b993b..6507c03cc80e 100644 --- a/sound/soc/sprd/sprd-pcm-compress.c +++ b/sound/soc/sprd/sprd-pcm-compress.c @@ -559,7 +559,7 @@ static int sprd_platform_compr_copy(struct snd_soc_component *component, } else { /* * If the data count is larger than the available spaces - * of the the stage 0 IRAM buffer, we should copy one + * of the stage 0 IRAM buffer, we should copy one * partial data to the stage 0 IRAM buffer, and copy * the left to the stage 1 DDR buffer. */ diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 2af6404dbd62..6c13cc84b3fb 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -335,7 +335,7 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, /* * FIXME: Undocumented in the datasheet, but - * Allwinner's code mentions that it is related + * Allwinner's code mentions that it is * related to microphone gain */ if (of_device_is_compatible(scodec->dev->of_node, diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index f5b7069bcca2..a41e25ad0aaf 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -121,50 +121,50 @@ /* mixer controls */ static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { - SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", SUN50I_ADDA_OL_MIX_CTRL, SUN50I_ADDA_OR_MIX_CTRL, - SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0), - SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", SUN50I_ADDA_OL_MIX_CTRL, SUN50I_ADDA_OR_MIX_CTRL, - SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0), + SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0), SOC_DAPM_DOUBLE_R("Line In Playback Switch", SUN50I_ADDA_OL_MIX_CTRL, SUN50I_ADDA_OR_MIX_CTRL, SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0), - SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SOC_DAPM_DOUBLE_R("DAC Playback Switch", SUN50I_ADDA_OL_MIX_CTRL, SUN50I_ADDA_OR_MIX_CTRL, - SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0), - SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", + SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", SUN50I_ADDA_OL_MIX_CTRL, SUN50I_ADDA_OR_MIX_CTRL, - SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0), + SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0), }; /* ADC mixer controls */ static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = { - SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", SUN50I_ADDA_L_ADCMIX_SRC, SUN50I_ADDA_R_ADCMIX_SRC, - SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0), - SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", SUN50I_ADDA_L_ADCMIX_SRC, SUN50I_ADDA_R_ADCMIX_SRC, - SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0), + SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0), SOC_DAPM_DOUBLE_R("Line In Capture Switch", SUN50I_ADDA_L_ADCMIX_SRC, SUN50I_ADDA_R_ADCMIX_SRC, SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0), - SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", SUN50I_ADDA_L_ADCMIX_SRC, SUN50I_ADDA_R_ADCMIX_SRC, - SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0), - SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", SUN50I_ADDA_L_ADCMIX_SRC, SUN50I_ADDA_R_ADCMIX_SRC, - SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0), + SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0), }; static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale, @@ -193,11 +193,6 @@ static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = { SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0, sun50i_codec_hp_vol_scale), - SOC_DOUBLE("Headphone Playback Switch", - SUN50I_ADDA_MIX_DAC_CTRL, - SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE, - SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0), - /* Mixer pre-gain */ SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL, SUN50I_ADDA_MIC1_CTRL_MIC1G, @@ -233,20 +228,10 @@ static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = { SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, sun50i_codec_lineout_vol_scale), - SOC_DOUBLE("Line Out Playback Switch", - SUN50I_ADDA_LINEOUT_CTRL0, - SUN50I_ADDA_LINEOUT_CTRL0_LEN, - SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), - SOC_SINGLE_TLV("Earpiece Playback Volume", SUN50I_ADDA_EARPIECE_CTRL1, SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0, sun50i_codec_earpiece_vol_scale), - - SOC_SINGLE("Earpiece Playback Switch", - SUN50I_ADDA_EARPIECE_CTRL1, - SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0), - }; static const char * const sun50i_codec_hp_src_enum_text[] = { @@ -264,6 +249,12 @@ static const struct snd_kcontrol_new sun50i_codec_hp_src[] = { sun50i_codec_hp_src_enum), }; +static const struct snd_kcontrol_new sun50i_codec_hp_switch = + SOC_DAPM_DOUBLE("Headphone Playback Switch", + SUN50I_ADDA_MIX_DAC_CTRL, + SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE, + SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0); + static const char * const sun50i_codec_lineout_src_enum_text[] = { "Stereo", "Mono Differential", }; @@ -279,6 +270,12 @@ static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { sun50i_codec_lineout_src_enum), }; +static const struct snd_kcontrol_new sun50i_codec_lineout_switch = + SOC_DAPM_DOUBLE("Line Out Playback Switch", + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LEN, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0); + static const char * const sun50i_codec_earpiece_src_enum_text[] = { "DACR", "DACL", "Right Mixer", "Left Mixer", }; @@ -293,6 +290,12 @@ static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = { sun50i_codec_earpiece_src_enum), }; +static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = { + SOC_DAPM_SINGLE("Earpiece Playback Switch", + SUN50I_ADDA_EARPIECE_CTRL1, + SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0), +}; + static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { /* DAC */ SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, @@ -311,18 +314,37 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { */ SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0), - SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_DAPM_MUX("Left Headphone Source", + SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), + SND_SOC_DAPM_MUX("Right Headphone Source", SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), - SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, + SND_SOC_DAPM_SWITCH("Left Headphone Switch", + SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch), + SND_SOC_DAPM_SWITCH("Right Headphone Switch", + SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch), + SND_SOC_DAPM_OUT_DRV("Left Headphone Amp", + SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Right Headphone Amp", + SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL, SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("HP"), - SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_DAPM_MUX("Left Line Out Source", SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + SND_SOC_DAPM_MUX("Right Line Out Source", + SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + SND_SOC_DAPM_SWITCH("Left Line Out Switch", + SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch), + SND_SOC_DAPM_SWITCH("Right Line Out Switch", + SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch), SND_SOC_DAPM_OUTPUT("LINEOUT"), SND_SOC_DAPM_MUX("Earpiece Source Playback Route", SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src), + SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch", + SND_SOC_NOPM, 0, 0, + sun50i_codec_earpiece_switch), SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1, SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("EARPIECE"), @@ -363,83 +385,105 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0, sun50i_a64_codec_mixer_controls, ARRAY_SIZE(sun50i_a64_codec_mixer_controls)), - SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL, - SUN50I_ADDA_ADC_CTRL_ADCLEN, 0, + SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0, sun50i_codec_adc_mixer_controls, ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), - SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL, - SUN50I_ADDA_ADC_CTRL_ADCREN, 0, + SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0, sun50i_codec_adc_mixer_controls, ARRAY_SIZE(sun50i_codec_adc_mixer_controls)), }; static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { /* Left Mixer Routes */ + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, - { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, /* Right Mixer Routes */ + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, { "Right Mixer", "DAC Playback Switch", "Right DAC" }, { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, - { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, - { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, - { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, /* ADC Routes */ { "Left ADC", NULL, "Left ADC Mixer" }, { "Right ADC", NULL, "Right ADC Mixer" }, /* Headphone Routes */ - { "Headphone Source Playback Route", "DAC", "Left DAC" }, - { "Headphone Source Playback Route", "DAC", "Right DAC" }, - { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, - { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, - { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "Left Headphone Source", "DAC", "Left DAC" }, + { "Left Headphone Source", "Mixer", "Left Mixer" }, + { "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" }, + { "Left Headphone Amp", NULL, "Left Headphone Switch" }, + { "Left Headphone Amp", NULL, "Headphone Amp" }, + { "HP", NULL, "Left Headphone Amp" }, + + { "Right Headphone Source", "DAC", "Right DAC" }, + { "Right Headphone Source", "Mixer", "Right Mixer" }, + { "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" }, + { "Right Headphone Amp", NULL, "Right Headphone Switch" }, + { "Right Headphone Amp", NULL, "Headphone Amp" }, + { "HP", NULL, "Right Headphone Amp" }, + { "Headphone Amp", NULL, "cpvdd" }, - { "HP", NULL, "Headphone Amp" }, /* Microphone Routes */ { "Mic1 Amplifier", NULL, "MIC1"}, /* Microphone Routes */ { "Mic2 Amplifier", NULL, "MIC2"}, - { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, - { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, - { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, - { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, - - /* Line-in Routes */ - { "Left Mixer", "Line In Playback Switch", "LINEIN" }, - { "Right Mixer", "Line In Playback Switch", "LINEIN" }, - { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, - { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, /* Line-out Routes */ - { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, - { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, - { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, - { "Line Out Source Playback Route", "Mono Differential", - "Right Mixer" }, - { "LINEOUT", NULL, "Line Out Source Playback Route" }, + { "Left Line Out Source", "Stereo", "Left Mixer" }, + { "Left Line Out Source", "Mono Differential", "Left Mixer" }, + { "Left Line Out Source", "Mono Differential", "Right Mixer" }, + { "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" }, + { "LINEOUT", NULL, "Left Line Out Switch" }, + + { "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" }, + { "Right Line Out Source", "Stereo", "Right Line Out Switch" }, + { "Right Line Out Source", "Mono Differential", "Left Line Out Switch" }, + { "LINEOUT", NULL, "Right Line Out Source" }, /* Earpiece Routes */ { "Earpiece Source Playback Route", "DACL", "Left DAC" }, { "Earpiece Source Playback Route", "DACR", "Right DAC" }, { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" }, { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" }, - { "Earpiece Amp", NULL, "Earpiece Source Playback Route" }, + { "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" }, + { "Earpiece Amp", NULL, "Earpiece Switch" }, { "EARPIECE", NULL, "Earpiece Amp" }, }; +static int sun50i_a64_codec_suspend(struct snd_soc_component *component) +{ + return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); +} + +static int sun50i_a64_codec_resume(struct snd_soc_component *component) +{ + return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0); +} + static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { .controls = sun50i_a64_codec_controls, .num_controls = ARRAY_SIZE(sun50i_a64_codec_controls), @@ -447,6 +491,8 @@ static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), .dapm_routes = sun50i_a64_codec_routes, .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), + .suspend = sun50i_a64_codec_suspend, + .resume = sun50i_a64_codec_resume, }; static const struct of_device_id sun50i_codec_analog_of_match[] = { diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index ca51af114419..178f6fb31fd4 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/log2.h> @@ -48,47 +49,52 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 #define SUN8I_AIF1_ADCDAT_CTRL 0x044 -#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA 15 -#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA 14 +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 +#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14 #define SUN8I_AIF1_DACDAT_CTRL 0x048 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14 #define SUN8I_AIF1_MXR_SRC 0x04c -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L 15 -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL 14 -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL 13 -#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR 12 +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15 +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14 +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13 +#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 #define SUN8I_ADC_DIG_CTRL 0x100 -#define SUN8I_ADC_DIG_CTRL_ENDA 15 +#define SUN8I_ADC_DIG_CTRL_ENAD 15 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1 #define SUN8I_DAC_DIG_CTRL 0x120 -#define SUN8I_DAC_DIG_CTRL_ENDA 15 +#define SUN8I_DAC_DIG_CTRL_ENDA 15 #define SUN8I_DAC_MXR_SRC 0x130 -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 -#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12 -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 -#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) +#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) +#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) + +struct sun8i_codec_quirks { + bool legacy_widgets : 1; + bool lrck_inversion : 1; +}; struct sun8i_codec { - struct regmap *regmap; - struct clk *clk_module; - struct clk *clk_bus; + struct regmap *regmap; + struct clk *clk_module; + const struct sun8i_codec_quirks *quirks; }; static int sun8i_codec_runtime_resume(struct device *dev) @@ -96,35 +102,15 @@ static int sun8i_codec_runtime_resume(struct device *dev) struct sun8i_codec *scodec = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(scodec->clk_module); - if (ret) { - dev_err(dev, "Failed to enable the module clock\n"); - return ret; - } - - ret = clk_prepare_enable(scodec->clk_bus); - if (ret) { - dev_err(dev, "Failed to enable the bus clock\n"); - goto err_disable_modclk; - } - regcache_cache_only(scodec->regmap, false); ret = regcache_sync(scodec->regmap); if (ret) { dev_err(dev, "Failed to sync regmap cache\n"); - goto err_disable_clk; + return ret; } return 0; - -err_disable_clk: - clk_disable_unprepare(scodec->clk_bus); - -err_disable_modclk: - clk_disable_unprepare(scodec->clk_module); - - return ret; } static int sun8i_codec_runtime_suspend(struct device *dev) @@ -134,9 +120,6 @@ static int sun8i_codec_runtime_suspend(struct device *dev) regcache_cache_only(scodec->regmap, true); regcache_mark_dirty(scodec->regmap); - clk_disable_unprepare(scodec->clk_module); - clk_disable_unprepare(scodec->clk_bus); - return 0; } @@ -209,18 +192,19 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); /* - * It appears that the DAI and the codec don't share the same - * polarity for the LRCK signal when they mean 'normal' and - * 'inverted' in the datasheet. + * It appears that the DAI and the codec in the A33 SoC don't + * share the same polarity for the LRCK signal when they mean + * 'normal' and 'inverted' in the datasheet. * * Since the DAI here is our regular i2s driver that have been * tested with way more codecs than just this one, it means * that the codec probably gets it backward, and we have to * invert the value here. */ + value ^= scodec->quirks->lrck_inversion; regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), - !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); + value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); /* DAI format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -366,43 +350,53 @@ static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = { SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L, + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L, SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0), SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL, + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL, SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0), SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL, + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL, SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0), SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, - SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR, + SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR, SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), }; static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { + SND_SOC_DAPM_CLOCK_SUPPLY("mod"), + /* Digital parts of the DACs and ADC */ SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA, + SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0), - /* Analog DAC AIF */ - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0, + /* AIF "DAC" Inputs */ + SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0, + SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 0, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), - /* Analog ADC AIF */ - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0, + /* AIF "ADC" Outputs */ + SND_SOC_DAPM_AIF_IN("AIF1 AD0L", "Capture", 0, SUN8I_AIF1_ADCDAT_CTRL, - SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0), - SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0, + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), + SND_SOC_DAPM_AIF_IN("AIF1 AD0R", "Capture", 0, SUN8I_AIF1_ADCDAT_CTRL, - SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0), + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), + + /* ADC Inputs (connected to analog codec DAPM context) */ + SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), + + /* DAC Outputs (connected to analog codec DAPM context) */ + SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), /* DAC and ADC Mixers */ SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, @@ -415,7 +409,7 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { sun8i_input_mixer_controls), /* Clocks */ - SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, + SND_SOC_DAPM_SUPPLY("MODCLK AIF1", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), @@ -439,50 +433,100 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), - - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Mic", NULL), - }; static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { /* Clock Routes */ + { "AIF1", NULL, "mod" }, + { "AIF1", NULL, "SYSCLK AIF1" }, { "AIF1 PLL", NULL, "AIF1" }, - { "RST AIF1", NULL, "AIF1 PLL" }, - { "MODCLK AFI1", NULL, "RST AIF1" }, - { "DAC", NULL, "MODCLK AFI1" }, - { "ADC", NULL, "MODCLK AFI1" }, + { "SYSCLK", NULL, "AIF1 PLL" }, + + { "RST AIF1", NULL, "SYSCLK" }, + { "MODCLK AIF1", NULL, "RST AIF1" }, + { "AIF1 AD0L", NULL, "MODCLK AIF1" }, + { "AIF1 AD0R", NULL, "MODCLK AIF1" }, + { "AIF1 DA0L", NULL, "MODCLK AIF1" }, + { "AIF1 DA0R", NULL, "MODCLK AIF1" }, { "RST DAC", NULL, "SYSCLK" }, { "MODCLK DAC", NULL, "RST DAC" }, { "DAC", NULL, "MODCLK DAC" }, + { "DACL", NULL, "DAC" }, + { "DACR", NULL, "DAC" }, { "RST ADC", NULL, "SYSCLK" }, { "MODCLK ADC", NULL, "RST ADC" }, { "ADC", NULL, "MODCLK ADC" }, + { "ADCL", NULL, "ADC" }, + { "ADCR", NULL, "ADC" }, /* DAC Routes */ - { "AIF1 Slot 0 Right", NULL, "DAC" }, - { "AIF1 Slot 0 Left", NULL, "DAC" }, + { "DACL", NULL, "Left Digital DAC Mixer" }, + { "DACR", NULL, "Right Digital DAC Mixer" }, /* DAC Mixer Routes */ - { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", - "AIF1 Slot 0 Left"}, - { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", - "AIF1 Slot 0 Right"}, + { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L" }, + { "Left Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCL" }, + + { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R" }, + { "Right Digital DAC Mixer", "ADC Digital DAC Playback Switch", "ADCR" }, /* ADC Routes */ - { "AIF1 Slot 0 Right ADC", NULL, "ADC" }, - { "AIF1 Slot 0 Left ADC", NULL, "ADC" }, + { "AIF1 AD0L", NULL, "Left Digital ADC Mixer" }, + { "AIF1 AD0R", NULL, "Right Digital ADC Mixer" }, /* ADC Mixer Routes */ - { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", - "AIF1 Slot 0 Left ADC" }, - { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", - "AIF1 Slot 0 Right ADC" }, + { "Left Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L" }, + { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" }, + + { "Right Digital ADC Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R" }, + { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" }, +}; + +static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = { + /* Legacy ADC Inputs (connected to analog codec DAPM context) */ + SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0), + + /* Legacy DAC Outputs (connected to analog codec DAPM context) */ + SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = { + /* Legacy ADC Routes */ + { "ADCL", NULL, "AIF1 Slot 0 Left ADC" }, + { "ADCR", NULL, "AIF1 Slot 0 Right ADC" }, + + /* Legacy DAC Routes */ + { "AIF1 Slot 0 Left", NULL, "DACL" }, + { "AIF1 Slot 0 Right", NULL, "DACR" }, }; +static int sun8i_codec_component_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); + int ret; + + /* Add widgets for backward compatibility with old device trees. */ + if (scodec->quirks->legacy_widgets) { + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, + ARRAY_SIZE(sun8i_codec_legacy_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes, + ARRAY_SIZE(sun8i_codec_legacy_routes)); + if (ret) + return ret; + } + + return 0; +} + static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { .hw_params = sun8i_codec_hw_params, .set_fmt = sun8i_set_fmt, @@ -516,6 +560,7 @@ static const struct snd_soc_component_driver sun8i_soc_component = { .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), .dapm_routes = sun8i_codec_dapm_routes, .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), + .probe = sun8i_codec_component_probe, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, @@ -547,25 +592,21 @@ static int sun8i_codec_probe(struct platform_device *pdev) return PTR_ERR(scodec->clk_module); } - scodec->clk_bus = devm_clk_get(&pdev->dev, "bus"); - if (IS_ERR(scodec->clk_bus)) { - dev_err(&pdev->dev, "Failed to get the bus clock\n"); - return PTR_ERR(scodec->clk_bus); - } - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); } - scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &sun8i_codec_regmap_config); + scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, + &sun8i_codec_regmap_config); if (IS_ERR(scodec->regmap)) { dev_err(&pdev->dev, "Failed to create our regmap\n"); return PTR_ERR(scodec->regmap); } + scodec->quirks = of_device_get_match_data(&pdev->dev); + platform_set_drvdata(pdev, scodec); pm_runtime_enable(&pdev->dev); @@ -603,8 +644,17 @@ static int sun8i_codec_remove(struct platform_device *pdev) return 0; } +static const struct sun8i_codec_quirks sun8i_a33_quirks = { + .legacy_widgets = true, + .lrck_inversion = true, +}; + +static const struct sun8i_codec_quirks sun50i_a64_quirks = { +}; + static const struct of_device_id sun8i_codec_of_match[] = { - { .compatible = "allwinner,sun8i-a33-codec" }, + { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks }, + { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 1e6ab87e4460..9775393d46b6 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -221,7 +221,7 @@ config SND_SOC_DM365_VOICE_CODEC_MODULE config SND_SOC_J721E_EVM tristate "SoC Audio support for j721e EVM" - depends on ARCH_K3_J721E_SOC || COMPILE_TEST + depends on ARCH_K3 || COMPILE_TEST depends on I2C select SND_SOC_PCM3168A_I2C select SND_SOC_DAVINCI_MCASP diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 617440767c45..3ffdd0f6292a 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -633,7 +633,7 @@ static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id, * right channels), so it has to be divided by number * of tdm-slots (for I2S - divided by 2). * Instead of storing this ratio, we calculate a new - * tdm_slot width by dividing the the ratio by the + * tdm_slot width by dividing the ratio by the * number of configured tdm slots. */ mcasp->slot_width = div / mcasp->tdm_slots; diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index 1d3586b68db7..5bd2730aab76 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -9,14 +9,14 @@ config SND_SOC_XILINX_I2S encapsulates PCM in AES format and sends AES data. config SND_SOC_XILINX_AUDIO_FORMATTER - tristate "Audio support for the the Xilinx audio formatter" + tristate "Audio support for the Xilinx audio formatter" help Select this option to enable Xilinx audio formatter support. This provides DMA platform device support for audio functionality. config SND_SOC_XILINX_SPDIF - tristate "Audio support for the the Xilinx SPDIF" + tristate "Audio support for the Xilinx SPDIF" help Select this option to enable Xilinx SPDIF Audio. This provides playback and capture of SPDIF audio in |