diff options
378 files changed, 6989 insertions, 2118 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2518.yaml b/Documentation/devicetree/bindings/sound/adi,ssm2518.yaml new file mode 100644 index 000000000000..f3f32540779c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm2518.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/adi,ssm2518.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices SSM2518 audio amplifier + +maintainers: + - Lars-Peter Clausen <lars@metafoo.de> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: adi,ssm2518 + + reg: + maxItems: 1 + description: | + I2C address of the device. This will either be 0x34 (ADDR pin low) + or 0x35 (ADDR pin high) + + gpios: + maxItems: 1 + description: | + GPIO connected to the nSD pin. If the property is not present + it is assumed that the nSD pin is hardwired to always on. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@34 { + compatible = "adi,ssm2518"; + reg = <0x34>; + gpios = <&gpio 5 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml new file mode 100644 index 000000000000..144450df5869 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm3515.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/adi,ssm3515.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices SSM3515 Audio Amplifier + +maintainers: + - Martin PoviÅ¡er <povik+lin@cutebit.org> + +description: | + SSM3515 is a mono Class-D audio amplifier with digital input. + + https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515.pdf + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - adi,ssm3515 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@14 { + compatible = "adi,ssm3515"; + reg = <0x14>; + #sound-dai-cells = <0>; + sound-name-prefix = "Left Tweeter"; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt deleted file mode 100644 index add1caf26ac2..000000000000 --- a/Documentation/devicetree/bindings/sound/da7219.txt +++ /dev/null @@ -1,112 +0,0 @@ -Dialog Semiconductor DA7219 Audio Codec bindings - -DA7219 is an audio codec with advanced accessory detect features. - -====== - -Required properties: -- compatible : Should be "dlg,da7219" -- reg: Specifies the I2C slave address - -- interrupts : IRQ line info for DA7219. - (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for - further information relating to interrupt properties) - -- VDD-supply: VDD power supply for the device -- VDDMIC-supply: VDDMIC power supply for the device -- VDDIO-supply: VDDIO power supply for the device - (See Documentation/devicetree/bindings/regulator/regulator.txt for further - information relating to regulators) - -Optional properties: -- interrupt-names : Name associated with interrupt line. Should be "wakeup" if - interrupt is to be used to wake system, otherwise "irq" should be used. -- wakeup-source: Flag to indicate this device can wake system (suspend/resume). - -- #clock-cells : Should be set to '<1>', two clock sources provided; -- clock-output-names : Names given for DAI clock outputs (WCLK & BCLK); - -- clocks : phandle and clock specifier for codec MCLK. -- clock-names : Clock name string for 'clocks' attribute, should be "mclk". - -- dlg,micbias-lvl : Voltage (mV) for Mic Bias - [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>] -- dlg,mic-amp-in-sel : Mic input source type - ["diff", "se_p", "se_n"] - -Deprecated properties: -- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine - (LDO unavailable in production HW so property no longer required). - -====== - -Child node - 'da7219_aad': - -Optional properties: -- dlg,micbias-pulse-lvl : Mic bias higher voltage pulse level (mV). - [<2800>, <2900>] -- dlg,micbias-pulse-time : Mic bias higher voltage pulse duration (ms) -- dlg,btn-cfg : Periodic button press measurements for 4-pole jack (ms) - [<2>, <5>, <10>, <50>, <100>, <200>, <500>] -- dlg,mic-det-thr : Impedance threshold for mic detection measurement (Ohms) - [<200>, <500>, <750>, <1000>] -- dlg,jack-ins-deb : Debounce time for jack insertion (ms) - [<5>, <10>, <20>, <50>, <100>, <200>, <500>, <1000>] -- dlg,jack-det-rate: Jack type detection latency (3/4 pole) - ["32ms_64ms", "64ms_128ms", "128ms_256ms", "256ms_512ms"] -- dlg,jack-rem-deb : Debounce time for jack removal (ms) - [<1>, <5>, <10>, <20>] -- dlg,a-d-btn-thr : Impedance threshold between buttons A and D - [0x0 - 0xFF] -- dlg,d-b-btn-thr : Impedance threshold between buttons D and B - [0x0 - 0xFF] -- dlg,b-c-btn-thr : Impedance threshold between buttons B and C - [0x0 - 0xFF] -- dlg,c-mic-btn-thr : Impedance threshold between button C and Mic - [0x0 - 0xFF] -- dlg,btn-avg : Number of 8-bit readings for averaged button measurement - [<1>, <2>, <4>, <8>] -- dlg,adc-1bit-rpt : Repeat count for 1-bit button measurement - [<1>, <2>, <4>, <8>] - -====== - -Example: - - codec: da7219@1a { - compatible = "dlg,da7219"; - reg = <0x1a>; - - interrupt-parent = <&gpio6>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; - - VDD-supply = <®_audio>; - VDDMIC-supply = <®_audio>; - VDDIO-supply = <®_audio>; - - #clock-cells = <1>; - clock-output-names = "dai-wclk", "dai-bclk"; - - clocks = <&clks 201>; - clock-names = "mclk"; - - dlg,ldo-lvl = <1200>; - dlg,micbias-lvl = <2600>; - dlg,mic-amp-in-sel = "diff"; - - da7219_aad { - dlg,btn-cfg = <50>; - dlg,mic-det-thr = <500>; - dlg,jack-ins-deb = <20>; - dlg,jack-det-rate = "32ms_64ms"; - dlg,jack-rem-deb = <1>; - - dlg,a-d-btn-thr = <0xa>; - dlg,d-b-btn-thr = <0x16>; - dlg,b-c-btn-thr = <0x21>; - dlg,c-mic-btn-thr = <0x3E>; - - dlg,btn-avg = <4>; - dlg,adc-1bit-rpt = <1>; - }; - }; diff --git a/Documentation/devicetree/bindings/sound/dialog,da7219.yaml b/Documentation/devicetree/bindings/sound/dialog,da7219.yaml new file mode 100644 index 000000000000..bb5af48ab1e1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/dialog,da7219.yaml @@ -0,0 +1,237 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/dialog,da7219.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dialog Semiconductor DA7219 Audio Codec + +maintainers: + - David Rau <David.Rau.opensource@dm.renesas.com> + +description: + The DA7219 is an ultra low-power audio codec with + in-built advanced accessory detection (AAD) for mobile + computing and accessory applications, which supports + sample rates up to 96 kHz at 24-bit resolution. + +properties: + compatible: + const: dlg,da7219 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + VDD-supply: + description: + VDD power supply for the device. + + VDDMIC-supply: + description: + VDDMIC power supply for the device. + + VDDIO-supply: + description: + VDDIO power supply for the device. + + interrupt-names: + description: + Should be "wakeup" if interrupt is to be used to wake system, + otherwise "irq" should be used. + enum: + - wakeup + - irq + + wakeup-source: + type: boolean + description: + Flag to indicate this device can wake system (suspend/resume). + + "#clock-cells": + const: 1 + + clock-output-names: + minItems: 2 + maxItems: 2 + description: + Name given for DAI WCLK and BCLK outputs. + + clocks: + maxItems: 1 + description: + phandle and clock specifier for codec MCLK. + + clock-names: + const: mclk + + dlg,micbias-lvl: + enum: [1600, 1800, 2000, 2200, 2400, 2600] + description: + Voltage (mV) for Mic Bias. + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,mic-amp-in-sel: + enum: ["diff", "se_p", "se_n"] + description: + Mic input source type. + + diff - Differential. + + se_p - MIC_P. + Positive differential analog microphone input. + + se_n - MIC_N. + Negative differential analog microphone input. + $ref: /schemas/types.yaml#/definitions/string + + da7219_aad: + type: object + description: + Configuration of advanced accessory detection. + properties: + dlg,micbias-pulse-lvl: + enum: [2800, 2900] + description: + Mic bias higher voltage pulse level (mV). + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,micbias-pulse-time: + description: + Mic bias higher voltage pulse duration (ms). + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + + dlg,btn-cfg: + enum: [2, 5, 10, 50, 100, 200, 500] + description: + Periodic button press measurements for 4-pole jack (ms). + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,mic-det-thr: + enum: [200, 500, 750, 1000] + description: + Impedance threshold for mic detection measurement (Ohms). + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,jack-ins-deb: + enum: [5, 10, 20, 50, 100, 200, 500, 1000] + description: + Debounce time for jack insertion (ms). + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,jack-ins-det-pty: + enum: ["low", "high"] + description: + Polarity for jack insertion detection. + $ref: /schemas/types.yaml#/definitions/string + + dlg,jack-det-rate: + enum: ["32_64", "64_128", "128_256", "256_512"] + description: + Jack type (3/4 pole) detection latency (ms). + $ref: /schemas/types.yaml#/definitions/string + + dlg,jack-rem-deb: + enum: [1, 5, 10, 20] + description: + Debounce time for jack removal (ms). + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,a-d-btn-thr: + description: + Impedance threshold between buttons A and D. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + + dlg,d-b-btn-thr: + description: + Impedance threshold between buttons D and B. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + + dlg,b-c-btn-thr: + description: + Impedance threshold between buttons B and C. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + + dlg,c-mic-btn-thr: + description: + Impedance threshold between button C and Mic. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + + dlg,btn-avg: + enum: [1, 2, 4, 8] + description: + Number of 8-bit readings for averaged button measurement. + $ref: /schemas/types.yaml#/definitions/uint32 + + dlg,adc-1bit-rpt: + enum: [1, 2, 4, 8] + description: + Repeat count for 1-bit button measurement. + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + - interrupts + - VDD-supply + - VDDMIC-supply + - VDDIO-supply + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec: da7219@1a { + compatible = "dlg,da7219"; + reg = <0x1a>; + + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + + VDD-supply = <&vdd_reg>; + VDDMIC-supply = <&vddmic_reg>; + VDDIO-supply = <&vddio_reg>; + + #clock-cells = <1>; + clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk"; + + clocks = <&clks 201>; + clock-names = "mclk"; + + dlg,micbias-lvl = <2600>; + dlg,mic-amp-in-sel = "diff"; + + da7219_aad { + dlg,btn-cfg = <50>; + dlg,mic-det-thr = <500>; + dlg,jack-ins-deb = <20>; + dlg,jack-ins-det-pty = "low"; + dlg,jack-det-rate = "32_64"; + dlg,jack-rem-deb = <1>; + + dlg,a-d-btn-thr = <0xa>; + dlg,d-b-btn-thr = <0x16>; + dlg,b-c-btn-thr = <0x21>; + dlg,c-mic-btn-thr = <0x3E>; + + dlg,btn-avg = <4>; + dlg,adc-1bit-rpt = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/google,chv3-codec.yaml b/Documentation/devicetree/bindings/sound/google,chv3-codec.yaml new file mode 100644 index 000000000000..5329dc140b1c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/google,chv3-codec.yaml @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/google,chv3-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google Chameleon v3 audio codec + +maintainers: + - PaweÅ‚ Anikiel <pan@semihalf.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: google,chv3-codec + + "#sound-dai-cells": + const: 0 + +required: + - compatible + +additionalProperties: false + +examples: + - | + audio-codec { + compatible = "google,chv3-codec"; + }; diff --git a/Documentation/devicetree/bindings/sound/google,chv3-i2s.yaml b/Documentation/devicetree/bindings/sound/google,chv3-i2s.yaml new file mode 100644 index 000000000000..3ce910f44d39 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/google,chv3-i2s.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/google,chv3-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google Chameleon v3 I2S device + +maintainers: + - PaweÅ‚ Anikiel <pan@semihalf.com> + +description: | + I2S device for the Google Chameleon v3. The device handles both RX + and TX using a producer/consumer ring buffer design. + +properties: + compatible: + const: google,chv3-i2s + + reg: + items: + - description: core registers + - description: irq registers + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + i2s@c0060300 { + compatible = "google,chv3-i2s"; + reg = <0xc0060300 0x100>, + <0xc0060f00 0x10>; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml index 67ccddd44489..666a95ac22c8 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml @@ -74,7 +74,8 @@ patternProperties: properties: sound-dai: - maxItems: 1 + minItems: 1 + maxItems: 4 required: - link-name diff --git a/Documentation/devicetree/bindings/sound/ingenic,aic.yaml b/Documentation/devicetree/bindings/sound/ingenic,aic.yaml index c59a7cd9eaa9..d15c000f14e1 100644 --- a/Documentation/devicetree/bindings/sound/ingenic,aic.yaml +++ b/Documentation/devicetree/bindings/sound/ingenic,aic.yaml @@ -23,6 +23,7 @@ properties: - ingenic,jz4760-i2s - ingenic,jz4770-i2s - ingenic,jz4780-i2s + - ingenic,x1000-i2s - items: - const: ingenic,jz4725b-i2s - const: ingenic,jz4740-i2s diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml index 82ccb32f08f2..e6cb711ece77 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml @@ -29,6 +29,10 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the mediatek topckgen controller + mediatek,infracfg: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the mediatek infracfg controller + power-domains: maxItems: 1 @@ -52,6 +56,11 @@ properties: - description: mux for i2si1_mck - description: mux for i2si2_mck - description: audio 26m clock + - description: audio pll1 divide 4 + - description: audio pll2 divide 4 + - description: clock divider for iec + - description: mux for a2sys clock + - description: mux for aud_iec clock-names: items: @@ -63,16 +72,21 @@ properties: - const: apll12_div2 - const: apll12_div3 - const: apll12_div9 - - const: a1sys_hp_sel - - const: aud_intbus_sel - - const: audio_h_sel - - const: audio_local_bus_sel - - const: dptx_m_sel - - const: i2so1_m_sel - - const: i2so2_m_sel - - const: i2si1_m_sel - - const: i2si2_m_sel + - const: top_a1sys_hp + - const: top_aud_intbus + - const: top_audio_h + - const: top_audio_local_bus + - const: top_dptx + - const: top_i2so1 + - const: top_i2so2 + - const: top_i2si1 + - const: top_i2si2 - const: adsp_audio_26m + - const: apll1_d4 + - const: apll2_d4 + - const: apll12_div4 + - const: top_a2sys + - const: top_aud_iec mediatek,etdm-in1-cowork-source: $ref: /schemas/types.yaml#/definitions/uint32 @@ -144,6 +158,7 @@ required: - resets - reset-names - mediatek,topckgen + - mediatek,infracfg - power-domains - clocks - clock-names @@ -162,6 +177,7 @@ examples: resets = <&watchdog 14>; reset-names = "audiosys"; mediatek,topckgen = <&topckgen>; + mediatek,infracfg = <&infracfg_ao>; power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO mediatek,etdm-in2-cowork-source = <2>; mediatek,etdm-out2-cowork-source = <0>; @@ -184,7 +200,12 @@ examples: <&topckgen 78>, //CLK_TOP_I2SO2 <&topckgen 79>, //CLK_TOP_I2SI1 <&topckgen 80>, //CLK_TOP_I2SI2 - <&adsp_audio26m 0>; //CLK_AUDIODSP_AUDIO26M + <&adsp_audio26m 0>, //CLK_AUDIODSP_AUDIO26M + <&topckgen 132>, //CLK_TOP_APLL1_D4 + <&topckgen 133>, //CLK_TOP_APLL2_D4 + <&topckgen 183>, //CLK_TOP_APLL12_CK_DIV4 + <&topckgen 84>, //CLK_TOP_A2SYS + <&topckgen 82>; //CLK_TOP_AUD_IEC>; clock-names = "clk26m", "apll1", "apll2", @@ -193,16 +214,21 @@ examples: "apll12_div2", "apll12_div3", "apll12_div9", - "a1sys_hp_sel", - "aud_intbus_sel", - "audio_h_sel", - "audio_local_bus_sel", - "dptx_m_sel", - "i2so1_m_sel", - "i2so2_m_sel", - "i2si1_m_sel", - "i2si2_m_sel", - "adsp_audio_26m"; + "top_a1sys_hp", + "top_aud_intbus", + "top_audio_h", + "top_audio_local_bus", + "top_dptx", + "top_i2so1", + "top_i2so2", + "top_i2si1", + "top_i2si2", + "adsp_audio_26m", + "apll1_d4", + "apll2_d4", + "apll12_div4", + "top_a2sys", + "top_aud_iec"; }; ... diff --git a/Documentation/devicetree/bindings/sound/nau8315.txt b/Documentation/devicetree/bindings/sound/nau8315.txt deleted file mode 100644 index 1cd94517d45e..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8315.txt +++ /dev/null @@ -1,24 +0,0 @@ -Nuvoton NAU8315 Mono Class-D Amplifier - -Required properties: -- compatible : "nuvoton,nau8315" - "nuvoton,nau8318" - -Optional properties: -- enable-gpios : GPIO specifier for the chip's device enable input(EN) pin. - If this option is not specified then driver does not manage - the pin state (e.g. chip is always on). - -Example: - -#include <dt-bindings/gpio/gpio.h> - -nau8315 { - compatible = "nuvoton,nau8315"; - enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; -}; - -nau8318 { - compatible = "nuvoton,nau8318"; - enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/sound/nau8540.txt b/Documentation/devicetree/bindings/sound/nau8540.txt deleted file mode 100644 index 307a76528320..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8540.txt +++ /dev/null @@ -1,16 +0,0 @@ -NAU85L40 audio CODEC - -This device supports I2C only. - -Required properties: - - - compatible : "nuvoton,nau8540" - - - reg : the I2C address of the device. - -Example: - -codec: nau8540@1c { - compatible = "nuvoton,nau8540"; - reg = <0x1c>; -}; diff --git a/Documentation/devicetree/bindings/sound/nau8810.txt b/Documentation/devicetree/bindings/sound/nau8810.txt deleted file mode 100644 index 7deaa452b200..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8810.txt +++ /dev/null @@ -1,17 +0,0 @@ -NAU8810/NAU8812/NAU8814 audio CODEC - -This device supports I2C only. - -Required properties: - - - compatible : One of "nuvoton,nau8810" or "nuvoton,nau8812" or - "nuvoton,nau8814" - - - reg : the I2C address of the device. - -Example: - -codec: nau8810@1a { - compatible = "nuvoton,nau8810"; - reg = <0x1a>; -}; diff --git a/Documentation/devicetree/bindings/sound/nau8824.txt b/Documentation/devicetree/bindings/sound/nau8824.txt deleted file mode 100644 index e0058b97e49a..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8824.txt +++ /dev/null @@ -1,88 +0,0 @@ -Nuvoton NAU8824 audio codec - -This device supports I2C only. - -Required properties: - - compatible : Must be "nuvoton,nau8824" - - - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1). - -Optional properties: - - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. - - - nuvoton,vref-impedance: VREF Impedance selection - 0 - Open - 1 - 25 kOhm - 2 - 125 kOhm - 3 - 2.5 kOhm - - - nuvoton,micbias-voltage: Micbias voltage level. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,sar-threshold-num: Number of buttons supported - - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as - SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) - where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance. - Refer datasheet section 10.2 for more information about threshold calculation. - - - nuvoton,sar-hysteresis: Button impedance measurement hysteresis. - - - nuvoton,sar-voltage: Reference voltage for button impedance measurement. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,sar-compare-time: SAR compare time - 0 - 500 ns - 1 - 1 us - 2 - 2 us - 3 - 4 us - - - nuvoton,sar-sampling-time: SAR sampling time - 0 - 2 us - 1 - 4 us - 2 - 8 us - 3 - 16 us - - - nuvoton,short-key-debounce: Button short key press debounce time. - 0 - 30 ms - 1 - 50 ms - 2 - 100 ms - - - nuvoton,jack-eject-debounce: Jack ejection debounce time. - 0 - 0 ms - 1 - 1 ms - 2 - 10 ms - - -Example: - - headset: nau8824@1a { - compatible = "nuvoton,nau8824"; - reg = <0x1a>; - interrupt-parent = <&gpio>; - interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>; - nuvoton,vref-impedance = <2>; - nuvoton,micbias-voltage = <6>; - // Setup 4 buttons impedance according to Android specification - nuvoton,sar-threshold-num = <4>; - nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; - nuvoton,sar-hysteresis = <0>; - nuvoton,sar-voltage = <6>; - nuvoton,sar-compare-time = <1>; - nuvoton,sar-sampling-time = <1>; - nuvoton,short-key-debounce = <0>; - nuvoton,jack-eject-debounce = <1>; - }; diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt deleted file mode 100644 index a9c34526f4cb..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8825.txt +++ /dev/null @@ -1,111 +0,0 @@ -Nuvoton NAU8825 audio codec - -This device supports I2C only. - -Required properties: - - compatible : Must be "nuvoton,nau8825" - - - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1). - -Optional properties: - - nuvoton,jkdet-enable: Enable jack detection via JKDET pin. - - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled, - otherwise pin in high impedance state. - - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down. - - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. - - - nuvoton,vref-impedance: VREF Impedance selection - 0 - Open - 1 - 25 kOhm - 2 - 125 kOhm - 3 - 2.5 kOhm - - - nuvoton,micbias-voltage: Micbias voltage level. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,sar-threshold-num: Number of buttons supported - - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as - SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) - where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance. - Refer datasheet section 10.2 for more information about threshold calculation. - - - nuvoton,sar-hysteresis: Button impedance measurement hysteresis. - - - nuvoton,sar-voltage: Reference voltage for button impedance measurement. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,sar-compare-time: SAR compare time - 0 - 500 ns - 1 - 1 us - 2 - 2 us - 3 - 4 us - - - nuvoton,sar-sampling-time: SAR sampling time - 0 - 2 us - 1 - 4 us - 2 - 8 us - 3 - 16 us - - - nuvoton,short-key-debounce: Button short key press debounce time. - 0 - 30 ms - 1 - 50 ms - 2 - 100 ms - 3 - 30 ms - - - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - - nuvoton,crosstalk-enable: make crosstalk function enable if set. - - - nuvoton,adcout-drive-strong: make the drive strength of ADCOUT IO PIN strong if set. - Otherwise, the drive keeps normal strength. - - - nuvoton,adc-delay-ms: Delay (in ms) to make input path stable and avoid pop noise. The - default value is 125 and range between 125 to 500 ms. - - - clocks: list of phandle and clock specifier pairs according to common clock bindings for the - clocks described in clock-names - - clock-names: should include "mclk" for the MCLK master clock - -Example: - - headset: nau8825@1a { - compatible = "nuvoton,nau8825"; - reg = <0x1a>; - interrupt-parent = <&gpio>; - interrupts = <TEGRA_GPIO(E, 6) IRQ_TYPE_LEVEL_LOW>; - nuvoton,jkdet-enable; - nuvoton,jkdet-pull-enable; - nuvoton,jkdet-pull-up; - nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>; - nuvoton,vref-impedance = <2>; - nuvoton,micbias-voltage = <6>; - // Setup 4 buttons impedance according to Android specification - nuvoton,sar-threshold-num = <4>; - nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; - nuvoton,sar-hysteresis = <1>; - nuvoton,sar-voltage = <0>; - nuvoton,sar-compare-time = <0>; - nuvoton,sar-sampling-time = <0>; - nuvoton,short-key-debounce = <2>; - nuvoton,jack-insert-debounce = <7>; - nuvoton,jack-eject-debounce = <7>; - nuvoton,crosstalk-enable; - - clock-names = "mclk"; - clocks = <&tegra_pmc TEGRA_PMC_CLK_OUT_2>; - }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8315.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8315.yaml new file mode 100644 index 000000000000..24006e9dc501 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8315.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8315.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU8315/NAU8318 Mono Class-D Amplifier + +maintainers: + - David Lin <CTLIN0@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nuvoton,nau8315 + - nuvoton,nau8318 + + '#sound-dai-cells': + const: 0 + + enable-gpios: + maxItems: 1 + description: + GPIO specifier for the chip's device enable input(EN) pin. + If this option is not specified then driver does not manage + the pin state (e.g. chip is always on). + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + codec { + compatible = "nuvoton,nau8315"; + #sound-dai-cells = <0>; + enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8540.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8540.yaml new file mode 100644 index 000000000000..7ccfbb8d8b04 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8540.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8540.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton Technology Corporation NAU85L40 Audio CODEC + +maintainers: + - John Hsu <KCHSU0@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: nuvoton,nau8540 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1c { + compatible = "nuvoton,nau8540"; + reg = <0x1c>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8810.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8810.yaml new file mode 100644 index 000000000000..d9696f6c75ed --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8810.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8810.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU8810/NAU8812/NAU8814 audio CODEC + +maintainers: + - David Lin <CTLIN0@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nuvoton,nau8810 + - nuvoton,nau8812 + - nuvoton,nau8814 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + #sound-dai-cells = <0>; + compatible = "nuvoton,nau8810"; + reg = <0x1a>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml new file mode 100644 index 000000000000..3dbf438c3841 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8824.yaml @@ -0,0 +1,182 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8824.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU8824 audio CODEC + +maintainers: + - John Hsu <KCHSU0@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nuvoton,nau8824 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + interrupts: + maxItems: 1 + + nuvoton,jkdet-polarity: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + JKDET pin polarity. + enum: + - 0 # active high + - 1 # active low + default: 1 + + nuvoton,vref-impedance: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + VREF Impedance selection. + enum: + - 0 # Open + - 1 # 25 kOhm + - 2 # 125 kOhm + - 3 # 2.5 kOhm + default: 2 + + nuvoton,micbias-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Micbias voltage level. + enum: + - 0 # VDDA + - 1 # VDDA + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,sar-threshold-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of buttons supported. + minimum: 1 + maximum: 8 + default: 4 + + nuvoton,sar-threshold: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Impedance threshold for each button. Array that contains up to 8 buttons + configuration. SAR value is calculated as + SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) where MICBIAS is + configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by + 'nuvoton,sar-voltage', R - button impedance. + Refer datasheet section 10.2 for more information about threshold + calculation. + minItems: 1 + maxItems: 8 + items: + minimum: 0 + maximum: 255 + + nuvoton,sar-hysteresis: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Button impedance measurement hysteresis. + default: 0 + + nuvoton,sar-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Reference voltage for button impedance measurement. + enum: + - 0 # VDDA + - 1 # VDDA + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,sar-compare-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + SAR compare time. + enum: + - 0 # 500ns + - 1 # 1us + - 2 # 2us + - 3 # 4us + default: 1 + + nuvoton,sar-sampling-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + SAR sampling time. + enum: + - 0 # 2us + - 1 # 4us + - 2 # 8us + - 3 # 16us + default: 1 + + nuvoton,short-key-debounce: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Button short key press debounce time. + enum: + - 0 # 30 ms + - 1 # 50 ms + - 2 # 100 ms + default: 0 + + nuvoton,jack-eject-debounce: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Jack ejection debounce time. + enum: + - 0 # 0 ms + - 1 # 1 ms + - 2 # 10 ms + default: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + #sound-dai-cells = <0>; + compatible = "nuvoton,nau8824"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <38 IRQ_TYPE_LEVEL_LOW>; + nuvoton,vref-impedance = <2>; + nuvoton,micbias-voltage = <6>; + nuvoton,sar-threshold-num = <4>; + // Setup 4 buttons impedance according to Android specification + nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; + nuvoton,sar-hysteresis = <0>; + nuvoton,sar-voltage = <6>; + nuvoton,sar-compare-time = <1>; + nuvoton,sar-sampling-time = <1>; + nuvoton,short-key-debounce = <0>; + nuvoton,jack-eject-debounce = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml new file mode 100644 index 000000000000..a54f194a0b49 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8825.yaml @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8825.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU8825 audio CODEC + +maintainers: + - John Hsu <KCHSU0@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nuvoton,nau8825 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + nuvoton,jkdet-enable: + description: + Enable jack detection via JKDET pin. + type: boolean + + nuvoton,jkdet-pull-enable: + description: + Enable JKDET pin pull. + If set - pin pull enabled, otherwise pin in high impedance state. + type: boolean + + nuvoton,jkdet-pull-up: + description: + Pull-up JKDET pin. + If set then JKDET pin is pull up, otherwise pull down. + type: boolean + + nuvoton,jkdet-polarity: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + JKDET pin polarity. + enum: + - 0 # active high + - 1 # active low + default: 1 + + nuvoton,vref-impedance: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + VREF Impedance selection. + enum: + - 0 # Open + - 1 # 25 kOhm + - 2 # 125 kOhm + - 3 # 2.5 kOhm + default: 2 + + nuvoton,micbias-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Micbias voltage level. + enum: + - 0 # VDDA + - 1 # VDDA + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,sar-threshold-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of buttons supported. + minimum: 1 + maximum: 4 + default: 4 + + nuvoton,sar-threshold: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Impedance threshold for each button. Array that contains up to 8 buttons + configuration. SAR value is calculated as + SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) where MICBIAS is + configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by + 'nuvoton,sar-voltage', R - button impedance. + Refer datasheet section 10.2 for more information about threshold + calculation. + minItems: 1 + maxItems: 4 + items: + minimum: 0 + maximum: 255 + + nuvoton,sar-hysteresis: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Button impedance measurement hysteresis. + default: 0 + + nuvoton,sar-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Reference voltage for button impedance measurement. + enum: + - 0 # VDDA + - 1 # VDDA + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,sar-compare-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + SAR compare time. + enum: + - 0 # 500 ns + - 1 # 1 us + - 2 # 2 us + - 3 # 4 us + default: 1 + + nuvoton,sar-sampling-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + SAR sampling time. + enum: + - 0 # 2 us + - 1 # 4 us + - 2 # 8 us + - 3 # 16 us + default: 1 + + nuvoton,short-key-debounce: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Button short key press debounce time. + enum: + - 0 # 30 ms + - 1 # 50 ms + - 2 # 100 ms + - 3 # 30 ms + default: 3 + + nuvoton,jack-insert-debounce: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + number from 0 to 7 that sets debounce time to 2^(n+2) ms. + maximum: 7 + default: 7 + + nuvoton,jack-eject-debounce: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + number from 0 to 7 that sets debounce time to 2^(n+2) ms + maximum: 7 + default: 0 + + nuvoton,crosstalk-enable: + description: + make crosstalk function enable if set. + type: boolean + + nuvoton,adcout-drive-strong: + description: + make the drive strength of ADCOUT IO PIN strong if set. + Otherwise, the drive keeps normal strength. + type: boolean + + nuvoton,adc-delay-ms: + description: + Delay (in ms) to make input path stable and avoid pop noise. + The default value is 125 and range between 125 to 500 ms. + minimum: 125 + maximum: 500 + default: 125 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: mclk + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + #sound-dai-cells = <0>; + compatible = "nuvoton,nau8825"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <38 IRQ_TYPE_LEVEL_LOW>; + nuvoton,jkdet-enable; + nuvoton,jkdet-pull-enable; + nuvoton,jkdet-pull-up; + nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>; + nuvoton,vref-impedance = <2>; + nuvoton,micbias-voltage = <6>; + // Setup 4 buttons impedance according to Android specification + nuvoton,sar-threshold-num = <4>; + nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; + nuvoton,sar-hysteresis = <1>; + nuvoton,sar-voltage = <0>; + nuvoton,sar-compare-time = <0>; + nuvoton,sar-sampling-time = <0>; + nuvoton,short-key-debounce = <2>; + nuvoton,jack-insert-debounce = <7>; + nuvoton,jack-eject-debounce = <7>; + nuvoton,crosstalk-enable; + + clock-names = "mclk"; + clocks = <&tegra_pmc 1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml index 7c1e9895ce85..2588589ad62d 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-common.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/nvidia,tegra-audio-common.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Common properties for NVIDIA Tegra audio complexes diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml index cdbb4096fa44..9e5b30d9c6e6 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/qcom,q6apm-dai.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/qcom,q6apm-dai.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Audio Process Manager Digital Audio Interfaces diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml index 1168410f6fbd..3552c44137ed 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-clocks.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-clocks.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-clocks.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm DSP LPASS Clock Controller diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml index 044e77718a1b..08c618e7e428 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-ports.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-ports.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm DSP LPASS(Low Power Audio SubSystem) Audio Ports diff --git a/Documentation/devicetree/bindings/sound/realtek,rt1016.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1016.yaml new file mode 100644 index 000000000000..5287e9c9197e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt1016.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt1016.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Reaktek RT1016 Stereo Class D Audio Amplifier + +maintainers: + - oder_chiou@realtek.com + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: realtek,rt1016 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + compatible = "realtek,rt1016"; + reg = <0x1a>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/rt1016.txt b/Documentation/devicetree/bindings/sound/rt1016.txt deleted file mode 100644 index 2310f8ff259b..000000000000 --- a/Documentation/devicetree/bindings/sound/rt1016.txt +++ /dev/null @@ -1,17 +0,0 @@ -RT1016 Stereo Class D Audio Amplifier - -This device supports I2C only. - -Required properties: - -- compatible : "realtek,rt1016". - -- reg : The I2C address of the device. - - -Example: - -rt1016: codec@1a { - compatible = "realtek,rt1016"; - reg = <0x1a>; -}; diff --git a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml index 56e623d4e168..a970fd264b21 100644 --- a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml @@ -36,7 +36,8 @@ properties: const: i2sclk resets: - maxItems: 1 + items: + - description: Optional controller resets dmas: items: diff --git a/Documentation/devicetree/bindings/sound/ssm2518.txt b/Documentation/devicetree/bindings/sound/ssm2518.txt deleted file mode 100644 index 59381a778c79..000000000000 --- a/Documentation/devicetree/bindings/sound/ssm2518.txt +++ /dev/null @@ -1,20 +0,0 @@ -SSM2518 audio amplifier - -This device supports I2C only. - -Required properties: - - compatible : Must be "adi,ssm2518" - - reg : the I2C address of the device. This will either be 0x34 (ADDR pin low) - or 0x35 (ADDR pin high) - -Optional properties: - - gpios : GPIO connected to the nSD pin. If the property is not present it is - assumed that the nSD pin is hardwired to always on. - -Example: - - ssm2518: ssm2518@34 { - compatible = "adi,ssm2518"; - reg = <0x34>; - gpios = <&gpio 5 0>; - }; diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml index 31a3024ea789..f01c0dde0cf7 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/tas2562.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2019 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/tas2562.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/tas2562.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2562 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/tas2770.yaml index 8908bf1122e9..be2536e8c440 100644 --- a/Documentation/devicetree/bindings/sound/tas2770.yaml +++ b/Documentation/devicetree/bindings/sound/tas2770.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2019-20 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/tas2770.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/tas2770.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2770 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/tas27xx.yaml index a876545ec87d..f2d878f6f495 100644 --- a/Documentation/devicetree/bindings/sound/tas27xx.yaml +++ b/Documentation/devicetree/bindings/sound/tas27xx.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020-2022 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/tas27xx.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/tas27xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2764/TAS2780 Smart PA diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml index 7105ed5fd6c7..4cfa66f62681 100644 --- a/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8903.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/sound/wlf,wm8903.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/sound/wlf,wm8903.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: WM8903 audio codec diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 9f7c5103bc82..39f203256c4f 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -131,6 +131,14 @@ #define RX_CODEC_DMA_RX_7 126 #define QUINARY_MI2S_RX 127 #define QUINARY_MI2S_TX 128 +#define DISPLAY_PORT_RX_0 DISPLAY_PORT_RX +#define DISPLAY_PORT_RX_1 129 +#define DISPLAY_PORT_RX_2 130 +#define DISPLAY_PORT_RX_3 131 +#define DISPLAY_PORT_RX_4 132 +#define DISPLAY_PORT_RX_5 133 +#define DISPLAY_PORT_RX_6 134 +#define DISPLAY_PORT_RX_7 135 #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 002042b1c73c..1f9713d7ca76 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -223,6 +223,7 @@ #define CS35L56_MBOX_CMD_AUDIO_PLAY 0x0B000001 #define CS35L56_MBOX_CMD_AUDIO_PAUSE 0x0B000002 +#define CS35L56_MBOX_CMD_AUDIO_REINIT 0x0B000003 #define CS35L56_MBOX_CMD_HIBERNATE_NOW 0x02000001 #define CS35L56_MBOX_CMD_WAKEUP 0x02000002 #define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE 0x02000003 diff --git a/include/sound/da7219-aad.h b/include/sound/da7219-aad.h index 24ee7baa2589..41320522daa2 100644 --- a/include/sound/da7219-aad.h +++ b/include/sound/da7219-aad.h @@ -44,6 +44,11 @@ enum da7219_aad_jack_ins_deb { DA7219_AAD_JACK_INS_DEB_1S, }; +enum da7219_aad_jack_ins_det_pty { + DA7219_AAD_JACK_INS_DET_PTY_LOW = 0, + DA7219_AAD_JACK_INS_DET_PTY_HIGH, +}; + enum da7219_aad_jack_det_rate { DA7219_AAD_JACK_DET_RATE_32_64MS = 0, DA7219_AAD_JACK_DET_RATE_64_128MS, @@ -80,6 +85,7 @@ struct da7219_aad_pdata { enum da7219_aad_btn_cfg btn_cfg; enum da7219_aad_mic_det_thr mic_det_thr; enum da7219_aad_jack_ins_deb jack_ins_deb; + enum da7219_aad_jack_ins_det_pty jack_ins_det_pty; enum da7219_aad_jack_det_rate jack_det_rate; enum da7219_aad_jack_rem_deb jack_rem_deb; diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index a3f3f3aa9e6e..0e46f985eeda 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -73,7 +73,6 @@ struct asoc_simple_priv { struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dais; struct snd_soc_dai_link_component *dlcs; - struct snd_soc_dai_link_component dummy; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; const struct snd_soc_ops *ops; diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 82a7db23db69..e49b97d9e3ff 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -31,6 +31,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; @@ -40,6 +41,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 0814ed143864..0b47603c9db2 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -454,6 +454,10 @@ int snd_soc_component_force_enable_pin_unlocked( struct snd_soc_component *component, const char *pin); +/* component controls */ +int snd_soc_component_notify_control(struct snd_soc_component *component, + const char * const ctl); + /* component driver ops */ int snd_soc_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream); diff --git a/include/sound/soc.h b/include/sound/soc.h index 05004c048dd5..533e553a343f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -878,6 +878,7 @@ asoc_link_to_platform(struct snd_soc_dai_link *link, int n) { #define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", } extern struct snd_soc_dai_link_component null_dailink_component[0]; +extern struct snd_soc_dai_link_component asoc_dummy_dlc; struct snd_soc_codec_conf { diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index fe3587547cfe..7cfaa908ff57 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -17,7 +17,6 @@ #include <linux/regmap.h> #include <linux/export.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/hdaudio.h> #include <sound/hda_regmap.h> diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 890c2f7c33fc..b7ca2a83fbb0 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/export.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/hda_codec.h> #include "hda_local.h" diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 848fbae26c3b..48e778c18912 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -75,6 +75,7 @@ source "sound/soc/bcm/Kconfig" source "sound/soc/cirrus/Kconfig" source "sound/soc/dwc/Kconfig" source "sound/soc/fsl/Kconfig" +source "sound/soc/google/Kconfig" source "sound/soc/hisilicon/Kconfig" source "sound/soc/jz4740/Kconfig" source "sound/soc/kirkwood/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 507eaed1d6a1..d5cc3eb710f9 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC) += bcm/ obj-$(CONFIG_SND_SOC) += cirrus/ obj-$(CONFIG_SND_SOC) += dwc/ obj-$(CONFIG_SND_SOC) += fsl/ +obj-$(CONFIG_SND_SOC) += google/ obj-$(CONFIG_SND_SOC) += hisilicon/ obj-$(CONFIG_SND_SOC) += jz4740/ obj-$(CONFIG_SND_SOC) += img/ diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index b4dcce4fbae9..6da17140beea 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -795,13 +795,6 @@ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); /* Declare ACP CPU components */ -static struct snd_soc_dai_link_component dummy_codec[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - static struct snd_soc_dai_link_component platform_component[] = { { .name = "acp_asoc_renoir.0", @@ -912,8 +905,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->hs_codec_id == RT5682) { links[i].codecs = rt5682; @@ -943,8 +936,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->hs_codec_id == NAU8825) { links[i].codecs = nau8825; @@ -973,8 +966,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->amp_codec_id == RT1019) { links[i].codecs = rt1019; @@ -1005,8 +998,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->amp_codec_id == MAX98360A) { links[i].codecs = max98360a; @@ -1076,8 +1069,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].dpcm_capture = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->hs_codec_id == RT5682) { links[i].codecs = rt5682; @@ -1110,8 +1103,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].dpcm_capture = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->hs_codec_id == NAU8825) { links[i].codecs = nau8825; @@ -1138,8 +1131,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].dpcm_playback = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->amp_codec_id == RT1019) { links[i].codecs = rt1019; @@ -1173,8 +1166,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].dpcm_playback = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } if (drv_data->amp_codec_id == MAX98360A) { links[i].codecs = max98360a; @@ -1201,8 +1194,8 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].num_codecs = ARRAY_SIZE(dmic_codec); } else { /* Use dummy codec if codec id not specified */ - links[i].codecs = dummy_codec; - links[i].num_codecs = ARRAY_SIZE(dummy_codec); + links[i].codecs = &asoc_dummy_dlc; + links[i].num_codecs = 1; } links[i].cpus = pdm_dmic; links[i].num_cpus = ARRAY_SIZE(pdm_dmic); diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index a0c84cd07fde..8154fbfd1229 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <linux/module.h> #include "amd.h" diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 447612a7a762..f220378ec20e 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -18,7 +18,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dai.h> -#include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #include "amd.h" diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h index dd36790b25ae..2f94448102d0 100644 --- a/sound/soc/amd/ps/acp63.h +++ b/sound/soc/amd/ps/acp63.h @@ -2,7 +2,7 @@ /* * AMD ALSA SoC PDM Driver * - * Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (C) 2022, 2023 Advanced Micro Devices, Inc. All rights reserved. */ #include <sound/acp63_chip_offset_byte.h> @@ -58,6 +58,9 @@ #define ACP63_PDM_DEV_MASK 1 #define ACP_DMIC_DEV 2 +/* time in ms for acp timeout */ +#define ACP_TIMEOUT 500 + enum acp_config { ACP_CONFIG_0 = 0, ACP_CONFIG_1, @@ -92,16 +95,6 @@ struct pdm_dev_data { struct snd_pcm_substream *capture_stream; }; -static inline u32 acp63_readl(void __iomem *base_addr) -{ - return readl(base_addr); -} - -static inline void acp63_writel(u32 val, void __iomem *base_addr) -{ - writel(val, base_addr); -} - struct acp63_dev_data { void __iomem *acp63_base; struct resource *res; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index afddb9a77ba4..c957718abefc 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -14,66 +14,53 @@ #include <linux/interrupt.h> #include <sound/pcm_params.h> #include <linux/pm_runtime.h> +#include <linux/iopoll.h> #include "acp63.h" static int acp63_power_on(void __iomem *acp_base) { u32 val; - int timeout; - val = acp63_readl(acp_base + ACP_PGFSM_STATUS); + val = readl(acp_base + ACP_PGFSM_STATUS); if (!val) return val; if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) - acp63_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); - timeout = 0; - while (++timeout < 500) { - val = acp63_readl(acp_base + ACP_PGFSM_STATUS); - if (!val) - return 0; - udelay(1); - } - return -ETIMEDOUT; + writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + + return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); } static int acp63_reset(void __iomem *acp_base) { u32 val; - int timeout; - - acp63_writel(1, acp_base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = acp63_readl(acp_base + ACP_SOFT_RESET); - if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) - break; - cpu_relax(); - } - acp63_writel(0, acp_base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = acp63_readl(acp_base + ACP_SOFT_RESET); - if (!val) - return 0; - cpu_relax(); - } - return -ETIMEDOUT; + int ret; + + writel(1, acp_base + ACP_SOFT_RESET); + + ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, + DELAY_US, ACP_TIMEOUT); + if (ret) + return ret; + + writel(0, acp_base + ACP_SOFT_RESET); + + return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); } static void acp63_enable_interrupts(void __iomem *acp_base) { - acp63_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); + writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); } static void acp63_disable_interrupts(void __iomem *acp_base) { - acp63_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + - ACP_EXTERNAL_INTR_STAT); - acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); - acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT); + writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); } static int acp63_init(void __iomem *acp_base, struct device *dev) @@ -85,7 +72,7 @@ static int acp63_init(void __iomem *acp_base, struct device *dev) dev_err(dev, "ACP power on failed\n"); return ret; } - acp63_writel(0x01, acp_base + ACP_CONTROL); + writel(0x01, acp_base + ACP_CONTROL); ret = acp63_reset(acp_base); if (ret) { dev_err(dev, "ACP reset failed\n"); @@ -105,7 +92,7 @@ static int acp63_deinit(void __iomem *acp_base, struct device *dev) dev_err(dev, "ACP reset failed\n"); return ret; } - acp63_writel(0, acp_base + ACP_CONTROL); + writel(0, acp_base + ACP_CONTROL); return 0; } @@ -120,11 +107,11 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) if (!adata) return IRQ_NONE; - val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT); + val = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT); if (val & BIT(PDM_DMA_STAT)) { pdev_index = adata->pdm_dev_index; ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev); - acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); + writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); if (ps_pdm_data->capture_stream) snd_pcm_period_elapsed(ps_pdm_data->capture_stream); return IRQ_HANDLED; @@ -302,7 +289,7 @@ static int snd_acp63_probe(struct pci_dev *pci, dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); goto de_init; } - val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG); + val = readl(adata->acp63_base + ACP_PIN_CONFIG); get_acp63_device_config(val, pci, adata); ret = create_acp63_platform_devs(pci, adata, addr); if (ret < 0) { diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c index 46b91327168f..3ecc6cf3fd34 100644 --- a/sound/soc/amd/ps/ps-pdm-dma.c +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -45,10 +45,10 @@ static const struct snd_pcm_hardware acp63_pdm_hardware_capture = { static void acp63_init_pdm_ring_buffer(u32 physical_addr, u32 buffer_size, u32 watermark_size, void __iomem *acp_base) { - acp63_writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR); - acp63_writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE); - acp63_writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); - acp63_writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL); + writel(physical_addr, acp_base + ACP_WOV_RX_RINGBUFADDR); + writel(buffer_size, acp_base + ACP_WOV_RX_RINGBUFSIZE); + writel(watermark_size, acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + writel(0x01, acp_base + ACPAXI2AXI_ATU_CTRL); } static void acp63_enable_pdm_clock(void __iomem *acp_base) @@ -58,11 +58,11 @@ static void acp63_enable_pdm_clock(void __iomem *acp_base) pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK; pdm_ctrl = 0x00; - acp63_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL); - pdm_ctrl = acp63_readl(acp_base + ACP_WOV_MISC_CTRL); + writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL); + pdm_ctrl = readl(acp_base + ACP_WOV_MISC_CTRL); pdm_ctrl &= ~ACP_WOV_GAIN_CONTROL; pdm_ctrl |= FIELD_PREP(ACP_WOV_GAIN_CONTROL, clamp(pdm_gain, 0, 3)); - acp63_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL); + writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL); } static void acp63_enable_pdm_interrupts(struct pdm_dev_data *adata) @@ -70,9 +70,9 @@ static void acp63_enable_pdm_interrupts(struct pdm_dev_data *adata) u32 ext_int_ctrl; mutex_lock(adata->acp_lock); - ext_int_ctrl = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl = readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); ext_int_ctrl |= PDM_DMA_INTR_MASK; - acp63_writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); mutex_unlock(adata->acp_lock); } @@ -81,9 +81,9 @@ static void acp63_disable_pdm_interrupts(struct pdm_dev_data *adata) u32 ext_int_ctrl; mutex_lock(adata->acp_lock); - ext_int_ctrl = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl = readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); ext_int_ctrl &= ~PDM_DMA_INTR_MASK; - acp63_writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL); mutex_unlock(adata->acp_lock); } @@ -93,8 +93,8 @@ static bool acp63_check_pdm_dma_status(void __iomem *acp_base) u32 pdm_enable, pdm_dma_enable; pdm_dma_status = false; - pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE); - pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_enable = readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); if ((pdm_enable & ACP_PDM_ENABLE) && (pdm_dma_enable & ACP_PDM_DMA_EN_STATUS)) pdm_dma_status = true; @@ -111,11 +111,11 @@ static int acp63_start_pdm_dma(void __iomem *acp_base) pdm_dma_enable = 0x01; acp63_enable_pdm_clock(acp_base); - acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); - acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); timeout = 0; while (++timeout < ACP_COUNTER) { - pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); if ((pdm_dma_enable & 0x02) == ACP_PDM_DMA_EN_STATUS) return 0; udelay(DELAY_US); @@ -131,14 +131,14 @@ static int acp63_stop_pdm_dma(void __iomem *acp_base) pdm_enable = 0x00; pdm_dma_enable = 0x00; - pdm_enable = acp63_readl(acp_base + ACP_WOV_PDM_ENABLE); - pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_enable = readl(acp_base + ACP_WOV_PDM_ENABLE); + pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); if (pdm_dma_enable & 0x01) { pdm_dma_enable = 0x02; - acp63_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); + writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); timeout = 0; while (++timeout < ACP_COUNTER) { - pdm_dma_enable = acp63_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); + pdm_dma_enable = readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); if ((pdm_dma_enable & 0x02) == 0x00) break; udelay(DELAY_US); @@ -148,9 +148,9 @@ static int acp63_stop_pdm_dma(void __iomem *acp_base) } if (pdm_enable == ACP_PDM_ENABLE) { pdm_enable = ACP_PDM_DISABLE; - acp63_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); + writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); } - acp63_writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH); + writel(0x01, acp_base + ACP_WOV_PDM_FIFO_FLUSH); return 0; } @@ -164,18 +164,16 @@ static void acp63_config_dma(struct pdm_stream_instance *rtd, int direction) val = PDM_PTE_OFFSET; /* Group Enable */ - acp63_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp63_base + - ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); - acp63_writel(PAGE_SIZE_4K_ENABLE, rtd->acp63_base + - ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp63_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); + writel(PAGE_SIZE_4K_ENABLE, rtd->acp63_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { /* Load the low address of page int ACP SRAM through SRBM */ low = lower_32_bits(addr); high = upper_32_bits(addr); - acp63_writel(low, rtd->acp63_base + ACP_SCRATCH_REG_0 + val); + writel(low, rtd->acp63_base + ACP_SCRATCH_REG_0 + val); high |= BIT(31); - acp63_writel(high, rtd->acp63_base + ACP_SCRATCH_REG_0 + val + 4); + writel(high, rtd->acp63_base + ACP_SCRATCH_REG_0 + val + 4); val += 8; addr += PAGE_SIZE; } @@ -242,9 +240,9 @@ static u64 acp63_pdm_get_byte_count(struct pdm_stream_instance *rtd, u32 high, low; u64 byte_count; - high = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); + high = readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); byte_count = high; - low = acp63_readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); + low = readl(rtd->acp63_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); byte_count = (byte_count << 32) | low; return byte_count; } @@ -309,9 +307,8 @@ static int acp63_pdm_dai_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - acp63_writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS); - acp63_writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + - ACP_WOV_PDM_DECIMATION_FACTOR); + writel(ch_mask, rtd->acp63_base + ACP_WOV_PDM_NO_OF_CHANNELS); + writel(PDM_DECIMATION_FACTOR, rtd->acp63_base + ACP_WOV_PDM_DECIMATION_FACTOR); rtd->bytescount = acp63_pdm_get_byte_count(rtd, substream->stream); pdm_status = acp63_check_pdm_dma_status(rtd->acp63_base); if (!pdm_status) diff --git a/sound/soc/amd/vangogh/acp5x.h b/sound/soc/amd/vangogh/acp5x.h index bd9f1c5684d1..ac1936a8c43f 100644 --- a/sound/soc/amd/vangogh/acp5x.h +++ b/sound/soc/amd/vangogh/acp5x.h @@ -147,6 +147,8 @@ static inline void acp_writel(u32 val, void __iomem *base_addr) writel(val, base_addr - ACP5x_PHY_BASE_ADDRESS); } +int snd_amd_acp_find_config(struct pci_dev *pci); + static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction) { diff --git a/sound/soc/amd/vangogh/pci-acp5x.c b/sound/soc/amd/vangogh/pci-acp5x.c index e0df17c88e8e..c4634a8a17cd 100644 --- a/sound/soc/amd/vangogh/pci-acp5x.c +++ b/sound/soc/amd/vangogh/pci-acp5x.c @@ -125,10 +125,15 @@ static int snd_acp5x_probe(struct pci_dev *pci, { struct acp5x_dev_data *adata; struct platform_device_info pdevinfo[ACP5x_DEVS]; - unsigned int irqflags; + unsigned int irqflags, flag; int ret, i; u32 addr, val; + /* Return if acp config flag is defined */ + flag = snd_amd_acp_find_config(pci); + if (flag) + return -ENODEV; + irqflags = IRQF_SHARED; if (pci->revision != 0x50) return -ENODEV; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 4406a5def076..31e466917c3d 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -314,6 +314,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MECHREVO"), + DMI_MATCH(DMI_BOARD_NAME, "MRID6"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "System76"), DMI_MATCH(DMI_PRODUCT_VERSION, "pang12"), } diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 007ab746973d..4c1985711218 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -473,21 +473,19 @@ static int atmel_classd_asoc_card_init(struct device *dev, if (!dai_link) return -ENOMEM; - comp = devm_kzalloc(dev, 2 * sizeof(*comp), GFP_KERNEL); + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (!comp) return -ENOMEM; - dai_link->cpus = &comp[0]; - dai_link->codecs = &comp[1]; + dai_link->cpus = comp; + dai_link->codecs = &asoc_dummy_dlc; dai_link->num_cpus = 1; dai_link->num_codecs = 1; dai_link->name = "CLASSD"; dai_link->stream_name = "CLASSD PCM"; - dai_link->codecs->dai_name = "snd-soc-dummy-dai"; dai_link->cpus->dai_name = dev_name(dev); - dai_link->codecs->name = "snd-soc-dummy"; card->dai_link = dai_link; card->num_links = 1; diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index 00c7b3a34ef5..efcbdd1a629f 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -496,21 +496,19 @@ static int atmel_pdmic_asoc_card_init(struct device *dev, if (!dai_link) return -ENOMEM; - comp = devm_kzalloc(dev, 2 * sizeof(*comp), GFP_KERNEL); + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (!comp) return -ENOMEM; - dai_link->cpus = &comp[0]; - dai_link->codecs = &comp[1]; + dai_link->cpus = comp; + dai_link->codecs = &asoc_dummy_dlc; dai_link->num_cpus = 1; dai_link->num_codecs = 1; dai_link->name = "PDMIC"; dai_link->stream_name = "PDMIC PCM"; - dai_link->codecs->dai_name = "snd-soc-dummy-dai"; dai_link->cpus->dai_name = dev_name(dev); - dai_link->codecs->name = "snd-soc-dummy"; card->dai_link = dai_link; card->num_links = 1; diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index baf38964b491..0405e9e49140 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -23,7 +23,6 @@ #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/i2c.h> #include <linux/of.h> #include <linux/atmel-ssc.h> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8020097d4e4c..8f487d1ba2f9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AW88395 imply SND_SOC_BT_SCO imply SND_SOC_BD28623 + imply SND_SOC_CHV3_CODEC imply SND_SOC_CQ0093VC imply SND_SOC_CROS_EC_CODEC imply SND_SOC_CS35L32 @@ -207,6 +208,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT712_SDCA_DMIC_SDW imply SND_SOC_RT715_SDW imply SND_SOC_RT715_SDCA_SDW + imply SND_SOC_RT722_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW imply SND_SOC_RT1318_SDW @@ -643,6 +645,13 @@ config SND_SOC_BD28623 config SND_SOC_BT_SCO tristate "Dummy BT SCO codec driver" +config SND_SOC_CHV3_CODEC + tristate "Google Chameleon v3 codec driver" + help + Enable support for the Google Chameleon v3 audio codec. + This codec does not have a control interface, it always outputs + 8 channel S32_LE audio. + config SND_SOC_CPCAP tristate "Motorola CPCAP codec" depends on MFD_CPCAP || COMPILE_TEST @@ -1539,6 +1548,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ +config SND_SOC_RT722_SDCA_SDW + tristate "Realtek RT722 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT715 tristate @@ -1652,6 +1667,12 @@ config SND_SOC_SSM2602_I2C select SND_SOC_SSM2602 select REGMAP_I2C +config SND_SOC_SSM3515 + tristate "Analog Devices SSM3515 amplifier driver" + select REGMAP_I2C + depends on I2C + depends on OF + config SND_SOC_SSM4567 tristate "Analog Devices ssm4567 amplifier driver support" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5cdbae88e6e3..67f336a12d74 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -51,6 +51,7 @@ snd-soc-aw88395-objs := aw88395/aw88395.o \ aw88395/aw88395_device.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o +snd-soc-chv3-codec-objs := chv3-codec.o snd-soc-cpcap-objs := cpcap.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cros-ec-codec-objs := cros_ec_codec.o @@ -237,6 +238,7 @@ snd-soc-rt712-sdca-objs := rt712-sdca.o rt712-sdca-sdw.o snd-soc-rt712-sdca-dmic-objs := rt712-sdca-dmic.o snd-soc-rt715-objs := rt715.o rt715-sdw.o snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o +snd-soc-rt722-sdca-objs := rt722-sdca.o rt722-sdca-sdw.o snd-soc-rt9120-objs := rt9120.o snd-soc-sdw-mockup-objs := sdw-mockup.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -256,6 +258,7 @@ snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-spi-objs := ssm2602-spi.o snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o +snd-soc-ssm3515-objs := ssm3515.o snd-soc-ssm4567-objs := ssm4567.o snd-soc-sta32x-objs := sta32x.o snd-soc-sta350-objs := sta350.o @@ -425,6 +428,7 @@ obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o +obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o obj-$(CONFIG_SND_SOC_CROS_EC_CODEC) += snd-soc-cros-ec-codec.o @@ -607,6 +611,7 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o +obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o @@ -623,6 +628,7 @@ obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o +obj-$(CONFIG_SND_SOC_SSM3515) += snd-soc-ssm3515.o obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c index 4cb8d87f9011..15d74bb31c4c 100644 --- a/sound/soc/codecs/ad193x-i2c.c +++ b/sound/soc/codecs/ad193x-i2c.c @@ -38,7 +38,7 @@ static struct i2c_driver ad193x_i2c_driver = { .driver = { .name = "ad193x", }, - .probe_new = ad193x_i2c_probe, + .probe = ad193x_i2c_probe, .id_table = ad193x_id, }; module_i2c_driver(ad193x_i2c_driver); diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index 8ed0ffdedbc9..132b9e2cca59 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -30,7 +30,7 @@ static struct i2c_driver adau1372_i2c_driver = { .driver = { .name = "adau1372", }, - .probe_new = adau1372_i2c_probe, + .probe = adau1372_i2c_probe, .id_table = adau1372_i2c_ids, }; module_i2c_driver(adau1372_i2c_driver); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 37e178e8a1d0..c5b087b8fffc 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1505,7 +1505,7 @@ static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", }, - .probe_new = adau1373_i2c_probe, + .probe = adau1373_i2c_probe, .id_table = adau1373_i2c_id, }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 135a7db7fcf9..8c8de3b3c901 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -876,7 +876,7 @@ static struct i2c_driver adau1701_i2c_driver = { .name = "adau1701", .of_match_table = of_match_ptr(adau1701_dt_ids), }, - .probe_new = adau1701_i2c_probe, + .probe = adau1701_i2c_probe, .id_table = adau1701_i2c_id, }; diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 0cefff49569c..a554255186ae 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver adau1761_i2c_driver = { .name = "adau1761", .of_match_table = of_match_ptr(adau1761_i2c_dt_ids), }, - .probe_new = adau1761_i2c_probe, + .probe = adau1761_i2c_probe, .remove = adau1761_i2c_remove, .id_table = adau1761_i2c_ids, }; diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 39021b8cfb62..3a170fd78ff3 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -56,7 +56,7 @@ static struct i2c_driver adau1781_i2c_driver = { .name = "adau1781", .of_match_table = of_match_ptr(adau1781_i2c_dt_ids), }, - .probe_new = adau1781_i2c_probe, + .probe = adau1781_i2c_probe, .remove = adau1781_i2c_remove, .id_table = adau1781_i2c_ids, }; diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 634d4dbca5ec..f2932713b4de 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -1059,13 +1059,12 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, if (!adau) return -ENOMEM; - adau->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(adau->mclk)) { - if (PTR_ERR(adau->mclk) != -ENOENT) - return PTR_ERR(adau->mclk); - /* Clock is optional (for the driver) */ - adau->mclk = NULL; - } else if (adau->mclk) { + /* Clock is optional (for the driver) */ + adau->mclk = devm_clk_get_optional(dev, "mclk"); + if (IS_ERR(adau->mclk)) + return PTR_ERR(adau->mclk); + + if (adau->mclk) { adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO; /* diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index 9f137a0634d5..24c7b9c84c19 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -42,7 +42,7 @@ static struct i2c_driver adau1977_i2c_driver = { .driver = { .name = "adau1977", }, - .probe_new = adau1977_i2c_probe, + .probe = adau1977_i2c_probe, .id_table = adau1977_i2c_ids, }; module_i2c_driver(adau1977_i2c_driver); diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index afed48401b25..73f181f7757e 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -78,7 +78,7 @@ static struct i2c_driver adau7118_driver = { .name = "adau7118", .of_match_table = adau7118_of_match, }, - .probe_new = adau7118_probe_i2c, + .probe = adau7118_probe_i2c, .id_table = adau7118_id, }; module_i2c_driver(adau7118_driver); diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c index bf181bbaabed..78a317947df9 100644 --- a/sound/soc/codecs/adav803.c +++ b/sound/soc/codecs/adav803.c @@ -29,7 +29,7 @@ static struct i2c_driver adav803_driver = { .driver = { .name = "adav803", }, - .probe_new = adav803_probe, + .probe = adav803_probe, .id_table = adav803_id, }; module_i2c_driver(adav803_driver); diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index b6d9a10bdccd..e34e5533765c 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -264,8 +264,6 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data) struct ak4118_priv *ak4118 = data; struct snd_soc_component *component = ak4118->component; struct snd_kcontrol_new *kctl_new; - struct snd_kcontrol *kctl; - struct snd_ctl_elem_id *id; unsigned int i; if (!component) @@ -273,13 +271,8 @@ static irqreturn_t ak4118_irq_handler(int irq, void *data) for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) { kctl_new = &ak4118_iec958_controls[i]; - kctl = snd_soc_card_get_kcontrol(component->card, - kctl_new->name); - if (!kctl) - continue; - id = &kctl->id; - snd_ctl_notify(component->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, id); + + snd_soc_component_notify_control(component, kctl_new->name); } return IRQ_HANDLED; @@ -414,7 +407,7 @@ static struct i2c_driver ak4118_i2c_driver = { .of_match_table = of_match_ptr(ak4118_of_match), }, .id_table = ak4118_id_table, - .probe_new = ak4118_i2c_probe, + .probe = ak4118_i2c_probe, }; module_i2c_driver(ak4118_i2c_driver); diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c index 573389e402f8..f287acb98646 100644 --- a/sound/soc/codecs/ak4375.c +++ b/sound/soc/codecs/ak4375.c @@ -597,7 +597,7 @@ static struct i2c_driver ak4375_i2c_driver = { .pm = &ak4375_pm, .of_match_table = ak4375_of_match, }, - .probe_new = ak4375_i2c_probe, + .probe = ak4375_i2c_probe, .remove = ak4375_i2c_remove, }; module_i2c_driver(ak4375_i2c_driver); diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 8c69c8cf9b67..77678f85ad94 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -818,7 +818,7 @@ static struct i2c_driver ak4458_i2c_driver = { .pm = &ak4458_pm, .of_match_table = ak4458_of_match, }, - .probe_new = ak4458_i2c_probe, + .probe = ak4458_i2c_probe, .remove = ak4458_i2c_remove, }; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 8c8c93eea704..904bf91090aa 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -439,7 +439,7 @@ static struct i2c_driver ak4535_i2c_driver = { .driver = { .name = "ak4535", }, - .probe_new = ak4535_i2c_probe, + .probe = ak4535_i2c_probe, .id_table = ak4535_i2c_id, }; diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index f75c19ef3551..ad56caec9dac 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -925,7 +925,7 @@ static struct i2c_driver ak4613_i2c_driver = { .name = "ak4613-codec", .of_match_table = ak4613_of_match, }, - .probe_new = ak4613_i2c_probe, + .probe = ak4613_i2c_probe, .id_table = ak4613_i2c_id, }; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 0d3ee195b3cc..5b7df2f0dd6a 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -628,7 +628,7 @@ static struct i2c_driver ak4641_i2c_driver = { .driver = { .name = "ak4641", }, - .probe_new = ak4641_i2c_probe, + .probe = ak4641_i2c_probe, .remove = ak4641_i2c_remove, .id_table = ak4641_i2c_id, }; diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 914d5b1969f8..2a8984c1fa9c 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -698,7 +698,7 @@ static struct i2c_driver ak4642_i2c_driver = { .name = "ak4642-codec", .of_match_table = ak4642_of_match, }, - .probe_new = ak4642_i2c_probe, + .probe = ak4642_i2c_probe, .id_table = ak4642_i2c_id, }; diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index cd76765f8cc0..5b849b390c2a 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -655,7 +655,7 @@ static struct i2c_driver ak4671_i2c_driver = { .driver = { .name = "ak4671-codec", }, - .probe_new = ak4671_i2c_probe, + .probe = ak4671_i2c_probe, .id_table = ak4671_i2c_id, }; diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 60abcffe6a0c..442e2cb42df4 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -497,7 +497,7 @@ static struct i2c_driver ak5558_i2c_driver = { .of_match_table = of_match_ptr(ak5558_i2c_dt_ids), .pm = &ak5558_pm, }, - .probe_new = ak5558_i2c_probe, + .probe = ak5558_i2c_probe, .remove = ak5558_i2c_remove, }; diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 9ef01b1dd294..b24c32206884 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -1083,7 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = { .name = "alc562x-codec", .of_match_table = of_match_ptr(alc5623_of_match), }, - .probe_new = alc5623_i2c_probe, + .probe = alc5623_i2c_probe, .id_table = alc5623_i2c_table, }; diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index a770704a4e17..d5021f266930 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1182,7 +1182,7 @@ static struct i2c_driver alc5632_i2c_driver = { .name = "alc5632", .of_match_table = of_match_ptr(alc5632_of_match), }, - .probe_new = alc5632_i2c_probe, + .probe = alc5632_i2c_probe, .id_table = alc5632_i2c_table, }; diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index afdce6b7fa26..9dcd75dd799a 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -570,7 +570,7 @@ static struct i2c_driver aw88395_i2c_driver = { .driver = { .name = AW88395_I2C_NAME, }, - .probe_new = aw88395_i2c_probe, + .probe = aw88395_i2c_probe, .id_table = aw88395_i2c_id, }; module_i2c_driver(aw88395_i2c_driver); diff --git a/sound/soc/codecs/chv3-codec.c b/sound/soc/codecs/chv3-codec.c new file mode 100644 index 000000000000..ab99effa6874 --- /dev/null +++ b/sound/soc/codecs/chv3-codec.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/module.h> +#include <sound/soc.h> + +static struct snd_soc_dai_driver chv3_codec_dai = { + .name = "chv3-codec-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 8, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, +}; + +static const struct snd_soc_component_driver soc_component_dev_chv3_codec = { +}; + +static int chv3_codec_probe(struct platform_device *pdev) +{ + return devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_chv3_codec, &chv3_codec_dai, 1); +} + +static const struct of_device_id chv3_codec_of_match[] = { + { .compatible = "google,chv3-codec", }, + { } +}; + +static struct platform_driver chv3_codec_platform_driver = { + .driver = { + .name = "chv3-codec", + .of_match_table = chv3_codec_of_match, + }, + .probe = chv3_codec_probe, +}; +module_platform_driver(chv3_codec_platform_driver); + +MODULE_DESCRIPTION("ASoC Chameleon v3 codec driver"); +MODULE_AUTHOR("Pawel Anikiel <pan@semihalf.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index dc7a58d68076..88828714c5d6 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -572,7 +572,7 @@ static struct i2c_driver cs35l32_i2c_driver = { .of_match_table = cs35l32_of_match, }, .id_table = cs35l32_id, - .probe_new = cs35l32_i2c_probe, + .probe = cs35l32_i2c_probe, .remove = cs35l32_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 15e79168d256..33552414e9f1 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -1282,7 +1282,7 @@ static struct i2c_driver cs35l33_i2c_driver = { }, .id_table = cs35l33_id, - .probe_new = cs35l33_i2c_probe, + .probe = cs35l33_i2c_probe, .remove = cs35l33_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index b3f98023e6a7..5ef3fc453391 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -1213,7 +1213,7 @@ static struct i2c_driver cs35l34_i2c_driver = { }, .id_table = cs35l34_id, - .probe_new = cs35l34_i2c_probe, + .probe = cs35l34_i2c_probe, .remove = cs35l34_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 947a440a3a47..2e3bb61a2bf4 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1654,7 +1654,7 @@ static struct i2c_driver cs35l35_i2c_driver = { .of_match_table = cs35l35_of_match, }, .id_table = cs35l35_id, - .probe_new = cs35l35_i2c_probe, + .probe = cs35l35_i2c_probe, .remove = cs35l35_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index a078dd422ea1..04ba7f25012e 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1944,7 +1944,7 @@ static struct i2c_driver cs35l36_i2c_driver = { .of_match_table = cs35l36_of_match, }, .id_table = cs35l36_id, - .probe_new = cs35l36_i2c_probe, + .probe = cs35l36_i2c_probe, .remove = cs35l36_i2c_remove, }; module_i2c_driver(cs35l36_i2c_driver); diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index 3676b596f60b..7ea890d7d387 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -88,7 +88,7 @@ static struct i2c_driver cs35l41_i2c_driver = { .acpi_match_table = ACPI_PTR(cs35l41_acpi_match), }, .id_table = cs35l41_id_i2c, - .probe_new = cs35l41_i2c_probe, + .probe = cs35l41_i2c_probe, .remove = cs35l41_i2c_remove, }; diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c index 562f73df7afa..77e0f8750f37 100644 --- a/sound/soc/codecs/cs35l45-i2c.c +++ b/sound/soc/codecs/cs35l45-i2c.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0 // // cs35l45-i2c.c -- CS35L45 I2C driver // @@ -65,12 +65,12 @@ static struct i2c_driver cs35l45_i2c_driver = { .pm = &cs35l45_pm_ops, }, .id_table = cs35l45_id_i2c, - .probe_new = cs35l45_i2c_probe, + .probe = cs35l45_i2c_probe, .remove = cs35l45_i2c_remove, }; module_i2c_driver(cs35l45_i2c_driver); MODULE_DESCRIPTION("I2C CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(SND_SOC_CS35L45); diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c index a00b23b4180c..5efb77530cc3 100644 --- a/sound/soc/codecs/cs35l45-spi.c +++ b/sound/soc/codecs/cs35l45-spi.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0 // // cs35l45-spi.c -- CS35L45 SPI driver // @@ -74,5 +74,5 @@ module_spi_driver(cs35l45_spi_driver); MODULE_DESCRIPTION("SPI CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(SND_SOC_CS35L45); diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c index 46610e64e818..066f83c0c7ac 100644 --- a/sound/soc/codecs/cs35l45-tables.c +++ b/sound/soc/codecs/cs35l45-tables.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0 // // cs35l45-tables.c -- CS35L45 ALSA SoC audio driver // diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c index c31597f6bfae..d1edb9876c10 100644 --- a/sound/soc/codecs/cs35l45.c +++ b/sound/soc/codecs/cs35l45.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0 // // cs35l45.c - CS35L45 ALSA SoC audio driver // @@ -1296,4 +1296,4 @@ EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45); MODULE_DESCRIPTION("ASoC CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h index 0da28439f628..61135a316df3 100644 --- a/sound/soc/codecs/cs35l45.h +++ b/sound/soc/codecs/cs35l45.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* SPDX-License-Identifier: GPL-2.0 */ /* * cs35l45.h - CS35L45 ALSA SoC audio driver * diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index d1677d76d018..3c07bd1e959e 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -825,25 +825,23 @@ static void cs35l56_system_reset(struct cs35l56_private *cs35l56) regcache_cache_only(cs35l56->regmap, false); } -static void cs35l56_dsp_work(struct work_struct *work) +static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) { - struct cs35l56_private *cs35l56 = container_of(work, - struct cs35l56_private, - dsp_work); - unsigned int reg; - unsigned int val; - int ret = 0; - - if (!cs35l56->init_done) - return; - - cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x", - cs35l56->secured ? "s" : "", cs35l56->rev); + int ret; - if (!cs35l56->dsp.part) - return; + /* Use wm_adsp to load and apply the firmware patch and coefficient files */ + ret = wm_adsp_power_up(&cs35l56->dsp); + if (ret) + dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); + else + cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT); +} - pm_runtime_get_sync(cs35l56->dev); +static void cs35l56_patch(struct cs35l56_private *cs35l56) +{ + unsigned int reg; + unsigned int val; + int ret; /* * Disable SoundWire interrupts to prevent race with IRQ work. @@ -910,9 +908,6 @@ static void cs35l56_dsp_work(struct work_struct *work) err_unlock: mutex_unlock(&cs35l56->irq_lock); err: - pm_runtime_mark_last_busy(cs35l56->dev); - pm_runtime_put_autosuspend(cs35l56->dev); - /* Re-enable SoundWire interrupts */ if (cs35l56->sdw_peripheral) { cs35l56->sdw_irq_no_unmask = false; @@ -921,6 +916,32 @@ err: } } +static void cs35l56_dsp_work(struct work_struct *work) +{ + struct cs35l56_private *cs35l56 = container_of(work, + struct cs35l56_private, + dsp_work); + + if (!cs35l56->init_done) + return; + + pm_runtime_get_sync(cs35l56->dev); + + /* + * When the device is running in secure mode the firmware files can + * only contain insecure tunings and therefore we do not need to + * shutdown the firmware to apply them and can use the lower cost + * reinit sequence instead. + */ + if (cs35l56->secured) + cs35l56_secure_patch(cs35l56); + else + cs35l56_patch(cs35l56); + + pm_runtime_mark_last_busy(cs35l56->dev); + pm_runtime_put_autosuspend(cs35l56->dev); +} + static int cs35l56_component_probe(struct snd_soc_component *component) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); @@ -1508,6 +1529,12 @@ int cs35l56_init(struct cs35l56_private *cs35l56) dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", cs35l56->secured ? "s" : "", cs35l56->rev, otpid); + /* Populate the DSP information with the revision and security state */ + cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x", + cs35l56->secured ? "s" : "", cs35l56->rev); + if (!cs35l56->dsp.part) + return -ENOMEM; + /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1, diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c index dee1a6662c2e..2d53a440a107 100644 --- a/sound/soc/codecs/cs4234.c +++ b/sound/soc/codecs/cs4234.c @@ -906,7 +906,7 @@ static struct i2c_driver cs4234_i2c_driver = { .pm = &cs4234_pm, .of_match_table = cs4234_of_match, }, - .probe_new = cs4234_i2c_probe, + .probe = cs4234_i2c_probe, .remove = cs4234_i2c_remove, }; module_i2c_driver(cs4234_i2c_driver); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 3573363b7e31..0cfc5ab36a13 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -649,7 +649,7 @@ static struct i2c_driver cs4265_i2c_driver = { .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, - .probe_new = cs4265_i2c_probe, + .probe = cs4265_i2c_probe, .remove = cs4265_i2c_remove, }; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 1b640d8232ba..ab32f15e3b44 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -751,7 +751,7 @@ static struct i2c_driver cs4270_i2c_driver = { .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, - .probe_new = cs4270_i2c_probe, + .probe = cs4270_i2c_probe, .remove = cs4270_i2c_remove, }; diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c index 4033be1c3bc1..89fe7d1665df 100644 --- a/sound/soc/codecs/cs4271-i2c.c +++ b/sound/soc/codecs/cs4271-i2c.c @@ -33,7 +33,7 @@ static struct i2c_driver cs4271_i2c_driver = { .name = "cs4271", .of_match_table = of_match_ptr(cs4271_dt_ids), }, - .probe_new = cs4271_i2c_probe, + .probe = cs4271_i2c_probe, .id_table = cs4271_i2c_id, }; module_i2c_driver(cs4271_i2c_driver); diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 67b253287daf..2552a1e6b82f 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -92,7 +92,7 @@ static struct i2c_driver cs42l42_i2c_driver = { .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), }, .id_table = cs42l42_id, - .probe_new = cs42l42_i2c_probe, + .probe = cs42l42_i2c_probe, .remove = cs42l42_i2c_remove, }; diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index e3edaa1a2761..8aa6af21e52c 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -646,12 +646,19 @@ static const struct cs42l42_pll_params pll_ratio_table[] = { { 3072000, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, { 4000000, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96, 1}, { 4096000, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94, 1}, + { 4800000, 1, 0x01, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, + { 4800000, 1, 0x01, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2}, { 5644800, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, { 6000000, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, { 6144000, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, + { 6144000, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1}, + { 9600000, 1, 0x02, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, + { 9600000, 1, 0x02, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2}, { 11289600, 0, 0, 0, 0, 0, 0, 11289600, 0, 1}, { 12000000, 0, 0, 0, 0, 0, 0, 12000000, 0, 1}, { 12288000, 0, 0, 0, 0, 0, 0, 12288000, 0, 1}, + { 19200000, 1, 0x03, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, + { 19200000, 1, 0x03, 0x50, 0x000000, 0x01, 0x10, 12288000, 82, 2}, { 22579200, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, { 24000000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, { 24576000, 1, 0x03, 0x40, 0x000000, 0x03, 0x10, 12288000, 128, 1} diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index 85238339fbca..b2106ff6a7cb 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -43,7 +43,7 @@ static struct i2c_driver cs42l51_i2c_driver = { .of_match_table = cs42l51_of_match, .pm = &cs42l51_pm_ops, }, - .probe_new = cs42l51_i2c_probe, + .probe = cs42l51_i2c_probe, .remove = cs42l51_i2c_remove, .id_table = cs42l51_i2c_id, }; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index e88d9ff95cdf..a67cd3ee84e0 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -724,12 +724,9 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, cs42l51); cs42l51->regmap = regmap; - cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); - if (IS_ERR(cs42l51->mclk_handle)) { - if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT) - return PTR_ERR(cs42l51->mclk_handle); - cs42l51->mclk_handle = NULL; - } + cs42l51->mclk_handle = devm_clk_get_optional(dev, "MCLK"); + if (IS_ERR(cs42l51->mclk_handle)) + return PTR_ERR(cs42l51->mclk_handle); for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++) cs42l51->supplies[i].supply = cs42l51_supply_names[i]; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 90bf535fc5a5..1f1ded0ff0ac 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1226,7 +1226,7 @@ static struct i2c_driver cs42l52_i2c_driver = { .of_match_table = cs42l52_of_match, }, .id_table = cs42l52_id, - .probe_new = cs42l52_i2c_probe, + .probe = cs42l52_i2c_probe, }; module_i2c_driver(cs42l52_i2c_driver); diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 3b0e715549c9..4c646e8d72aa 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1341,7 +1341,7 @@ static struct i2c_driver cs42l56_i2c_driver = { .of_match_table = cs42l56_of_match, }, .id_table = cs42l56_id, - .probe_new = cs42l56_i2c_probe, + .probe = cs42l56_i2c_probe, .remove = cs42l56_i2c_remove, }; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 0a146319755a..378a4400d234 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1384,7 +1384,7 @@ static struct i2c_driver cs42l73_i2c_driver = { .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, - .probe_new = cs42l73_i2c_probe, + .probe = cs42l73_i2c_probe, }; diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c index 37629ebd90e0..d3aa1edf60bb 100644 --- a/sound/soc/codecs/cs42l83-i2c.c +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -228,7 +228,7 @@ static struct i2c_driver cs42l83_i2c_driver = { .pm = &cs42l83_i2c_pm_ops, .of_match_table = of_match_ptr(cs42l83_of_match), }, - .probe_new = cs42l83_i2c_probe, + .probe = cs42l83_i2c_probe, .remove = cs42l83_i2c_remove, }; diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 052ffb7dcfc6..a422472820fb 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -70,7 +70,7 @@ static struct i2c_driver cs42xx8_i2c_driver = { .pm = &cs42xx8_pm, .of_match_table = cs42xx8_of_match, }, - .probe_new = cs42xx8_i2c_probe, + .probe = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, .id_table = cs42xx8_i2c_id, }; diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index db39abb2a31b..523ca54ebf64 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -2697,7 +2697,7 @@ static struct i2c_driver cs43130_i2c_driver = { .pm = &cs43130_runtime_pm, }, .id_table = cs43130_i2c_id, - .probe_new = cs43130_i2c_probe, + .probe = cs43130_i2c_probe, .remove = cs43130_i2c_remove, }; diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index ac1696034846..2ceca5d0e5bf 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -258,7 +258,7 @@ static struct i2c_driver cs4341_i2c_driver = { .name = "cs4341-i2c", .of_match_table = of_match_ptr(cs4341_dt_ids), }, - .probe_new = cs4341_i2c_probe, + .probe = cs4341_i2c_probe, .id_table = cs4341_i2c_id, }; #endif diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index ba94ffd0a7e4..8365dd0ebe2a 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -375,7 +375,7 @@ static struct i2c_driver cs4349_i2c_driver = { .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, - .probe_new = cs4349_i2c_probe, + .probe = cs4349_i2c_probe, .remove = cs4349_i2c_remove, }; diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 69db0013d243..21962b828ab1 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -990,14 +990,10 @@ static int cs53l30_i2c_probe(struct i2c_client *client) } /* Check if MCLK provided */ - cs53l30->mclk = devm_clk_get(dev, "mclk"); + cs53l30->mclk = devm_clk_get_optional(dev, "mclk"); if (IS_ERR(cs53l30->mclk)) { - if (PTR_ERR(cs53l30->mclk) != -ENOENT) { - ret = PTR_ERR(cs53l30->mclk); - goto error; - } - /* Otherwise mark the mclk pointer to NULL */ - cs53l30->mclk = NULL; + ret = PTR_ERR(cs53l30->mclk); + goto error; } /* Fetch the MUTE control */ @@ -1121,7 +1117,7 @@ static struct i2c_driver cs53l30_i2c_driver = { .pm = &cs53l30_runtime_pm, }, .id_table = cs53l30_id, - .probe_new = cs53l30_i2c_probe, + .probe = cs53l30_i2c_probe, .remove = cs53l30_i2c_remove, }; diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 5deceaa89282..082231088a26 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1706,7 +1706,7 @@ static struct i2c_driver cx2072x_i2c_driver = { .acpi_match_table = ACPI_PTR(cx2072x_acpi_match), .pm = &cx2072x_runtime_pm, }, - .probe_new = cx2072x_i2c_probe, + .probe = cx2072x_i2c_probe, .remove = cx2072x_i2c_remove, .id_table = cx2072x_i2c_id, }; diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index f838466bfebf..1e232d01809c 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1248,7 +1248,7 @@ static struct i2c_driver da7210_i2c_driver = { .driver = { .name = "da7210", }, - .probe_new = da7210_i2c_probe, + .probe = da7210_i2c_probe, .id_table = da7210_i2c_id, }; #endif diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 1c1f211a8e2e..3a6449c44b23 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -2069,7 +2069,7 @@ static struct i2c_driver da7213_i2c_driver = { .acpi_match_table = ACPI_PTR(da7213_acpi_match), .pm = &da7213_pm, }, - .probe_new = da7213_i2c_probe, + .probe = da7213_i2c_probe, .remove = da7213_i2c_remove, .id_table = da7213_i2c_id, }; diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index d9c28e701613..3f456b08b809 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3317,7 +3317,7 @@ static struct i2c_driver da7218_i2c_driver = { .name = "da7218", .of_match_table = da7218_of_match, }, - .probe_new = da7218_i2c_probe, + .probe = da7218_i2c_probe, .id_table = da7218_i2c_id, }; diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 993a0d00bc48..c65256bd526d 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -571,16 +571,29 @@ static enum da7219_aad_jack_ins_deb } } +static enum da7219_aad_jack_ins_det_pty + da7219_aad_fw_jack_ins_det_pty(struct device *dev, const char *str) +{ + if (!strcmp(str, "low")) { + return DA7219_AAD_JACK_INS_DET_PTY_LOW; + } else if (!strcmp(str, "high")) { + return DA7219_AAD_JACK_INS_DET_PTY_HIGH; + } else { + dev_warn(dev, "Invalid jack insertion detection polarity"); + return DA7219_AAD_JACK_INS_DET_PTY_LOW; + } +} + static enum da7219_aad_jack_det_rate da7219_aad_fw_jack_det_rate(struct device *dev, const char *str) { - if (!strcmp(str, "32ms_64ms")) { + if (!strcmp(str, "32_64")) { return DA7219_AAD_JACK_DET_RATE_32_64MS; - } else if (!strcmp(str, "64ms_128ms")) { + } else if (!strcmp(str, "64_128")) { return DA7219_AAD_JACK_DET_RATE_64_128MS; - } else if (!strcmp(str, "128ms_256ms")) { + } else if (!strcmp(str, "128_256")) { return DA7219_AAD_JACK_DET_RATE_128_256MS; - } else if (!strcmp(str, "256ms_512ms")) { + } else if (!strcmp(str, "256_512")) { return DA7219_AAD_JACK_DET_RATE_256_512MS; } else { dev_warn(dev, "Invalid jack detect rate"); @@ -688,6 +701,12 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev) else aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; + if (!fwnode_property_read_string(aad_np, "dlg,jack-ins-det-pty", &fw_str)) + aad_pdata->jack_ins_det_pty = + da7219_aad_fw_jack_ins_det_pty(dev, fw_str); + else + aad_pdata->jack_ins_det_pty = DA7219_AAD_JACK_INS_DET_PTY_LOW; + if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str)) aad_pdata->jack_det_rate = da7219_aad_fw_jack_det_rate(dev, fw_str); @@ -849,6 +868,21 @@ static void da7219_aad_handle_pdata(struct snd_soc_component *component) mask |= DA7219_ADC_1_BIT_REPEAT_MASK; } snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg); + + switch (aad_pdata->jack_ins_det_pty) { + case DA7219_AAD_JACK_INS_DET_PTY_LOW: + snd_soc_component_write(component, 0xF0, 0x8B); + snd_soc_component_write(component, 0x75, 0x80); + snd_soc_component_write(component, 0xF0, 0x00); + break; + case DA7219_AAD_JACK_INS_DET_PTY_HIGH: + snd_soc_component_write(component, 0xF0, 0x8B); + snd_soc_component_write(component, 0x75, 0x00); + snd_soc_component_write(component, 0xF0, 0x00); + break; + default: + break; + } } } diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 7468ee4af2ea..600c2db58756 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2714,7 +2714,7 @@ static struct i2c_driver da7219_i2c_driver = { .of_match_table = of_match_ptr(da7219_of_match), .acpi_match_table = ACPI_PTR(da7219_acpi_match), }, - .probe_new = da7219_i2c_probe, + .probe = da7219_i2c_probe, .id_table = da7219_i2c_id, }; diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2c5b0b74201c..f8ca1afa8af5 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1555,7 +1555,7 @@ static struct i2c_driver da732x_i2c_driver = { .driver = { .name = "da7320", }, - .probe_new = da732x_i2c_probe, + .probe = da732x_i2c_probe, .id_table = da732x_i2c_id, }; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 28043b4530df..ae20086777b5 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1531,7 +1531,7 @@ static struct i2c_driver da9055_i2c_driver = { .name = "da9055-codec", .of_match_table = of_match_ptr(da9055_of_match), }, - .probe_new = da9055_i2c_probe, + .probe = da9055_i2c_probe, .id_table = da9055_i2c_id, }; diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index ccecfdf70064..069f1ce1cd50 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -892,7 +892,7 @@ static struct i2c_driver es8316_i2c_driver = { .acpi_match_table = ACPI_PTR(es8316_acpi_match), .of_match_table = of_match_ptr(es8316_of_match), }, - .probe_new = es8316_i2c_probe, + .probe = es8316_i2c_probe, .id_table = es8316_i2c_id, }; module_i2c_driver(es8316_i2c_driver); diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 28a0565c2a95..7cb5b57ae655 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -896,7 +896,7 @@ static struct i2c_driver es8326_i2c_driver = { .acpi_match_table = ACPI_PTR(es8326_acpi_match), .of_match_table = of_match_ptr(es8326_of_match), }, - .probe_new = es8326_i2c_probe, + .probe = es8326_i2c_probe, .id_table = es8326_i2c_id, }; module_i2c_driver(es8326_i2c_driver); diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c index 68072e99fcc7..3c4aaa0032a0 100644 --- a/sound/soc/codecs/es8328-i2c.c +++ b/sound/soc/codecs/es8328-i2c.c @@ -40,7 +40,7 @@ static struct i2c_driver es8328_i2c_driver = { .name = "es8328", .of_match_table = es8328_of_match, }, - .probe_new = es8328_i2c_probe, + .probe = es8328_i2c_probe, .id_table = es8328_id, }; diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 50105d72b2b7..f9456133a89a 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1142,7 +1142,7 @@ static struct i2c_driver isabelle_i2c_driver = { .driver = { .name = "isabelle", }, - .probe_new = isabelle_i2c_probe, + .probe = isabelle_i2c_probe, .id_table = isabelle_i2c_id, }; diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index dba161305de8..e7542f71323d 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -137,7 +137,7 @@ static struct i2c_driver lm4857_i2c_driver = { .driver = { .name = "lm4857", }, - .probe_new = lm4857_i2c_probe, + .probe = lm4857_i2c_probe, .id_table = lm4857_i2c_id, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index a2e782cc4276..a4094689b3dd 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1451,7 +1451,7 @@ static struct i2c_driver lm49453_i2c_driver = { .driver = { .name = "lm49453", }, - .probe_new = lm49453_i2c_probe, + .probe = lm49453_i2c_probe, .id_table = lm49453_i2c_id, }; diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index d711eb1da0a8..d22b4ba51ed8 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -214,7 +214,7 @@ static struct i2c_driver max9768_i2c_driver = { .driver = { .name = "max9768", }, - .probe_new = max9768_i2c_probe, + .probe = max9768_i2c_probe, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 405ec16be2b6..fb136e2b849b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1789,7 +1789,7 @@ static struct i2c_driver max98088_i2c_driver = { .name = "max98088", .of_match_table = of_match_ptr(max98088_of_match), }, - .probe_new = max98088_i2c_probe, + .probe = max98088_i2c_probe, .id_table = max98088_i2c_id, }; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index b419c49e1e08..7bc463910d4f 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/acpi.h> @@ -2691,7 +2690,7 @@ static struct i2c_driver max98090_i2c_driver = { .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), }, - .probe_new = max98090_i2c_probe, + .probe = max98090_i2c_probe, .shutdown = max98090_i2c_shutdown, .remove = max98090_i2c_remove, .id_table = max98090_i2c_id, diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 44aa58fcc23f..7e525d49328d 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2155,7 +2155,7 @@ static struct i2c_driver max98095_i2c_driver = { .name = "max98095", .of_match_table = of_match_ptr(max98095_of_match), }, - .probe_new = max98095_i2c_probe, + .probe = max98095_i2c_probe, .id_table = max98095_i2c_id, }; diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index bac9d1bcf60a..f0e49179c38f 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -419,7 +419,7 @@ static struct i2c_driver max98371_i2c_driver = { .name = "max98371", .of_match_table = of_match_ptr(max98371_of_match), }, - .probe_new = max98371_i2c_probe, + .probe = max98371_i2c_probe, .id_table = max98371_i2c_id, }; diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index ec0905df65d1..0fa5ceca62a2 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -9,7 +9,7 @@ #include <linux/mod_devicetable.h> #include <linux/of.h> #include <linux/of_gpio.h> -#include <linux/pm_runtime.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/cdev.h> @@ -624,7 +624,7 @@ static struct i2c_driver max98373_i2c_driver = { .acpi_match_table = ACPI_PTR(max98373_acpi_match), .pm = &max98373_pm, }, - .probe_new = max98373_i2c_probe, + .probe = max98373_i2c_probe, .id_table = max98373_i2c_id, }; diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 7a5260ff8d6b..5b8e78e51630 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -1133,7 +1133,7 @@ static struct i2c_driver max98390_i2c_driver = { .acpi_match_table = ACPI_PTR(max98390_acpi_match), .pm = &max98390_pm, }, - .probe_new = max98390_i2c_probe, + .probe = max98390_i2c_probe, .id_table = max98390_i2c_id, }; diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index db3de41f10e0..3a1d8c211f3c 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1907,7 +1907,7 @@ static struct i2c_driver max98396_i2c_driver = { .acpi_match_table = ACPI_PTR(max98396_acpi_match), .pm = &max98396_pm, }, - .probe_new = max98396_i2c_probe, + .probe = max98396_i2c_probe, .id_table = max98396_i2c_id, }; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index a6733396b0ca..8b012a85360a 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -329,7 +329,7 @@ static struct i2c_driver max9850_i2c_driver = { .driver = { .name = "max9850", }, - .probe_new = max9850_i2c_probe, + .probe = max9850_i2c_probe, .id_table = max9850_i2c_id, }; diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c index 0daa2a3dd621..93412b966b33 100644 --- a/sound/soc/codecs/max98504.c +++ b/sound/soc/codecs/max98504.c @@ -371,7 +371,7 @@ static struct i2c_driver max98504_i2c_driver = { .name = "max98504", .of_match_table = of_match_ptr(max98504_of_match), }, - .probe_new = max98504_i2c_probe, + .probe = max98504_i2c_probe, .id_table = max98504_i2c_id, }; module_i2c_driver(max98504_i2c_driver); diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c index 5edd6f90f8a7..8637fff307ad 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -756,7 +756,7 @@ static struct i2c_driver max98520_i2c_driver = { .of_match_table = of_match_ptr(max98520_of_match), .pm = &max98520_pm, }, - .probe_new = max98520_i2c_probe, + .probe = max98520_i2c_probe, .id_table = max98520_i2c_id, }; diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 9611ab1e79e5..4015ed2c47ec 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -723,7 +723,7 @@ static const struct of_device_id max9860_of_match[] = { MODULE_DEVICE_TABLE(of, max9860_of_match); static struct i2c_driver max9860_i2c_driver = { - .probe_new = max9860_probe, + .probe = max9860_probe, .remove = max9860_remove, .id_table = max9860_i2c_id, .driver = { diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index ae552d72beec..b616ad39858c 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -702,7 +702,7 @@ static struct i2c_driver max9867_i2c_driver = { .name = "max9867", .of_match_table = of_match_ptr(max9867_of_match), }, - .probe_new = max9867_i2c_probe, + .probe = max9867_i2c_probe, .id_table = max9867_i2c_id, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 3bf86328d5cd..2ae64fcf29c7 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -160,7 +160,7 @@ static struct i2c_driver max9877_i2c_driver = { .driver = { .name = "max9877", }, - .probe_new = max9877_i2c_probe, + .probe = max9877_i2c_probe, .id_table = max9877_i2c_id, }; diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index c24d9f2c8874..a9c1d85cd0d5 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -635,7 +635,7 @@ static struct i2c_driver max98925_i2c_driver = { .name = "max98925", .of_match_table = of_match_ptr(max98925_of_match), }, - .probe_new = max98925_i2c_probe, + .probe = max98925_i2c_probe, .id_table = max98925_i2c_id, }; diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index bffd56e240e9..bdc508e23e59 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -582,7 +582,7 @@ static struct i2c_driver max98926_i2c_driver = { .name = "max98926", .of_match_table = of_match_ptr(max98926_of_match), }, - .probe_new = max98926_i2c_probe, + .probe = max98926_i2c_probe, .id_table = max98926_i2c_id, }; diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 331d3e1d735c..0aaf2e6ae78d 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -973,7 +973,7 @@ static struct i2c_driver max98927_i2c_driver = { .acpi_match_table = ACPI_PTR(max98927_acpi_match), .pm = &max98927_pm, }, - .probe_new = max98927_i2c_probe, + .probe = max98927_i2c_probe, .remove = max98927_i2c_remove, .id_table = max98927_i2c_id, }; diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 3c6ac77379cb..a45ef9d65703 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -581,7 +581,7 @@ static struct i2c_driver ml26124_i2c_driver = { .driver = { .name = "ml26124", }, - .probe_new = ml26124_i2c_probe, + .probe = ml26124_i2c_probe, .id_table = ml26124_i2c_id, }; diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index cb487e63615c..30690479ec17 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -18,6 +18,20 @@ #include "mt6359.h" +static void mt6359_set_gpio_smt(struct mt6359_priv *priv) +{ + /* set gpio SMT mode */ + regmap_update_bits(priv->regmap, MT6359_SMT_CON1, 0x3ff0, 0x3ff0); +} + +static void mt6359_set_gpio_driving(struct mt6359_priv *priv) +{ + /* 8:4mA(default), a:8mA, c:12mA, e:16mA */ + regmap_update_bits(priv->regmap, MT6359_DRV_CON2, 0xffff, 0x8888); + regmap_update_bits(priv->regmap, MT6359_DRV_CON3, 0xffff, 0x8888); + regmap_update_bits(priv->regmap, MT6359_DRV_CON4, 0x00ff, 0x88); +} + static void mt6359_set_playback_gpio(struct mt6359_priv *priv) { /* set gpio mosi mode, clk / data mosi */ @@ -360,8 +374,34 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = 0; int index = ucontrol->value.integer.value[0]; + int orig_gain[2], new_gain[2]; int ret; + switch (mc->reg) { + case MT6359_ZCD_CON2: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]; + orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR]; + break; + case MT6359_ZCD_CON1: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]; + orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR]; + break; + case MT6359_ZCD_CON3: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]; + break; + case MT6359_AUDENC_ANA_CON0: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1]; + break; + case MT6359_AUDENC_ANA_CON1: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2]; + break; + case MT6359_AUDENC_ANA_CON2: + orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3]; + break; + default: + return -EINVAL; + } + ret = snd_soc_put_volsw(kcontrol, ucontrol); if (ret < 0) return ret; @@ -373,6 +413,8 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol, (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK; priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]; + new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR]; break; case MT6359_ZCD_CON1: regmap_read(priv->regmap, MT6359_ZCD_CON1, ®); @@ -380,35 +422,82 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol, (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK; priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]; + new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR]; 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; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]; 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; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1]; 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; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2]; 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; + new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3]; break; } + ret = 0; + if (orig_gain[0] != new_gain[0]) { + ret = 1; + } else if (snd_soc_volsw_is_stereo(mc)) { + if (orig_gain[1] != new_gain[1]) + ret = 1; + } + 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; } +static int mt6359_get_playback_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; + + switch (mc->reg) { + case MT6359_ZCD_CON2: + ucontrol->value.integer.value[0] = + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]; + ucontrol->value.integer.value[1] = + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR]; + break; + case MT6359_ZCD_CON1: + ucontrol->value.integer.value[0] = + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL]; + ucontrol->value.integer.value[1] = + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR]; + break; + case MT6359_ZCD_CON3: + ucontrol->value.integer.value[0] = + priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL]; + break; + default: + return -EINVAL; + } + + return 0; +} + /* MUX */ /* LOL MUX */ @@ -1070,9 +1159,10 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w, { 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(), event 0x%x, mux %u\n", - __func__, event, dapm_kcontrol_get_value(w->kcontrols[0])); + __func__, event, mux); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1110,14 +1200,29 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w, /* 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); + /* Switch LOL MUX to audio DAC */ + if (mux == LO_MUX_L_DAC) { + if (priv->dev_counter[DEVICE_HP] > 0) { + dev_info(priv->dev, "%s(), can not enable DAC, hp count %d\n", + __func__, priv->dev_counter[DEVICE_HP]); + break; + } + /* Enable DACL and switch HP MUX to open*/ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x3009); + /* Disable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0xf200); + usleep_range(100, 120); + /* Switch LOL MUX to DACL */ + regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0117); + } else if (mux == LO_MUX_3RD_DAC) { + /* 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 */ @@ -1129,6 +1234,15 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w, regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x000f, 0x0000); + if (mux == LO_MUX_L_DAC) { + /* 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 AUD_CLK */ mt6359_set_decoder_clk(priv, false); @@ -2358,6 +2472,10 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = { {"MISO2_MUX", "UL2_CH1", "UL2_SRC_MUX"}, {"MISO2_MUX", "UL2_CH2", "UL2_SRC_MUX"}, + {"MISO0_MUX", NULL, "UL_SRC"}, + {"MISO1_MUX", NULL, "UL_SRC"}, + {"MISO2_MUX", NULL, "UL_SRC_34"}, + {"UL_SRC_MUX", "AMIC", "ADC_L"}, {"UL_SRC_MUX", "AMIC", "ADC_R"}, {"UL_SRC_MUX", "DMIC", "DMIC0_MUX"}, @@ -2497,6 +2615,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = { /* Lineout Path */ {"LOL Mux", "Playback", "DAC_3RD"}, + {"LOL Mux", "Playback_L_DAC", "DACL"}, {"LINEOUT L", NULL, "LOL Mux"}, /* Headphone Path */ @@ -2666,6 +2785,8 @@ static int mt6359_codec_init_reg(struct snd_soc_component *cmpnt) 0x1 << RG_AUDLOLSCDISABLE_VAUDP32_SFT); /* set gpio */ + mt6359_set_gpio_smt(priv); + mt6359_set_gpio_driving(priv); mt6359_reset_playback_gpio(priv); mt6359_reset_capture_gpio(priv); @@ -2697,22 +2818,23 @@ static void mt6359_codec_remove(struct snd_soc_component *cmpnt) cmpnt->regmap = NULL; } -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), + MT6359_ZCD_CON2, 0, 7, 0x12, 0, + mt6359_get_playback_volsw, mt6359_put_volsw, + playback_tlv), SOC_DOUBLE_EXT_TLV("Lineout Volume", MT6359_ZCD_CON1, 0, 7, 0x12, 0, - snd_soc_get_volsw, mt6359_put_volsw, playback_tlv), + mt6359_get_playback_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), + mt6359_get_playback_volsw, mt6359_put_volsw, + playback_tlv), /* ul pga gain */ SOC_SINGLE_EXT_TLV("PGA1 Volume", diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index cc2df5f7ea19..5c50c7de26cd 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -570,7 +570,7 @@ static struct i2c_driver mt6660_i2c_driver = { .of_match_table = of_match_ptr(mt6660_of_id), .pm = &mt6660_dev_pm_ops, }, - .probe_new = mt6660_i2c_probe, + .probe = mt6660_i2c_probe, .remove = mt6660_i2c_remove, .id_table = mt6660_i2c_id, }; diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index 0626d5694c22..2174a89772fc 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -890,7 +890,7 @@ static struct i2c_driver nau8540_i2c_driver = { .name = "nau8540", .of_match_table = of_match_ptr(nau8540_of_ids), }, - .probe_new = nau8540_i2c_probe, + .probe = nau8540_i2c_probe, .id_table = nau8540_i2c_ids, }; module_i2c_driver(nau8540_i2c_driver); diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index ccb512c21d74..47f000cd4d99 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -914,7 +914,7 @@ static struct i2c_driver nau8810_i2c_driver = { .name = "nau8810", .of_match_table = of_match_ptr(nau8810_of_match), }, - .probe_new = nau8810_i2c_probe, + .probe = nau8810_i2c_probe, .id_table = nau8810_i2c_id, }; diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index fee970427a24..96d75882b33a 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -1859,7 +1859,7 @@ static struct i2c_driver nau8821_driver = { .of_match_table = of_match_ptr(nau8821_of_ids), .acpi_match_table = ACPI_PTR(nau8821_acpi_match), }, - .probe_new = nau8821_i2c_probe, + .probe = nau8821_i2c_probe, .id_table = nau8821_i2c_ids, }; module_i2c_driver(nau8821_driver); diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index d5006d8de639..ff3024899f45 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -1166,7 +1166,7 @@ static struct i2c_driver nau8822_i2c_driver = { .name = "nau8822", .of_match_table = of_match_ptr(nau8822_of_match), }, - .probe_new = nau8822_i2c_probe, + .probe = nau8822_i2c_probe, .id_table = nau8822_i2c_id, }; module_i2c_driver(nau8822_i2c_driver); diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 4f19fd9b65d1..8ee47d4d750a 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -2006,7 +2006,7 @@ static struct i2c_driver nau8824_i2c_driver = { .of_match_table = of_match_ptr(nau8824_of_ids), .acpi_match_table = ACPI_PTR(nau8824_acpi_match), }, - .probe_new = nau8824_i2c_probe, + .probe = nau8824_i2c_probe, .id_table = nau8824_i2c_ids, }; module_i2c_driver(nau8824_i2c_driver); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index f4eb999761a4..cc3e18207c42 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -911,6 +911,32 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg) } } +static int nau8825_fepga_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 nau8825 *nau8825 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(nau8825->regmap, NAU8825_REG_FEPGA, + NAU8825_ACDC_CTRL_MASK, + NAU8825_ACDC_VREF_MICP | NAU8825_ACDC_VREF_MICN); + regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST, + NAU8825_DISCHRG_EN, NAU8825_DISCHRG_EN); + msleep(40); + regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST, + NAU8825_DISCHRG_EN, 0); + regmap_update_bits(nau8825->regmap, NAU8825_REG_FEPGA, + NAU8825_ACDC_CTRL_MASK, 0); + break; + default: + break; + } + + return 0; +} + static int nau8825_adc_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1127,8 +1153,8 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { SND_SOC_DAPM_INPUT("MIC"), SND_SOC_DAPM_MICBIAS("MICBIAS", NAU8825_REG_MIC_BIAS, 8, 0), - SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0, - NULL, 0), + SND_SOC_DAPM_PGA_E("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0, + NULL, 0, nau8825_fepga_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, nau8825_adc_event, SND_SOC_DAPM_POST_PMU | @@ -2944,7 +2970,7 @@ static struct i2c_driver nau8825_driver = { .of_match_table = of_match_ptr(nau8825_of_ids), .acpi_match_table = ACPI_PTR(nau8825_acpi_match), }, - .probe_new = nau8825_i2c_probe, + .probe = nau8825_i2c_probe, .remove = nau8825_i2c_remove, .id_table = nau8825_i2c_ids, }; diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 44b62bc3880f..38ce052aed50 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -442,10 +442,17 @@ /* BOOST (0x76) */ #define NAU8825_PRECHARGE_DIS (1 << 13) #define NAU8825_GLOBAL_BIAS_EN (1 << 12) +#define NAU8825_DISCHRG_EN (1 << 11) #define NAU8825_HP_BOOST_DIS (1 << 9) #define NAU8825_HP_BOOST_G_DIS (1 << 8) #define NAU8825_SHORT_SHUTDOWN_EN (1 << 6) +/* FEPGA (0x77) */ +#define NAU8825_ACDC_CTRL_SFT 14 +#define NAU8825_ACDC_CTRL_MASK (0x3 << NAU8825_ACDC_CTRL_SFT) +#define NAU8825_ACDC_VREF_MICP (0x1 << NAU8825_ACDC_CTRL_SFT) +#define NAU8825_ACDC_VREF_MICN (0x2 << NAU8825_ACDC_CTRL_SFT) + /* POWER_UP_CONTROL (0x7f) */ #define NAU8825_POWERUP_INTEGR_R (1 << 5) #define NAU8825_POWERUP_INTEGR_L (1 << 4) diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 3591f6f53901..735e1942b530 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -327,7 +327,7 @@ static struct i2c_driver pcm1681_i2c_driver = { .of_match_table = of_match_ptr(pcm1681_dt_ids), }, .id_table = pcm1681_i2c_id, - .probe_new = pcm1681_i2c_probe, + .probe = pcm1681_i2c_probe, }; module_i2c_driver(pcm1681_i2c_driver); diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c index fafe0dcbe4ea..f2d0b4d21e41 100644 --- a/sound/soc/codecs/pcm1789-i2c.c +++ b/sound/soc/codecs/pcm1789-i2c.c @@ -52,7 +52,7 @@ static struct i2c_driver pcm1789_i2c_driver = { .of_match_table = of_match_ptr(pcm1789_of_match), }, .id_table = pcm1789_i2c_ids, - .probe_new = pcm1789_i2c_probe, + .probe = pcm1789_i2c_probe, .remove = pcm1789_i2c_remove, }; diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c index e20fe3a85af8..10579681f44b 100644 --- a/sound/soc/codecs/pcm179x-i2c.c +++ b/sound/soc/codecs/pcm179x-i2c.c @@ -49,7 +49,7 @@ static struct i2c_driver pcm179x_i2c_driver = { .of_match_table = of_match_ptr(pcm179x_of_match), }, .id_table = pcm179x_i2c_ids, - .probe_new = pcm179x_i2c_probe, + .probe = pcm179x_i2c_probe, }; module_i2c_driver(pcm179x_i2c_driver); diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c index 932c8d41c3ea..a514ebd1b68a 100644 --- a/sound/soc/codecs/pcm186x-i2c.c +++ b/sound/soc/codecs/pcm186x-i2c.c @@ -46,7 +46,7 @@ static int pcm186x_i2c_probe(struct i2c_client *i2c) } static struct i2c_driver pcm186x_i2c_driver = { - .probe_new = pcm186x_i2c_probe, + .probe = pcm186x_i2c_probe, .id_table = pcm186x_i2c_id, .driver = { .name = "pcm186x", diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index dd21803ba13c..451a8fd8fac5 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <linux/slab.h> diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c index 2388098eeca3..5330cf46b127 100644 --- a/sound/soc/codecs/pcm3060-i2c.c +++ b/sound/soc/codecs/pcm3060-i2c.c @@ -49,7 +49,7 @@ static struct i2c_driver pcm3060_i2c_driver = { #endif /* CONFIG_OF */ }, .id_table = pcm3060_i2c_id, - .probe_new = pcm3060_i2c_probe, + .probe = pcm3060_i2c_probe, }; module_i2c_driver(pcm3060_i2c_driver); diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c index a0eec82e9872..7052cc0c97d1 100644 --- a/sound/soc/codecs/pcm3168a-i2c.c +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -44,7 +44,7 @@ static const struct of_device_id pcm3168a_of_match[] = { MODULE_DEVICE_TABLE(of, pcm3168a_of_match); static struct i2c_driver pcm3168a_i2c_driver = { - .probe_new = pcm3168a_i2c_probe, + .probe = pcm3168a_i2c_probe, .remove = pcm3168a_i2c_remove, .id_table = pcm3168a_i2c_id, .driver = { diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index 9dfbbe8f4a0b..5cd2b64b9337 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match); #endif static struct i2c_driver pcm512x_i2c_driver = { - .probe_new = pcm512x_i2c_probe, + .probe = pcm512x_i2c_probe, .remove = pcm512x_i2c_remove, .id_table = pcm512x_i2c_id, .driver = { diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 1d523bfd9d84..9697aefc6e03 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <sound/dmaengine_pcm.h> diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index c1568216126e..4ceb410c5024 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2483,7 +2483,7 @@ static struct i2c_driver rt1011_i2c_driver = { .of_match_table = of_match_ptr(rt1011_of_match), .acpi_match_table = ACPI_PTR(rt1011_acpi_match) }, - .probe_new = rt1011_i2c_probe, + .probe = rt1011_i2c_probe, .shutdown = rt1011_i2c_shutdown, .id_table = rt1011_i2c_id, }; diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 57d0f1c69e46..38d9f69b08d6 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1170,7 +1170,7 @@ static struct i2c_driver rt1015_i2c_driver = { .of_match_table = of_match_ptr(rt1015_of_match), .acpi_match_table = ACPI_PTR(rt1015_acpi_match), }, - .probe_new = rt1015_i2c_probe, + .probe = rt1015_i2c_probe, .shutdown = rt1015_i2c_shutdown, .id_table = rt1015_i2c_id, }; diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 37eeec650f03..b1e69fa290b2 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -683,7 +683,7 @@ static struct i2c_driver rt1016_i2c_driver = { .of_match_table = of_match_ptr(rt1016_of_match), .acpi_match_table = ACPI_PTR(rt1016_acpi_match), }, - .probe_new = rt1016_i2c_probe, + .probe = rt1016_i2c_probe, .shutdown = rt1016_i2c_shutdown, .id_table = rt1016_i2c_id, }; diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index dff2596c81eb..735feea8fd92 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -600,7 +600,7 @@ static struct i2c_driver rt1019_i2c_driver = { .of_match_table = of_match_ptr(rt1019_of_match), .acpi_match_table = ACPI_PTR(rt1019_acpi_match), }, - .probe_new = rt1019_i2c_probe, + .probe = rt1019_i2c_probe, .id_table = rt1019_i2c_id, }; module_i2c_driver(rt1019_i2c_driver); diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 5b39a440b6dc..28a4a70c3307 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -1170,7 +1170,7 @@ static struct i2c_driver rt1305_i2c_driver = { .acpi_match_table = ACPI_PTR(rt1305_acpi_match) #endif }, - .probe_new = rt1305_i2c_probe, + .probe = rt1305_i2c_probe, .shutdown = rt1305_i2c_shutdown, .id_table = rt1305_i2c_id, }; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 1797af824f60..313e97c94532 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -304,9 +304,6 @@ static int rt1308_update_status(struct sdw_slave *slave, { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt1308->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt1308->hw_init = false; @@ -314,7 +311,7 @@ static int rt1308_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt1308->hw_init || rt1308->status != SDW_SLAVE_ATTACHED) + if (rt1308->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h index 04ff18fa18e2..f816c73e247e 100644 --- a/sound/soc/codecs/rt1308-sdw.h +++ b/sound/soc/codecs/rt1308-sdw.h @@ -159,7 +159,6 @@ struct rt1308_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; struct sdw_slave *sdw_slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index d2a8e9fe3e23..04c5d5de71ff 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -862,7 +862,7 @@ static struct i2c_driver rt1308_i2c_driver = { .of_match_table = of_match_ptr(rt1308_of_match), .acpi_match_table = ACPI_PTR(rt1308_acpi_match), }, - .probe_new = rt1308_i2c_probe, + .probe = rt1308_i2c_probe, .shutdown = rt1308_i2c_shutdown, .id_table = rt1308_i2c_id, }; diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 2ee5e763e345..601b76320124 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -323,9 +323,6 @@ static int rt1316_update_status(struct sdw_slave *slave, { struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt1316->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt1316->hw_init = false; @@ -333,7 +330,7 @@ static int rt1316_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt1316->hw_init || rt1316->status != SDW_SLAVE_ATTACHED) + if (rt1316->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h index e37121655bc1..dc1bfe40edd3 100644 --- a/sound/soc/codecs/rt1316-sdw.h +++ b/sound/soc/codecs/rt1316-sdw.h @@ -42,7 +42,6 @@ struct rt1316_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; struct sdw_slave *sdw_slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 795accedc22c..3751d923611c 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -456,9 +456,6 @@ static int rt1318_update_status(struct sdw_slave *slave, { struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt1318->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt1318->hw_init = false; @@ -466,7 +463,7 @@ static int rt1318_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED) + if (rt1318->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h index 85918c184f16..86e83d63a017 100644 --- a/sound/soc/codecs/rt1318-sdw.h +++ b/sound/soc/codecs/rt1318-sdw.h @@ -88,7 +88,6 @@ struct rt1318_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; struct sdw_slave *sdw_slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 4667bf7561b1..9a33e3776b55 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1221,7 +1221,7 @@ static struct i2c_driver rt274_i2c_driver = { .of_match_table = of_match_ptr(rt274_of_match), #endif }, - .probe_new = rt274_i2c_probe, + .probe = rt274_i2c_probe, .remove = rt274_i2c_remove, .id_table = rt274_i2c_id, }; diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index ceb56647e369..981155b046fd 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1263,7 +1263,7 @@ static struct i2c_driver rt286_i2c_driver = { .name = "rt286", .acpi_match_table = ACPI_PTR(rt286_acpi_match), }, - .probe_new = rt286_i2c_probe, + .probe = rt286_i2c_probe, .remove = rt286_i2c_remove, .id_table = rt286_i2c_id, }; diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index cea26f3a02b6..8fbd25ad9b47 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1311,7 +1311,7 @@ static struct i2c_driver rt298_i2c_driver = { .name = "rt298", .acpi_match_table = ACPI_PTR(rt298_acpi_match), }, - .probe_new = rt298_i2c_probe, + .probe = rt298_i2c_probe, .remove = rt298_i2c_remove, .id_table = rt298_i2c_id, }; diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index b9bcf04d4dc9..0f9f52b93e36 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1328,7 +1328,7 @@ static struct i2c_driver rt5514_i2c_driver = { .of_match_table = of_match_ptr(rt5514_of_match), .pm = &rt5514_i2_pm_ops, }, - .probe_new = rt5514_i2c_probe, + .probe = rt5514_i2c_probe, .id_table = rt5514_i2c_id, }; module_i2c_driver(rt5514_i2c_driver); diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 948abde10463..91c967391de9 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1404,7 +1404,7 @@ static struct i2c_driver rt5616_i2c_driver = { .name = "rt5616", .of_match_table = of_match_ptr(rt5616_of_match), }, - .probe_new = rt5616_i2c_probe, + .probe = rt5616_i2c_probe, .remove = rt5616_i2c_remove, .shutdown = rt5616_i2c_shutdown, .id_table = rt5616_i2c_id, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 55c232413e2b..9a4cb45e37d4 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1728,7 +1728,7 @@ static struct i2c_driver rt5631_i2c_driver = { .name = "rt5631", .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, - .probe_new = rt5631_i2c_probe, + .probe = rt5631_i2c_probe, .remove = rt5631_i2c_remove, .id_table = rt5631_i2c_id, }; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 139257055507..c7d2f315273e 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -3079,7 +3079,7 @@ static struct i2c_driver rt5640_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5640_acpi_match), .of_match_table = of_match_ptr(rt5640_of_match), }, - .probe_new = rt5640_i2c_probe, + .probe = rt5640_i2c_probe, .id_table = rt5640_i2c_id, }; module_i2c_driver(rt5640_i2c_driver); diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 7c7cbb6362ea..01aa999fc6db 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -4184,7 +4184,7 @@ static struct i2c_driver rt5645_i2c_driver = { .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, - .probe_new = rt5645_i2c_probe, + .probe = rt5645_i2c_probe, .remove = rt5645_i2c_remove, .shutdown = rt5645_i2c_shutdown, .id_table = rt5645_i2c_id, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index df90af906563..b2ec44fa478b 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2279,7 +2279,7 @@ static struct i2c_driver rt5651_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5651_acpi_match), .of_match_table = of_match_ptr(rt5651_of_match), }, - .probe_new = rt5651_i2c_probe, + .probe = rt5651_i2c_probe, .id_table = rt5651_i2c_id, }; module_i2c_driver(rt5651_i2c_driver); diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 5e21e3c37ab5..df6f0d769bbd 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -4141,13 +4141,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c) regmap_write(rt5659->regmap, RT5659_RESET, 0); /* Check if MCLK provided */ - rt5659->mclk = devm_clk_get(&i2c->dev, "mclk"); - if (IS_ERR(rt5659->mclk)) { - if (PTR_ERR(rt5659->mclk) != -ENOENT) - return PTR_ERR(rt5659->mclk); - /* Otherwise mark the mclk pointer to NULL */ - rt5659->mclk = NULL; - } + rt5659->mclk = devm_clk_get_optional(&i2c->dev, "mclk"); + if (IS_ERR(rt5659->mclk)) + return PTR_ERR(rt5659->mclk); rt5659_calibrate(rt5659); @@ -4340,7 +4336,7 @@ static struct i2c_driver rt5659_i2c_driver = { .of_match_table = of_match_ptr(rt5659_of_match), .acpi_match_table = ACPI_PTR(rt5659_acpi_match), }, - .probe_new = rt5659_i2c_probe, + .probe = rt5659_i2c_probe, .shutdown = rt5659_i2c_shutdown, .id_table = rt5659_i2c_id, }; diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 341baa29fdb1..fd453f47455b 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1341,7 +1341,7 @@ static struct i2c_driver rt5660_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5660_acpi_match), .of_match_table = of_match_ptr(rt5660_of_match), }, - .probe_new = rt5660_i2c_probe, + .probe = rt5660_i2c_probe, .id_table = rt5660_i2c_id, }; module_i2c_driver(rt5660_i2c_driver); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index f73751dbde30..ceeadbb4f62d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3733,7 +3733,7 @@ static struct i2c_driver rt5663_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5663_acpi_match), .of_match_table = of_match_ptr(rt5663_of_match), }, - .probe_new = rt5663_i2c_probe, + .probe = rt5663_i2c_probe, .remove = rt5663_i2c_remove, .shutdown = rt5663_i2c_shutdown, .id_table = rt5663_i2c_id, diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 17afaef85c77..732e15e3a497 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4968,7 +4968,7 @@ static struct i2c_driver rt5665_i2c_driver = { .of_match_table = of_match_ptr(rt5665_of_match), .acpi_match_table = ACPI_PTR(rt5665_acpi_match), }, - .probe_new = rt5665_i2c_probe, + .probe = rt5665_i2c_probe, .shutdown = rt5665_i2c_shutdown, .id_table = rt5665_i2c_id, }; diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index ecf3b0527dbe..13fec49d4824 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2618,7 +2618,7 @@ static struct i2c_driver rt5668_i2c_driver = { .of_match_table = of_match_ptr(rt5668_of_match), .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, - .probe_new = rt5668_i2c_probe, + .probe = rt5668_i2c_probe, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a230f441559a..e8ce3e7c8e3f 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -3328,7 +3328,7 @@ static struct i2c_driver rt5670_i2c_driver = { .name = "rt5670", .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, - .probe_new = rt5670_i2c_probe, + .probe = rt5670_i2c_probe, .remove = rt5670_i2c_remove, .id_table = rt5670_i2c_id, }; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 3bf019b3f700..60e38a9bcd1b 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5704,7 +5704,7 @@ static struct i2c_driver rt5677_i2c_driver = { .of_match_table = rt5677_of_match, .acpi_match_table = ACPI_PTR(rt5677_acpi_match), }, - .probe_new = rt5677_i2c_probe, + .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, }; module_i2c_driver(rt5677_i2c_driver); diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 2935c1bb81f3..a88fcf507386 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> @@ -332,7 +331,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = rt5682_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = rt5682_i2c_probe, + .probe = rt5682_i2c_probe, .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 23f17f70d7e9..67404f45389f 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -79,7 +79,7 @@ static const struct regmap_config rt5682_sdw_indirect_regmap = { .max_register = RT5682_I2C_MODE, .volatile_reg = rt5682_volatile_register, .readable_reg = rt5682_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = rt5682_reg, .num_reg_defaults = RT5682_REG_NUM, .use_single_read = true, @@ -500,9 +500,6 @@ static int rt5682_update_status(struct sdw_slave *slave, { struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt5682->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt5682->hw_init = false; @@ -510,7 +507,7 @@ static int rt5682_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt5682->hw_init || rt5682->status != SDW_SLAVE_ATTACHED) + if (rt5682->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index d568c6993c33..301d1817f8f1 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1440,7 +1440,6 @@ struct rt5682_priv { bool disable_irq; struct mutex calibrate_mutex; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 9c34dca58f54..c77c675bd5f5 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> @@ -2848,14 +2847,9 @@ static int rt5682s_dai_probe_clks(struct snd_soc_component *component) int ret; /* Check if MCLK provided */ - rt5682s->mclk = devm_clk_get(component->dev, "mclk"); - if (IS_ERR(rt5682s->mclk)) { - if (PTR_ERR(rt5682s->mclk) != -ENOENT) { - ret = PTR_ERR(rt5682s->mclk); - return ret; - } - rt5682s->mclk = NULL; - } + rt5682s->mclk = devm_clk_get_optional(component->dev, "mclk"); + if (IS_ERR(rt5682s->mclk)) + return PTR_ERR(rt5682s->mclk); /* Register CCF DAI clock control */ ret = rt5682s_register_dai_clks(component); @@ -3046,7 +3040,7 @@ static const struct regmap_config rt5682s_regmap = { .max_register = RT5682S_MAX_REG, .volatile_reg = rt5682s_volatile_register, .readable_reg = rt5682s_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = rt5682s_reg, .num_reg_defaults = ARRAY_SIZE(rt5682s_reg), .use_single_read = true, @@ -3316,7 +3310,7 @@ static struct i2c_driver rt5682s_i2c_driver = { .acpi_match_table = rt5682s_acpi_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = rt5682s_i2c_probe, + .probe = rt5682s_i2c_probe, .remove = rt5682s_i2c_remove, .shutdown = rt5682s_i2c_shutdown, .id_table = rt5682s_i2c_id, diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 96fc5f36d0d0..ba7767bee07c 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -315,9 +315,6 @@ static int rt700_update_status(struct sdw_slave *slave, { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt700->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt700->hw_init = false; @@ -325,7 +322,7 @@ static int rt700_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt700->hw_init || rt700->status != SDW_SLAVE_ATTACHED) + if (rt700->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h index 93c44005d38c..491774d207de 100644 --- a/sound/soc/codecs/rt700.h +++ b/sound/soc/codecs/rt700.h @@ -15,7 +15,6 @@ struct rt700_priv { struct regmap *regmap; struct regmap *sdw_regmap; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 51f3335343e0..2c5eb28259dc 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -143,9 +143,6 @@ static int rt711_sdca_update_status(struct sdw_slave *slave, { struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt711->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt711->hw_init = false; @@ -168,7 +165,7 @@ static int rt711_sdca_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED) + if (rt711->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h index 22076f268577..11d421e8ab2b 100644 --- a/sound/soc/codecs/rt711-sdca.h +++ b/sound/soc/codecs/rt711-sdca.h @@ -19,7 +19,6 @@ struct rt711_sdca_priv { struct regmap *regmap, *mbq_regmap; struct snd_soc_component *component; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 4fe68bcf2a7c..b8ed3c6236d8 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -319,9 +319,6 @@ static int rt711_update_status(struct sdw_slave *slave, { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt711->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt711->hw_init = false; @@ -329,7 +326,7 @@ static int rt711_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED) + if (rt711->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h index b31351f11df9..491e357191f9 100644 --- a/sound/soc/codecs/rt711.h +++ b/sound/soc/codecs/rt711.h @@ -15,7 +15,6 @@ struct rt711_priv { struct regmap *sdw_regmap; struct snd_soc_component *component; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 09807b6d6353..847198e6c07e 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -803,9 +803,6 @@ static int rt712_sdca_dmic_update_status(struct sdw_slave *slave, { struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt712->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt712->hw_init = false; @@ -813,7 +810,7 @@ static int rt712_sdca_dmic_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt712->hw_init || rt712->status != SDW_SLAVE_ATTACHED) + if (rt712->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt712-sdca-dmic.h b/sound/soc/codecs/rt712-sdca-dmic.h index 74c29677c251..110154e74efe 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.h +++ b/sound/soc/codecs/rt712-sdca-dmic.h @@ -16,7 +16,6 @@ struct rt712_sdca_dmic_priv { struct regmap *mbq_regmap; struct snd_soc_component *component; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 3f319459dfec..8f65516e7562 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -140,9 +140,6 @@ static int rt712_sdca_update_status(struct sdw_slave *slave, { struct rt712_sdca_priv *rt712 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt712->status = status; - if (status == SDW_SLAVE_UNATTACHED) rt712->hw_init = false; @@ -165,7 +162,7 @@ static int rt712_sdca_update_status(struct sdw_slave *slave, * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt712->hw_init || rt712->status != SDW_SLAVE_ATTACHED) + if (rt712->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index c6a94a23f46e..ff79e03118ce 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -20,7 +20,6 @@ struct rt712_sdca_priv { struct regmap *mbq_regmap; struct snd_soc_component *component; struct sdw_slave *slave; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index 38a82e4e2f95..7e5ddce8097d 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -121,14 +121,11 @@ static int rt715_sdca_update_status(struct sdw_slave *slave, { struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt715->status = status; - /* * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED) + if (rt715->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h index 7577f3151934..e5d6928ecaba 100644 --- a/sound/soc/codecs/rt715-sdca.h +++ b/sound/soc/codecs/rt715-sdca.h @@ -24,7 +24,6 @@ struct rt715_sdca_priv { int dbg_nid; int dbg_vid; int dbg_payload; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 4e61e16470ed..6db87442b783 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -354,7 +354,7 @@ static const struct regmap_config rt715_regmap = { .max_register = 0x752039, /* Maximum number of register */ .reg_defaults = rt715_reg_defaults, /* Defaults */ .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, .reg_read = rt715_sdw_read, @@ -417,13 +417,11 @@ static int rt715_update_status(struct sdw_slave *slave, { struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); - /* Update the status */ - rt715->status = status; /* * Perform initialization only if slave status is present and * hw_init flag is false */ - if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED) + if (rt715->hw_init || status != SDW_SLAVE_ATTACHED) return 0; /* perform I/O transfers required for Slave initialization */ diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 17a8d041c1c3..12a0ae656d09 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -18,7 +18,6 @@ struct rt715_priv { int dbg_nid; int dbg_vid; int dbg_payload; - enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; bool first_hw_init; diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c new file mode 100644 index 000000000000..bfb2dac6bfee --- /dev/null +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt722-sdca-sdw.c -- rt722 SDCA ALSA SoC audio driver +// +// Copyright(c) 2023 Realtek Semiconductor Corp. +// +// + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/pm_runtime.h> +#include <linux/soundwire/sdw_registers.h> + +#include "rt722-sdca.h" +#include "rt722-sdca-sdw.h" + +static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01 ... 0x2f0a: + case 0x2f35 ... 0x2f36: + case 0x2f50: + case 0x2f54: + case 0x2f58 ... 0x2f5d: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_SELECTED_MODE, + 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, + 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01: + case 0x2f54: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, + 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000 ... 0x2000024: + case 0x2000029 ... 0x200004a: + case 0x2000051 ... 0x2000052: + case 0x200005a ... 0x200005b: + case 0x2000061 ... 0x2000069: + case 0x200006b: + case 0x2000070: + case 0x200007f: + case 0x2000082 ... 0x200008e: + case 0x2000090 ... 0x2000094: + case 0x5300000 ... 0x5300002: + case 0x5400002: + case 0x5600000 ... 0x5600007: + case 0x5700000 ... 0x5700004: + case 0x5800000 ... 0x5800004: + case 0x5b00003: + case 0x5c00011: + case 0x5d00006: + case 0x5f00000 ... 0x5f0000d: + case 0x5f00030: + case 0x6100000 ... 0x6100051: + case 0x6100055 ... 0x6100057: + case 0x6100062: + case 0x6100064 ... 0x6100065: + case 0x6100067: + case 0x6100070 ... 0x610007c: + case 0x6100080: + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_04): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, + RT722_SDCA_CTL_FU_CH_GAIN, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, + RT722_SDCA_CTL_FU_CH_GAIN, CH_R): + return true; + default: + return false; + } +} + +static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + case 0x200000d: + case 0x2000019: + case 0x2000020: + case 0x2000030: + case 0x2000046: + case 0x2000067: + case 0x2000084: + case 0x2000086: + return true; + default: + return false; + } +} + +static const struct regmap_config rt722_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt722_sdca_readable_register, + .volatile_reg = rt722_sdca_volatile_register, + .max_register = 0x44ffffff, + .reg_defaults = rt722_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt722_sdca_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt722_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt722_sdca_mbq_readable_register, + .volatile_reg = rt722_sdca_mbq_volatile_register, + .max_register = 0x41000312, + .reg_defaults = rt722_sdca_mbq_defaults, + .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt722_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt722->hw_init = false; + + if (status == SDW_SLAVE_ATTACHED) { + if (rt722->hs_jack) { + /* + * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then + * if the device attached again, we will need to set the setting back. + * It could avoid losing the jack detection interrupt. + * This also could sync with the cache value as the rt722_sdca_jack_init set. + */ + sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + } + } + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt722->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt722_sdca_io_init(&slave->dev, slave); +} + +static int rt722_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* + * port = 1 for headphone playback + * port = 2 for headset-mic capture + * port = 3 for speaker playback + * port = 6 for digital-mic capture + */ + prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */ + prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 200; + + /* wake-up event */ + prop->wake_capable = 1; + + return 0; +} + +static int rt722_sdca_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev); + int ret, stat; + int count = 0, retry = 3; + unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; + + if (cancel_delayed_work_sync(&rt722->jack_detect_work)) { + dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__); + /* avoid the HID owner doesn't change to device */ + if (rt722->scp_sdca_stat2) + scp_sdca_stat2 = rt722->scp_sdca_stat2; + } + + /* + * The critical section below intentionally protects a rather large piece of code. + * We don't want to allow the system suspend to disable an interrupt while we are + * processing it, which could be problematic given the quirky SoundWire interrupt + * scheme. We do want however to prevent new workqueues from being scheduled if + * the disable_irq flag was set during system suspend. + */ + mutex_lock(&rt722->disable_irq_lock); + + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + rt722->scp_sdca_stat1 = ret; + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + rt722->scp_sdca_stat2 = ret; + if (scp_sdca_stat2) + rt722->scp_sdca_stat2 |= scp_sdca_stat2; + do { + /* clear flag */ + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { + ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1, + SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); + if (ret < 0) + goto io_error; + } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) { + ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1, + SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6); + if (ret < 0) + goto io_error; + } + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { + ret = sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INT2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + if (ret < 0) + goto io_error; + } + + /* check if flag clear or not */ + ret = sdw_read_no_pm(rt722->slave, SDW_DP0_INT); + if (ret < 0) + goto io_error; + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; + + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; + + stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; + + count++; + } while (stat != 0 && count < retry); + + if (stat) + dev_warn(&slave->dev, + "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt722->scp_sdca_stat1, rt722->scp_sdca_stat2); + + if (status->sdca_cascade && !rt722->disable_irq) + mod_delayed_work(system_power_efficient_wq, + &rt722->jack_detect_work, msecs_to_jiffies(30)); + + mutex_unlock(&rt722->disable_irq_lock); + + return 0; + +io_error: + mutex_unlock(&rt722->disable_irq_lock); + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static struct sdw_slave_ops rt722_sdca_slave_ops = { + .read_prop = rt722_sdca_read_prop, + .interrupt_callback = rt722_sdca_interrupt_callback, + .update_status = rt722_sdca_update_status, +}; + +static int rt722_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap, *mbq_regmap; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt722_sdca_mbq_regmap); + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); + + regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt722_sdca_init(&slave->dev, regmap, mbq_regmap, slave); +} + +static int rt722_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt722_sdca_priv *rt722 = dev_get_drvdata(&slave->dev); + + if (rt722->hw_init) { + cancel_delayed_work_sync(&rt722->jack_detect_work); + cancel_delayed_work_sync(&rt722->jack_btn_check_work); + } + + if (rt722->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt722->calibrate_mutex); + mutex_destroy(&rt722->disable_irq_lock); + + return 0; +} + +static const struct sdw_device_id rt722_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x722, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt722_sdca_id); + +static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev) +{ + struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); + + if (!rt722->hw_init) + return 0; + + cancel_delayed_work_sync(&rt722->jack_detect_work); + cancel_delayed_work_sync(&rt722->jack_btn_check_work); + + regcache_cache_only(rt722->regmap, true); + regcache_cache_only(rt722->mbq_regmap, true); + + return 0; +} + +static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) +{ + struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret1, ret2; + + if (!rt722_sdca->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt722_sdca->disable_irq_lock); + rt722_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + mutex_unlock(&rt722_sdca->disable_irq_lock); + + if (ret1 < 0 || ret2 < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); + } + + return rt722_sdca_dev_suspend(dev); +} + +#define RT722_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt722->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT722_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt722->regmap, false); + regcache_sync(rt722->regmap); + regcache_cache_only(rt722->mbq_regmap, false); + regcache_sync(rt722->mbq_regmap); + return 0; +} + +static const struct dev_pm_ops rt722_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt722_sdca_sdw_driver = { + .driver = { + .name = "rt722-sdca", + .owner = THIS_MODULE, + .pm = &rt722_sdca_pm, + }, + .probe = rt722_sdca_sdw_probe, + .remove = rt722_sdca_sdw_remove, + .ops = &rt722_sdca_slave_ops, + .id_table = rt722_sdca_id, +}; +module_sdw_driver(rt722_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt722-sdca-sdw.h b/sound/soc/codecs/rt722-sdca-sdw.h new file mode 100644 index 000000000000..5b43e86f75d1 --- /dev/null +++ b/sound/soc/codecs/rt722-sdca-sdw.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt722-sdca-sdw.h -- RT722 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2023 Realtek Semiconductor Corp. + */ + +#ifndef __RT722_SDW_H__ +#define __RT722_SDW_H__ + +#include <linux/regmap.h> +#include <linux/soundwire/sdw_registers.h> + +static const struct reg_default rt722_sdca_reg_defaults[] = { + { 0x202d, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x00 }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0b }, + { 0x2f06, 0x01 }, + { 0x2f08, 0x00 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f35, 0x00 }, + { 0x2f36, 0x00 }, + { 0x2f50, 0xf0 }, + { 0x2f58, 0x07 }, + { 0x2f59, 0x07 }, + { 0x2f5a, 0x07 }, + { 0x2f5b, 0x07 }, + { 0x2f5c, 0x27 }, + { 0x2f5d, 0x07 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE, + 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE, + 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0), + 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0), + 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0), + 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, +}; + +static const struct reg_default rt722_sdca_mbq_defaults[] = { + { 0x200003c, 0xc214 }, + { 0x2000046, 0x8004 }, + { 0x6100006, 0x0005 }, + { 0x6100010, 0x2630 }, + { 0x6100011, 0x152f }, + { 0x6100013, 0x0102 }, + { 0x6100015, 0x2200 }, + { 0x6100017, 0x0102 }, + { 0x6100025, 0x2a29 }, + { 0x6100026, 0x2a00 }, + { 0x6100028, 0x2a2a }, + { 0x6100029, 0x4141 }, + { 0x6100055, 0x0000 }, + { 0x5810000, 0x702d }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_01), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_02), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_03), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_04), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R), + 0x0000 }, +}; + +#endif /* __RT722_SDW_H__ */ diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c new file mode 100644 index 000000000000..9c0d34366c9e --- /dev/null +++ b/sound/soc/codecs/rt722-sdca.c @@ -0,0 +1,1555 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt722-sdca.c -- rt722 SDCA ALSA SoC audio driver +// +// Copyright(c) 2023 Realtek Semiconductor Corp. +// +// + +#include <linux/bitops.h> +#include <sound/core.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <sound/initval.h> +#include <sound/jack.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <sound/pcm.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/slab.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "rt722-sdca.h" + +int rt722_sdca_index_write(struct rt722_sdca_priv *rt722, + unsigned int nid, unsigned int reg, unsigned int value) +{ + struct regmap *regmap = rt722->mbq_regmap; + unsigned int addr = (nid << 20) | reg; + int ret; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + dev_err(&rt722->slave->dev, + "Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} + +int rt722_sdca_index_read(struct rt722_sdca_priv *rt722, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + struct regmap *regmap = rt722->mbq_regmap; + unsigned int addr = (nid << 20) | reg; + + ret = regmap_read(regmap, addr, value); + if (ret < 0) + dev_err(&rt722->slave->dev, + "Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt722_sdca_index_update_bits(struct rt722_sdca_priv *rt722, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt722_sdca_index_read(rt722, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + return rt722_sdca_index_write(rt722, nid, reg, tmp); +} + +static int rt722_sdca_btn_type(unsigned char *buffer) +{ + if ((*buffer & 0xf0) == 0x10 || (*buffer & 0x0f) == 0x01 || (*(buffer + 1) == 0x01) || + (*(buffer + 1) == 0x10)) + return SND_JACK_BTN_2; + else if ((*buffer & 0xf0) == 0x20 || (*buffer & 0x0f) == 0x02 || (*(buffer + 1) == 0x02) || + (*(buffer + 1) == 0x20)) + return SND_JACK_BTN_3; + else if ((*buffer & 0xf0) == 0x40 || (*buffer & 0x0f) == 0x04 || (*(buffer + 1) == 0x04) || + (*(buffer + 1) == 0x40)) + return SND_JACK_BTN_0; + else if ((*buffer & 0xf0) == 0x80 || (*buffer & 0x0f) == 0x08 || (*(buffer + 1) == 0x08) || + (*(buffer + 1) == 0x80)) + return SND_JACK_BTN_1; + + return 0; +} + +static unsigned int rt722_sdca_button_detect(struct rt722_sdca_priv *rt722) +{ + unsigned int btn_type = 0, offset, idx, val, owner; + int ret; + unsigned char buf[3]; + + /* get current UMP message owner */ + ret = regmap_read(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner); + if (ret < 0) + return 0; + + /* if owner is device then there is no button event from device */ + if (owner == 1) + return 0; + + /* read UMP message offset */ + ret = regmap_read(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto _end_btn_det_; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt722->regmap, + RT722_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto _end_btn_det_; + buf[idx] = val & 0xff; + } + + if (buf[0] == 0x11) + btn_type = rt722_sdca_btn_type(&buf[1]); + +_end_btn_det_: + /* Host is owner, so set back to device */ + if (owner == 0) + /* set owner to device */ + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + + return btn_type; +} + +static int rt722_sdca_headset_detect(struct rt722_sdca_priv *rt722) +{ + unsigned int det_mode; + int ret; + + /* get detected_mode */ + ret = regmap_read(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, + RT722_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + if (ret < 0) + goto io_error; + + switch (det_mode) { + case 0x00: + rt722->jack_type = 0; + break; + case 0x03: + rt722->jack_type = SND_JACK_HEADPHONE; + break; + case 0x05: + rt722->jack_type = SND_JACK_HEADSET; + break; + } + + /* write selected_mode */ + if (det_mode) { + ret = regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, + RT722_SDCA_CTL_SELECTED_MODE, 0), det_mode); + if (ret < 0) + goto io_error; + } + + dev_dbg(&rt722->slave->dev, + "%s, detected_mode=0x%x\n", __func__, det_mode); + + return 0; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static void rt722_sdca_jack_detect_handler(struct work_struct *work) +{ + struct rt722_sdca_priv *rt722 = + container_of(work, struct rt722_sdca_priv, jack_detect_work.work); + int btn_type = 0, ret; + + if (!rt722->hs_jack) + return; + + if (!rt722->component->card || !rt722->component->card->instantiated) + return; + + /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ + if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 || + rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + ret = rt722_sdca_headset_detect(rt722); + if (ret < 0) + return; + } + + /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */ + if (rt722->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8) + btn_type = rt722_sdca_button_detect(rt722); + + if (rt722->jack_type == 0) + btn_type = 0; + + dev_dbg(&rt722->slave->dev, + "in %s, jack_type=%d\n", __func__, rt722->jack_type); + dev_dbg(&rt722->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + dev_dbg(&rt722->slave->dev, + "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt722->scp_sdca_stat1, rt722->scp_sdca_stat2); + + snd_soc_jack_report(rt722->hs_jack, rt722->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt722->hs_jack, rt722->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt722->jack_btn_check_work, msecs_to_jiffies(200)); + } +} + +static void rt722_sdca_btn_check_handler(struct work_struct *work) +{ + struct rt722_sdca_priv *rt722 = + container_of(work, struct rt722_sdca_priv, jack_btn_check_work.work); + int btn_type = 0, ret, idx; + unsigned int det_mode, offset, val; + unsigned char buf[3]; + + ret = regmap_read(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, + RT722_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (det_mode) { + /* read UMP message offset */ + ret = regmap_read(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto io_error; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt722->regmap, + RT722_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto io_error; + buf[idx] = val & 0xff; + } + + if (buf[0] == 0x11) + btn_type = rt722_sdca_btn_type(&buf[1]); + } else + rt722->jack_type = 0; + + dev_dbg(&rt722->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt722->hs_jack, rt722->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt722->hs_jack, rt722->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt722->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) +{ + mutex_lock(&rt722->calibrate_mutex); + if (rt722->hs_jack) { + /* set SCP_SDCA_IntMask1[0]=1 */ + sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + /* set SCP_SDCA_IntMask2[0]=1 */ + sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + dev_dbg(&rt722->slave->dev, "in %s enable\n", __func__); + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_HDA_LEGACY_UNSOL_CTL, 0x016E); + /* set XU(et03h) & XU(et0Dh) to Not bypassed */ + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, + RT722_SDCA_CTL_SELECTED_MODE, 0), 0); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, + RT722_SDCA_CTL_SELECTED_MODE, 0), 0); + /* trigger GE interrupt */ + rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, + RT722_GE_RELATED_CTL2, 0x4000, 0x4000); + } + mutex_unlock(&rt722->calibrate_mutex); +} + +static int rt722_sdca_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + int ret; + + rt722->hs_jack = hs_jack; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); + return 0; + } + + rt722_sdca_jack_init(rt722); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + + return 0; +} + +/* For SDCA control DAC/ADC Gain */ +static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int adc_vol_flag = 0, changed = 0; + unsigned int lvalue, rvalue; + const unsigned int interval_offset = 0xc0; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt722->mbq_regmap, mc->reg, &lvalue); + regmap_read(rt722->mbq_regmap, mc->rreg, &rvalue); + + /* L Channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + + if (mc->shift == 8) /* boost gain */ + gain_l_val = gain_l_val * tendB; + else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset); + else + gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset); + gain_l_val &= 0xffff; + } + + /* R Channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + + if (mc->shift == 8) /* boost gain */ + gain_r_val = gain_r_val * tendB; + else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset); + else + gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset); + gain_r_val &= 0xffff; + } + + if (lvalue != gain_l_val || rvalue != gain_r_val) + changed = 1; + else + return 0; + + /* Lch*/ + regmap_write(rt722->mbq_regmap, mc->reg, gain_l_val); + + /* Rch */ + regmap_write(rt722->mbq_regmap, mc->rreg, gain_r_val); + + regmap_read(rt722->mbq_regmap, mc->reg, &read_l); + regmap_read(rt722->mbq_regmap, mc->rreg, &read_r); + if (read_r == gain_r_val && read_l == gain_l_val) + return changed; + + return -EIO; +} + +static int rt722_sdca_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt722->mbq_regmap, mc->reg, &read_l); + regmap_read(rt722->mbq_regmap, mc->rreg, &read_r); + + if (mc->shift == 8) /* boost gain */ + ctl_l = read_l / tendB; + else { + if (adc_vol_flag) + ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset); + else + ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset); + } + + if (read_l != read_r) { + if (mc->shift == 8) /* boost gain */ + ctl_r = read_r / tendB; + else { /* ADC/DAC gain */ + if (adc_vol_flag) + ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset); + else + ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset); + } + } else { + ctl_r = ctl_l; + } + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + + return 0; +} + +static int rt722_sdca_set_fu1e_capture_ctl(struct rt722_sdca_priv *rt722) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt722->fu1e_mixer_mute); i++) { + ch_mute = rt722->fu1e_dapm_mute || rt722->fu1e_mixer_mute[i]; + err = regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt722_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct rt722_sdca_dmic_kctrl_priv *p = + (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt722->fu1e_mixer_mute[i]; + + return 0; +} + +static int rt722_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct rt722_sdca_dmic_kctrl_priv *p = + (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt722->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt722->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt722_sdca_set_fu1e_capture_ctl(rt722); + if (err < 0) + return err; + + return changed; +} + +static int rt722_sdca_set_fu0f_capture_ctl(struct rt722_sdca_priv *rt722) +{ + int err; + unsigned int ch_l, ch_r; + + ch_l = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_r = (rt722->fu0f_dapm_mute || rt722->fu0f_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_L), ch_l); + if (err < 0) + return err; + + err = regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_R), ch_r); + if (err < 0) + return err; + + return 0; +} + +static int rt722_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt722->fu0f_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt722->fu0f_mixer_r_mute; + return 0; +} + +static int rt722_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + int err, changed = 0; + + if (rt722->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] || + rt722->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1]) + changed = 1; + + rt722->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt722->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt722_sdca_set_fu0f_capture_ctl(rt722); + if (err < 0) + return err; + + return changed; +} + +static int rt722_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt722_sdca_dmic_kctrl_priv *p = + (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct rt722_sdca_dmic_kctrl_priv *p = + (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int regvalue, ctl, i; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value); + + if (!adc_vol_flag) /* boost gain */ + ctl = regvalue / boost_step; + else { /* ADC gain */ + if (adc_vol_flag) + ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); + else + ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset); + } + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt722_sdca_dmic_kctrl_priv *p = + (struct rt722_sdca_dmic_kctrl_priv *)kcontrol->private_value; + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int gain_val[4]; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int regvalue[4]; + const unsigned int interval_offset = 0xc0; + int err; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + if (!adc_vol_flag) /* boost gain */ + gain_val[i] = gain_val[i] * boost_step; + else { /* ADC gain */ + gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + } + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt722->mbq_regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt722->slave->dev, "%#08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +#define RT722_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \ + ((unsigned long)&(struct rt722_sdca_dmic_kctrl_priv) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .invert = xinvert}) + +#define RT722_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = rt722_sdca_fu_info, \ + .get = rt722_sdca_fu1e_capture_get, \ + .put = rt722_sdca_fu1e_capture_put, \ + .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)} + +#define RT722_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, xcount, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt722_sdca_fu_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT722_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) } + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt722_sdca_controls[] = { + /* Headphone playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv), + /* Headset mic capture settings */ + SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt722_sdca_fu0f_capture_get, rt722_sdca_fu0f_capture_put), + SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0, + rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, + RT722_SDCA_CTL_FU_CH_GAIN, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, + RT722_SDCA_CTL_FU_CH_GAIN, CH_R), 8, 3, 0, + rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, boost_vol_tlv), + /* AMP playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt722_sdca_set_gain_get, rt722_sdca_set_gain_put, out_vol_tlv), + /* DMIC capture settings */ + RT722_SDCA_FU_CTRL("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4), + RT722_SDCA_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_VOLUME, CH_01), + rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put, + 4, 0x3f, mic_vol_tlv), + RT722_SDCA_EXT_TLV("FU15 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, + RT722_SDCA_CTL_FU_CH_GAIN, CH_01), + rt722_sdca_dmic_set_gain_get, rt722_sdca_dmic_set_gain_put, + 4, 3, boost_vol_tlv), +}; + +static int rt722_sdca_adc_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL, + RT722_HDA_LEGACY_MUX_CTL0, &val); + + ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7; + + return 0; +} + +static int rt722_sdca_adc_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL, + RT722_HDA_LEGACY_MUX_CTL0, &val2); + val2 = (0x7 << mask_sft) & val2; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) + rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, + RT722_HDA_LEGACY_MUX_CTL0, 0x7 << mask_sft, + val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc22_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", +}; + +static const char * const adc07_10_mux_text[] = { + "DMIC1", + "DMIC2", +}; + +static SOC_ENUM_SINGLE_DECL( + rt722_adc22_enum, SND_SOC_NOPM, 0, adc22_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt722_adc24_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt722_adc25_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); + +static const struct snd_kcontrol_new rt722_sdca_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt722_adc22_enum, + rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + +static const struct snd_kcontrol_new rt722_sdca_adc24_mux = + SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt722_adc24_enum, + rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + +static const struct snd_kcontrol_new rt722_sdca_adc25_mux = + SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt722_adc25_enum, + rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + +static int rt722_sdca_fu42_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt722_sdca_fu21_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt722_sdca_fu113_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt722->fu1e_dapm_mute = false; + rt722_sdca_set_fu1e_capture_ctl(rt722); + break; + case SND_SOC_DAPM_PRE_PMD: + rt722->fu1e_dapm_mute = true; + rt722_sdca_set_fu1e_capture_ctl(rt722); + break; + } + return 0; +} + +static int rt722_sdca_fu36_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt722->fu0f_dapm_mute = false; + rt722_sdca_set_fu0f_capture_ctl(rt722); + break; + case SND_SOC_DAPM_PRE_PMD: + rt722->fu0f_dapm_mute = true; + rt722_sdca_set_fu0f_capture_ctl(rt722); + break; + } + return 0; +} + +static int rt722_sdca_pde47_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt722_sdca_pde23_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt722_sdca_pde11_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt722_sdca_pde12_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 rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, + RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt722_sdca_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + SND_SOC_DAPM_INPUT("DMIC1_2"), + SND_SOC_DAPM_INPUT("DMIC3_4"), + + SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, + rt722_sdca_pde23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0, + rt722_sdca_pde47_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt722_sdca_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 12", SND_SOC_NOPM, 0, 0, + rt722_sdca_pde12_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0, + rt722_sdca_fu21_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0, + rt722_sdca_fu42_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0, + rt722_sdca_fu36_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0, + rt722_sdca_fu113_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt722_sdca_adc22_mux), + SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0, + &rt722_sdca_adc24_mux), + SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0, + &rt722_sdca_adc25_mux), + + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt722_sdca_audio_map[] = { + {"FU 42", NULL, "DP1RX"}, + {"FU 21", NULL, "DP3RX"}, + + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 24 Mux", "DMIC1", "DMIC1_2"}, + {"ADC 24 Mux", "DMIC2", "DMIC3_4"}, + {"ADC 25 Mux", "DMIC1", "DMIC1_2"}, + {"ADC 25 Mux", "DMIC2", "DMIC3_4"}, + {"FU 36", NULL, "PDE 12"}, + {"FU 36", NULL, "ADC 22 Mux"}, + {"FU 113", NULL, "PDE 11"}, + {"FU 113", NULL, "ADC 24 Mux"}, + {"FU 113", NULL, "ADC 25 Mux"}, + {"DP2TX", NULL, "FU 36"}, + {"DP6TX", NULL, "FU 113"}, + + {"HP", NULL, "PDE 47"}, + {"HP", NULL, "FU 42"}, + {"SPK", NULL, "PDE 23"}, + {"SPK", NULL, "FU 21"}, +}; + +static int rt722_sdca_parse_dt(struct rt722_sdca_priv *rt722, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", &rt722->jd_src); + + return 0; +} + +static int rt722_sdca_probe(struct snd_soc_component *component) +{ + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + int ret; + + rt722_sdca_parse_dt(rt722, &rt722->slave->dev); + rt722->component = component; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver soc_sdca_dev_rt722 = { + .probe = rt722_sdca_probe, + .controls = rt722_sdca_controls, + .num_controls = ARRAY_SIZE(rt722_sdca_controls), + .dapm_widgets = rt722_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt722_sdca_dapm_widgets), + .dapm_routes = rt722_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt722_sdca_audio_map), + .set_jack = rt722_sdca_set_jack_detect, + .endianness = 1, +}; + +static int rt722_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt722_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + int retval, port, num_channels; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt722->slave) + return -EINVAL; + + /* + * RT722_AIF1 with port = 1 for headphone playback + * RT722_AIF1 with port = 2 for headset-mic capture + * RT722_AIF2 with port = 3 for speaker playback + * RT722_AIF3 with port = 6 for digital-mic capture + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + if (dai->id == RT722_AIF1) + port = 1; + else if (dai->id == RT722_AIF2) + port = 3; + else + return -EINVAL; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT722_AIF1) + port = 2; + else if (dai->id == RT722_AIF3) + port = 6; + else + return -EINVAL; + } + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt722->slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) > 16) { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT722_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT722_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT722_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT722_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + if (dai->id == RT722_AIF1) { + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + } + + if (dai->id == RT722_AIF2) + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + if (dai->id == RT722_AIF3) + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + return 0; +} + +static int rt722_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt722->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt722->slave, sdw_stream); + return 0; +} + +#define RT722_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT722_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops rt722_sdca_ops = { + .hw_params = rt722_sdca_pcm_hw_params, + .hw_free = rt722_sdca_pcm_hw_free, + .set_stream = rt722_sdca_set_sdw_stream, + .shutdown = rt722_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt722_sdca_dai[] = { + { + .name = "rt722-sdca-aif1", + .id = RT722_AIF1, + .playback = { + .stream_name = "DP1 Headphone Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT722_STEREO_RATES, + .formats = RT722_FORMATS, + }, + .capture = { + .stream_name = "DP2 Headset Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT722_STEREO_RATES, + .formats = RT722_FORMATS, + }, + .ops = &rt722_sdca_ops, + }, + { + .name = "rt722-sdca-aif2", + .id = RT722_AIF2, + .playback = { + .stream_name = "DP3 Speaker Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT722_STEREO_RATES, + .formats = RT722_FORMATS, + }, + .ops = &rt722_sdca_ops, + }, + { + .name = "rt722-sdca-aif3", + .id = RT722_AIF3, + .capture = { + .stream_name = "DP6 DMic Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT722_STEREO_RATES, + .formats = RT722_FORMATS, + }, + .ops = &rt722_sdca_ops, + } +}; + +int rt722_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave) +{ + struct rt722_sdca_priv *rt722; + + rt722 = devm_kzalloc(dev, sizeof(*rt722), GFP_KERNEL); + if (!rt722) + return -ENOMEM; + + dev_set_drvdata(dev, rt722); + rt722->slave = slave; + rt722->regmap = regmap; + rt722->mbq_regmap = mbq_regmap; + + mutex_init(&rt722->calibrate_mutex); + mutex_init(&rt722->disable_irq_lock); + + INIT_DELAYED_WORK(&rt722->jack_detect_work, rt722_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt722->jack_btn_check_work, rt722_sdca_btn_check_handler); + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt722->hw_init = false; + rt722->first_hw_init = false; + rt722->fu1e_dapm_mute = true; + rt722->fu0f_dapm_mute = true; + rt722->fu0f_mixer_l_mute = rt722->fu0f_mixer_r_mute = true; + rt722->fu1e_mixer_mute[0] = rt722->fu1e_mixer_mute[1] = + rt722->fu1e_mixer_mute[2] = rt722->fu1e_mixer_mute[3] = true; + + return devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt722, rt722_sdca_dai, ARRAY_SIZE(rt722_sdca_dai)); +} + +static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722) +{ + /* Set AD07 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_ADC0A_08_PDE_FLOAT_CTL, 0x2a29); + /* Set AD10 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_ADC10_PDE_FLOAT_CTL, 0x2a00); + /* Set DMIC1/DMIC2 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_DMIC1_2_PDE_FLOAT_CTL, 0x2a2a); + /* Set DMIC2 IT entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_DMIC_ENT_FLOAT_CTL, 0x2626); + /* Set AD10 FU entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_ADC_ENT_FLOAT_CTL, 0x1e00); + /* Set DMIC2 FU entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_DMIC_GAIN_ENT_FLOAT_CTL0, 0x1515); + /* Set AD10 FU channel floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_ADC_VOL_CH_FLOAT_CTL, 0x0304); + /* Set DMIC2 FU channel floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_DMIC_GAIN_ENT_FLOAT_CTL2, 0x0304); + /* vf71f_r12_07_06 and vf71f_r13_07_06 = 2’b00 */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, + RT722_HDA_LEGACY_CONFIG_CTL0, 0x0000); + /* Enable vf707_r12_05/vf707_r13_05 */ + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, + RT722_SDCA_CTL_VENDOR_DEF, 0), 0x01); + /* Fine tune PDE2A latency */ + regmap_write(rt722->regmap, 0x2f5c, 0x25); +} + +static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722) +{ + /* Set DVQ=01 */ + rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6, + 0xc215); + /* Reset dc_cal_top */ + rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL, + 0x702c); + /* W1C Trigger Calibration */ + rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL, + 0xf02d); + /* Set DAC02/ClassD power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_AMP_PDE_FLOAT_CTL, + 0x2323); + /* Set EAPD high */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_EAPD_CTL, + 0x0002); + /* Enable vf707_r14 */ + regmap_write(rt722->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, + RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04); +} + +static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) +{ + int loop_check, chk_cnt = 100, ret; + unsigned int calib_status = 0; + + /* Read eFuse */ + rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL, + 0x4808); + /* Button A, B, C, D bypass mode */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4, + 0xcf00); + /* HID1 slot enable */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL5, + 0x000f); + /* Report ID for HID1 */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL0, + 0x1100); + /* OSC/OOC for slot 2, 3 */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL7, + 0x0c12); + /* Set JD de-bounce clock control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_JD_CTRL1, + 0x7002); + /* Set DVQ=01 */ + rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6, + 0xc215); + /* FSM switch to calibration manual mode */ + rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_FSM_CTL, + 0x4100); + /* W1C Trigger DC calibration (HP) */ + rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DAC_DC_CALI_CTL3, + 0x008d); + /* check HP calibration FSM status */ + for (loop_check = 0; loop_check < chk_cnt; loop_check++) { + ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI, + RT722_DAC_DC_CALI_CTL3, &calib_status); + if (ret < 0 || loop_check == chk_cnt) + dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret); + if ((calib_status & 0x0040) == 0x0) + break; + } + /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */ + rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4, + 0x0010); + /* Set ADC09 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL, + 0x2a12); + /* Set MIC2 and LINE1 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_MIC2_LINE2_PDE_FLOAT_CTL, + 0x3429); + /* Set ET41h and LINE2 power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ET41_LINE2_PDE_FLOAT_CTL, + 0x4112); + /* Set DAC03 and HP power entity floating control */ + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL, + 0x4040); + /* Fine tune PDE40 latency */ + regmap_write(rt722->regmap, 0x2f58, 0x07); +} + +int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); + + rt722->disable_irq = false; + + if (rt722->hw_init) + return 0; + + if (rt722->first_hw_init) { + regcache_cache_only(rt722->regmap, false); + regcache_cache_bypass(rt722->regmap, true); + regcache_cache_only(rt722->mbq_regmap, false); + regcache_cache_bypass(rt722->mbq_regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + rt722_sdca_dmic_preset(rt722); + rt722_sdca_amp_preset(rt722); + rt722_sdca_jack_preset(rt722); + + if (rt722->first_hw_init) { + regcache_cache_bypass(rt722->regmap, false); + regcache_mark_dirty(rt722->regmap); + regcache_cache_bypass(rt722->mbq_regmap, false); + regcache_mark_dirty(rt722->mbq_regmap); + } else + rt722->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt722->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +MODULE_DESCRIPTION("ASoC RT722 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h new file mode 100644 index 000000000000..44af8901352e --- /dev/null +++ b/sound/soc/codecs/rt722-sdca.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt722-sdca.h -- RT722 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2023 Realtek Semiconductor Corp. + */ + +#ifndef __RT722_H__ +#define __RT722_H__ + +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/soc.h> +#include <linux/workqueue.h> + +struct rt722_sdca_priv { + struct regmap *regmap; + struct regmap *mbq_regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; + struct mutex calibrate_mutex; + struct mutex disable_irq_lock; + bool disable_irq; + /* For Headset jack & Headphone */ + unsigned int scp_sdca_stat1; + unsigned int scp_sdca_stat2; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + int jack_type; + int jd_src; + bool fu0f_dapm_mute; + bool fu0f_mixer_l_mute; + bool fu0f_mixer_r_mute; + /* For DMIC */ + bool fu1e_dapm_mute; + bool fu1e_mixer_mute[4]; +}; + +struct rt722_sdca_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +/* NID */ +#define RT722_VENDOR_REG 0x20 +#define RT722_VENDOR_CALI 0x58 +#define RT722_VENDOR_SPK_EFUSE 0x5c +#define RT722_VENDOR_IMS_DRE 0x5b +#define RT722_VENDOR_ANALOG_CTL 0x5f +#define RT722_VENDOR_HDA_CTL 0x61 + +/* Index (NID:20h) */ +#define RT722_JD_PRODUCT_NUM 0x00 +#define RT722_ANALOG_BIAS_CTL3 0x04 +#define RT722_JD_CTRL1 0x09 +#define RT722_LDO2_3_CTL1 0x0e +#define RT722_LDO1_CTL 0x1a +#define RT722_HP_JD_CTRL 0x24 +#define RT722_CLSD_CTRL6 0x3c +#define RT722_COMBO_JACK_AUTO_CTL1 0x45 +#define RT722_COMBO_JACK_AUTO_CTL2 0x46 +#define RT722_COMBO_JACK_AUTO_CTL3 0x47 +#define RT722_DIGITAL_MISC_CTRL4 0x4a +#define RT722_FSM_CTL 0x67 +#define RT722_SDCA_INTR_REC 0x82 +#define RT722_SW_CONFIG1 0x8a +#define RT722_SW_CONFIG2 0x8b + +/* Index (NID:58h) */ +#define RT722_DAC_DC_CALI_CTL0 0x00 +#define RT722_DAC_DC_CALI_CTL1 0x01 +#define RT722_DAC_DC_CALI_CTL2 0x02 +#define RT722_DAC_DC_CALI_CTL3 0x03 + +/* Index (NID:59h) */ +#define RT722_ULTRA_SOUND_DETECTOR6 0x1e + +/* Index (NID:5bh) */ +#define RT722_IMS_DIGITAL_CTL1 0x00 +#define RT722_IMS_DIGITAL_CTL5 0x05 +#define RT722_HP_DETECT_RLDET_CTL1 0x29 +#define RT722_HP_DETECT_RLDET_CTL2 0x2a + +/* Index (NID:5fh) */ +#define RT722_MISC_POWER_CTL0 0x00 +#define RT722_MISC_POWER_CTL7 0x08 + +/* Index (NID:61h) */ +#define RT722_HDA_LEGACY_MUX_CTL0 0x00 +#define RT722_HDA_LEGACY_UNSOL_CTL 0x03 +#define RT722_HDA_LEGACY_CONFIG_CTL0 0x06 +#define RT722_HDA_LEGACY_RESET_CTL 0x08 +#define RT722_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e +#define RT722_DMIC_ENT_FLOAT_CTL 0x10 +#define RT722_DMIC_GAIN_ENT_FLOAT_CTL0 0x11 +#define RT722_DMIC_GAIN_ENT_FLOAT_CTL2 0x13 +#define RT722_ADC_ENT_FLOAT_CTL 0x15 +#define RT722_ADC_VOL_CH_FLOAT_CTL 0x17 +#define RT722_ADC_SAMPLE_RATE_FLOAT 0x18 +#define RT722_DAC03_HP_PDE_FLOAT_CTL 0x22 +#define RT722_MIC2_LINE2_PDE_FLOAT_CTL 0x23 +#define RT722_ET41_LINE2_PDE_FLOAT_CTL 0x24 +#define RT722_ADC0A_08_PDE_FLOAT_CTL 0x25 +#define RT722_ADC10_PDE_FLOAT_CTL 0x26 +#define RT722_DMIC1_2_PDE_FLOAT_CTL 0x28 +#define RT722_AMP_PDE_FLOAT_CTL 0x29 +#define RT722_I2S_IN_OUT_PDE_FLOAT_CTL 0x2f +#define RT722_GE_RELATED_CTL1 0x45 +#define RT722_GE_RELATED_CTL2 0x46 +#define RT722_MIXER_CTL0 0x52 +#define RT722_MIXER_CTL1 0x53 +#define RT722_EAPD_CTL 0x55 +#define RT722_UMP_HID_CTL0 0x60 +#define RT722_UMP_HID_CTL1 0x61 +#define RT722_UMP_HID_CTL2 0x62 +#define RT722_UMP_HID_CTL3 0x63 +#define RT722_UMP_HID_CTL4 0x64 +#define RT722_UMP_HID_CTL5 0x65 +#define RT722_UMP_HID_CTL6 0x66 +#define RT722_UMP_HID_CTL7 0x67 +#define RT722_UMP_HID_CTL8 0x68 + +/* Parameter & Verb control 01 (0x1a)(NID:20h) */ +#define RT722_HIDDEN_REG_SW_RESET (0x1 << 14) + +/* combo jack auto switch control 2 (0x46)(NID:20h) */ +#define RT722_COMBOJACK_AUTO_DET_STATUS (0x1 << 11) +#define RT722_COMBOJACK_AUTO_DET_TRS (0x1 << 10) +#define RT722_COMBOJACK_AUTO_DET_CTIA (0x1 << 9) +#define RT722_COMBOJACK_AUTO_DET_OMTP (0x1 << 8) + +/* DAC calibration control (0x00)(NID:58h) */ +#define RT722_DC_CALIB_CTRL (0x1 << 16) +/* DAC DC offset calibration control-1 (0x01)(NID:58h) */ +#define RT722_PDM_DC_CALIB_STATUS (0x1 << 15) + +#define RT722_EAPD_HIGH 0x2 +#define RT722_EAPD_LOW 0x0 + +/* Buffer address for HID */ +#define RT722_BUF_ADDR_HID1 0x44030000 +#define RT722_BUF_ADDR_HID2 0x44030020 + +/* RT722 SDCA Control - function number */ +#define FUNC_NUM_JACK_CODEC 0x01 +#define FUNC_NUM_MIC_ARRAY 0x02 +#define FUNC_NUM_HID 0x03 +#define FUNC_NUM_AMP 0x04 + +/* RT722 SDCA entity */ +#define RT722_SDCA_ENT_HID01 0x01 +#define RT722_SDCA_ENT_GE49 0x49 +#define RT722_SDCA_ENT_USER_FU05 0x05 +#define RT722_SDCA_ENT_USER_FU06 0x06 +#define RT722_SDCA_ENT_USER_FU0F 0x0f +#define RT722_SDCA_ENT_USER_FU10 0x19 +#define RT722_SDCA_ENT_USER_FU1E 0x1e +#define RT722_SDCA_ENT_FU15 0x15 +#define RT722_SDCA_ENT_PDE23 0x23 +#define RT722_SDCA_ENT_PDE40 0x40 +#define RT722_SDCA_ENT_PDE11 0x11 +#define RT722_SDCA_ENT_PDE12 0x12 +#define RT722_SDCA_ENT_PDE2A 0x2a +#define RT722_SDCA_ENT_CS01 0x01 +#define RT722_SDCA_ENT_CS11 0x11 +#define RT722_SDCA_ENT_CS1F 0x1f +#define RT722_SDCA_ENT_CS1C 0x1c +#define RT722_SDCA_ENT_CS31 0x31 +#define RT722_SDCA_ENT_OT23 0x42 +#define RT722_SDCA_ENT_IT26 0x26 +#define RT722_SDCA_ENT_IT09 0x09 +#define RT722_SDCA_ENT_PLATFORM_FU15 0x15 +#define RT722_SDCA_ENT_PLATFORM_FU44 0x44 +#define RT722_SDCA_ENT_XU03 0x03 +#define RT722_SDCA_ENT_XU0D 0x0d + +/* RT722 SDCA control */ +#define RT722_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT722_SDCA_CTL_FU_MUTE 0x01 +#define RT722_SDCA_CTL_FU_VOLUME 0x02 +#define RT722_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT722_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11 +#define RT722_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 +#define RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13 +#define RT722_SDCA_CTL_SELECTED_MODE 0x01 +#define RT722_SDCA_CTL_DETECTED_MODE 0x02 +#define RT722_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT722_SDCA_CTL_VENDOR_DEF 0x30 +#define RT722_SDCA_CTL_FU_CH_GAIN 0x0b + +/* RT722 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 +#define CH_08 0x08 + +/* sample frequency index */ +#define RT722_SDCA_RATE_16000HZ 0x04 +#define RT722_SDCA_RATE_32000HZ 0x07 +#define RT722_SDCA_RATE_44100HZ 0x08 +#define RT722_SDCA_RATE_48000HZ 0x09 +#define RT722_SDCA_RATE_96000HZ 0x0b +#define RT722_SDCA_RATE_192000HZ 0x0d + +enum { + RT722_AIF1, /* For headset mic and headphone */ + RT722_AIF2, /* For speaker */ + RT722_AIF3, /* For dmic */ + RT722_AIFS, +}; + +enum rt722_sdca_jd_src { + RT722_JD_NULL, + RT722_JD1, +}; + +int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt722_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave); +int rt722_sdca_index_write(struct rt722_sdca_priv *rt722, + unsigned int nid, unsigned int reg, unsigned int value); +int rt722_sdca_index_read(struct rt722_sdca_priv *rt722, + unsigned int nid, unsigned int reg, unsigned int *value); + +int rt722_sdca_jack_detect(struct rt722_sdca_priv *rt722, bool *hp, bool *mic); +#endif /* __RT722_H__ */ diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index fcf4fbaed3c7..733a7d130a95 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -633,7 +633,7 @@ static struct i2c_driver rt9120_driver = { .of_match_table = rt9120_device_table, .pm = &rt9120_pm_ops, }, - .probe_new = rt9120_probe, + .probe = rt9120_probe, .remove = rt9120_remove, }; module_i2c_driver(rt9120_driver); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a916f4619ea3..b22ba95bd0c0 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1826,7 +1826,7 @@ static struct i2c_driver sgtl5000_i2c_driver = { .name = "sgtl5000", .of_match_table = sgtl5000_dt_ids, }, - .probe_new = sgtl5000_i2c_probe, + .probe = sgtl5000_i2c_probe, .remove = sgtl5000_i2c_remove, .shutdown = sgtl5000_i2c_shutdown, .id_table = sgtl5000_id, diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c index b6c132edf3bd..7b9abbc1bd94 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -1807,7 +1807,7 @@ static struct i2c_driver sma1303_i2c_driver = { .name = "sma1303", .of_match_table = sma1303_of_match, }, - .probe_new = sma1303_i2c_probe, + .probe = sma1303_i2c_probe, .remove = sma1303_i2c_remove, .id_table = sma1303_i2c_id, }; diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c index a40fd20df984..93af8e209b05 100644 --- a/sound/soc/codecs/src4xxx-i2c.c +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -36,7 +36,7 @@ static struct i2c_driver src4xxx_i2c_driver = { .name = "src4xxx", .of_match_table = of_match_ptr(src4xxx_of_match), }, - .probe_new = src4xxx_i2c_probe, + .probe = src4xxx_i2c_probe, .id_table = src4xxx_i2c_ids, }; module_i2c_driver(src4xxx_i2c_driver); diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 22cb3b7c8283..d20d897407eb 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -803,7 +803,7 @@ static struct i2c_driver ssm2518_driver = { .name = "ssm2518", .of_match_table = of_match_ptr(ssm2518_dt_ids), }, - .probe_new = ssm2518_i2c_probe, + .probe = ssm2518_i2c_probe, .id_table = ssm2518_i2c_ids, }; module_i2c_driver(ssm2518_driver); diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index 3c85772901f5..596096466cd4 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -49,7 +49,7 @@ static struct i2c_driver ssm2602_i2c_driver = { .name = "ssm2602", .of_match_table = ssm2602_of_match, }, - .probe_new = ssm2602_i2c_probe, + .probe = ssm2602_i2c_probe, .id_table = ssm2602_i2c_id, }; module_i2c_driver(ssm2602_i2c_driver); diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c new file mode 100644 index 000000000000..784e890031a4 --- /dev/null +++ b/sound/soc/codecs/ssm3515.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +// +// Analog Devices' SSM3515 audio amp driver +// +// Copyright (C) The Asahi Linux Contributors + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> + +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + + +#define SSM3515_PWR 0x00 +#define SSM3515_PWR_APWDN_EN BIT(7) +#define SSM3515_PWR_BSNS_PWDN BIT(6) +#define SSM3515_PWR_S_RST BIT(1) +#define SSM3515_PWR_SPWDN BIT(0) + +#define SSM3515_GEC 0x01 +#define SSM3515_GEC_EDGE BIT(4) +#define SSM3515_GEC_EDGE_SHIFT 4 +#define SSM3515_GEC_ANA_GAIN GENMASK(1, 0) + +#define SSM3515_DAC 0x02 +#define SSM3515_DAC_HV BIT(7) +#define SSM3515_DAC_MUTE BIT(6) +#define SSM3515_DAC_HPF BIT(5) +#define SSM3515_DAC_LPM BIT(4) +#define SSM3515_DAC_FS GENMASK(2, 0) + +#define SSM3515_DAC_VOL 0x03 + +#define SSM3515_SAI1 0x04 +#define SSM3515_SAI1_DAC_POL BIT(7) +#define SSM3515_SAI1_BCLK_POL BIT(6) +#define SSM3515_SAI1_TDM_BCLKS GENMASK(5, 3) +#define SSM3515_SAI1_FSYNC_MODE BIT(2) +#define SSM3515_SAI1_SDATA_FMT BIT(1) +#define SSM3515_SAI1_SAI_MODE BIT(0) + +#define SSM3515_SAI2 0x05 +#define SSM3515_SAI2_DATA_WIDTH BIT(7) +#define SSM3515_SAI2_AUTO_SLOT BIT(4) +#define SSM3515_SAI2_TDM_SLOT GENMASK(3, 0) + +#define SSM3515_VBAT_OUT 0x06 + +#define SSM3515_STATUS 0x0a +#define SSM3515_STATUS_UVLO_REG BIT(6) +#define SSM3515_STATUS_LIM_EG BIT(5) +#define SSM3515_STATUS_CLIP BIT(4) +#define SSM3515_STATUS_AMP_OC BIT(3) +#define SSM3515_STATUS_OTF BIT(2) +#define SSM3515_STATUS_OTW BIT(1) +#define SSM3515_STATUS_BAT_WARN BIT(0) + +static bool ssm3515_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SSM3515_STATUS: + case SSM3515_VBAT_OUT: + return true; + + default: + return false; + } +} + +static const struct reg_default ssm3515_reg_defaults[] = { + { SSM3515_PWR, 0x81 }, + { SSM3515_GEC, 0x01 }, + { SSM3515_DAC, 0x32 }, + { SSM3515_DAC_VOL, 0x40 }, + { SSM3515_SAI1, 0x11 }, + { SSM3515_SAI2, 0x00 }, +}; + +static const struct regmap_config ssm3515_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = ssm3515_volatile_reg, + .max_register = 0xb, + .reg_defaults = ssm3515_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ssm3515_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +struct ssm3515_data { + struct device *dev; + struct regmap *regmap; +}; + +// The specced range is -71.25...24.00 dB with step size of 0.375 dB, +// and a mute item below that. This is represented by -71.62...24.00 dB +// with the mute item mapped onto the low end. +static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_volume, -7162, 2400); + +static const char * const ssm3515_ana_gain_text[] = { + "8.4 V Span", "12.6 V Span", "14 V Span", "15 V Span", +}; + +static SOC_ENUM_SINGLE_DECL(ssm3515_ana_gain_enum, SSM3515_GEC, + __bf_shf(SSM3515_GEC_ANA_GAIN), + ssm3515_ana_gain_text); + +static const struct snd_kcontrol_new ssm3515_snd_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SSM3515_DAC_VOL, + 0, 255, 1, ssm3515_dac_volume), + SOC_SINGLE("Low EMI Mode Switch", SSM3515_GEC, + __bf_shf(SSM3515_GEC_EDGE), 1, 0), + SOC_SINGLE("Soft Volume Ramping Switch", SSM3515_DAC, + __bf_shf(SSM3515_DAC_HV), 1, 1), + SOC_SINGLE("HPF Switch", SSM3515_DAC, + __bf_shf(SSM3515_DAC_HPF), 1, 0), + SOC_SINGLE("DAC Invert Switch", SSM3515_SAI1, + __bf_shf(SSM3515_SAI1_DAC_POL), 1, 0), + SOC_ENUM("DAC Analog Gain Select", ssm3515_ana_gain_enum), +}; + +static void ssm3515_read_faults(struct snd_soc_component *component) +{ + int ret; + + ret = snd_soc_component_read(component, SSM3515_STATUS); + if (ret <= 0) { + /* + * If the read was erroneous, ASoC core has printed a message, + * and that's all that's appropriate in handling the error here. + */ + return; + } + + dev_err(component->dev, "device reports:%s%s%s%s%s%s%s\n", + FIELD_GET(SSM3515_STATUS_UVLO_REG, ret) ? " voltage regulator fault" : "", + FIELD_GET(SSM3515_STATUS_LIM_EG, ret) ? " limiter engaged" : "", + FIELD_GET(SSM3515_STATUS_CLIP, ret) ? " clipping detected" : "", + FIELD_GET(SSM3515_STATUS_AMP_OC, ret) ? " amp over-current fault" : "", + FIELD_GET(SSM3515_STATUS_OTF, ret) ? " overtemperature fault" : "", + FIELD_GET(SSM3515_STATUS_OTW, ret) ? " overtemperature warning" : "", + FIELD_GET(SSM3515_STATUS_BAT_WARN, ret) ? " bat voltage low warning" : ""); +} + +static int ssm3515_probe(struct snd_soc_component *component) +{ + int ret; + + /* Start out muted */ + ret = snd_soc_component_update_bits(component, SSM3515_DAC, + SSM3515_DAC_MUTE, SSM3515_DAC_MUTE); + if (ret < 0) + return ret; + + /* Disable the 'master power-down' */ + ret = snd_soc_component_update_bits(component, SSM3515_PWR, + SSM3515_PWR_SPWDN, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + int ret; + + ret = snd_soc_component_update_bits(dai->component, + SSM3515_DAC, + SSM3515_DAC_MUTE, + FIELD_PREP(SSM3515_DAC_MUTE, mute)); + if (ret < 0) + return ret; + return 0; +} + +static int ssm3515_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret, rateval; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + case SNDRV_PCM_FORMAT_S24: + ret = snd_soc_component_update_bits(component, + SSM3515_SAI2, SSM3515_SAI2_DATA_WIDTH, + FIELD_PREP(SSM3515_SAI2_DATA_WIDTH, + params_width(params) == 16)); + if (ret < 0) + return ret; + break; + + default: + return -EINVAL; + } + + switch (params_rate(params)) { + case 8000 ... 12000: + rateval = 0; + break; + case 16000 ... 24000: + rateval = 1; + break; + case 32000 ... 48000: + rateval = 2; + break; + case 64000 ... 96000: + rateval = 3; + break; + case 128000 ... 192000: + rateval = 4; + break; + case 48001 ... 63999: /* this is ...72000 but overlaps */ + rateval = 5; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, + SSM3515_DAC, SSM3515_DAC_FS, + FIELD_PREP(SSM3515_DAC_FS, rateval)); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + bool fpol_inv = false; /* non-inverted: frame starts with low-to-high FSYNC */ + int ret; + u8 sai1 = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_NF: + case SND_SOC_DAIFMT_IB_IF: + sai1 |= SSM3515_SAI1_BCLK_POL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + fpol_inv = 1; + sai1 &= ~SSM3515_SAI1_SDATA_FMT; /* 1 bit start delay */ + break; + case SND_SOC_DAIFMT_LEFT_J: + fpol_inv = 0; + sai1 |= SSM3515_SAI1_SDATA_FMT; /* no start delay */ + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: + fpol_inv ^= 1; + break; + } + + /* Set the serial input to 'TDM mode' */ + sai1 |= SSM3515_SAI1_SAI_MODE; + + if (fpol_inv) { + /* + * We configure the codec in a 'TDM mode', in which the + * FSYNC_MODE bit of SAI1 is supposed to select between + * what the datasheet calls 'Pulsed FSYNC mode' and '50% + * FSYNC mode'. + * + * Experiments suggest that this bit in fact simply selects + * the FSYNC polarity, so go with that. + */ + sai1 |= SSM3515_SAI1_FSYNC_MODE; + } + + ret = snd_soc_component_update_bits(component, SSM3515_SAI1, + SSM3515_SAI1_BCLK_POL | SSM3515_SAI1_SDATA_FMT | + SSM3515_SAI1_SAI_MODE | SSM3515_SAI1_FSYNC_MODE, sai1); + + if (ret < 0) + return ret; + return 0; +} + +static int ssm3515_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + int slot, tdm_bclks_val, ret; + + if (tx_mask == 0 || rx_mask != 0) + return -EINVAL; + + slot = __ffs(tx_mask); + + if (tx_mask & ~BIT(slot)) + return -EINVAL; + + switch (slot_width) { + case 16: + tdm_bclks_val = 0; + break; + case 24: + tdm_bclks_val = 1; + break; + case 32: + tdm_bclks_val = 2; + break; + case 48: + tdm_bclks_val = 3; + break; + case 64: + tdm_bclks_val = 4; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, SSM3515_SAI1, + SSM3515_SAI1_TDM_BCLKS, + FIELD_PREP(SSM3515_SAI1_TDM_BCLKS, tdm_bclks_val)); + if (ret < 0) + return ret; + + ret = snd_soc_component_update_bits(component, SSM3515_SAI2, + SSM3515_SAI2_TDM_SLOT, + FIELD_PREP(SSM3515_SAI2_TDM_SLOT, slot)); + if (ret < 0) + return ret; + + return 0; +} + +static int ssm3515_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + /* + * We don't get live notification of faults, so at least at + * this time, when playback is over, check if we have tripped + * over anything and if so, log it. + */ + ssm3515_read_faults(dai->component); + return 0; +} + +static const struct snd_soc_dai_ops ssm3515_dai_ops = { + .mute_stream = ssm3515_mute, + .hw_params = ssm3515_hw_params, + .set_fmt = ssm3515_set_fmt, + .set_tdm_slot = ssm3515_set_tdm_slot, + .hw_free = ssm3515_hw_free, +}; + +static struct snd_soc_dai_driver ssm3515_dai_driver = { + .name = "SSM3515 SAI", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ssm3515_dai_ops, +}; + +static const struct snd_soc_dapm_widget ssm3515_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route ssm3515_dapm_routes[] = { + {"OUT", NULL, "DAC"}, + {"DAC", NULL, "Playback"}, +}; + +static const struct snd_soc_component_driver ssm3515_asoc_component = { + .probe = ssm3515_probe, + .controls = ssm3515_snd_controls, + .num_controls = ARRAY_SIZE(ssm3515_snd_controls), + .dapm_widgets = ssm3515_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm3515_dapm_widgets), + .dapm_routes = ssm3515_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ssm3515_dapm_routes), + .endianness = 1, +}; + +static int ssm3515_i2c_probe(struct i2c_client *client) +{ + struct ssm3515_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &client->dev; + i2c_set_clientdata(client, data); + + data->regmap = devm_regmap_init_i2c(client, &ssm3515_i2c_regmap); + if (IS_ERR(data->regmap)) + return dev_err_probe(data->dev, PTR_ERR(data->regmap), + "initializing register map\n"); + + /* Perform a reset */ + ret = regmap_update_bits(data->regmap, SSM3515_PWR, + SSM3515_PWR_S_RST, SSM3515_PWR_S_RST); + if (ret < 0) + return dev_err_probe(data->dev, ret, + "performing software reset\n"); + regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap); + + return devm_snd_soc_register_component(data->dev, + &ssm3515_asoc_component, + &ssm3515_dai_driver, 1); +} + +static const struct of_device_id ssm3515_of_match[] = { + { .compatible = "adi,ssm3515" }, + {} +}; +MODULE_DEVICE_TABLE(of, ssm3515_of_match); + +static struct i2c_driver ssm3515_i2c_driver = { + .driver = { + .name = "ssm3515", + .of_match_table = of_match_ptr(ssm3515_of_match), + }, + .probe_new = ssm3515_i2c_probe, +}; +module_i2c_driver(ssm3515_i2c_driver); + +MODULE_AUTHOR("Martin PoviÅ¡er <povik+lin@cutebit.org>"); +MODULE_DESCRIPTION("ASoC SSM3515 audio amp driver"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 4b0265617c7b..0a6f04d8f636 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -500,7 +500,7 @@ static struct i2c_driver ssm4567_driver = { .of_match_table = of_match_ptr(ssm4567_of_match), .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, - .probe_new = ssm4567_i2c_probe, + .probe = ssm4567_i2c_probe, .id_table = ssm4567_i2c_ids, }; module_i2c_driver(ssm4567_driver); diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 29af9595dac1..4a694d0bfd68 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1167,7 +1167,7 @@ static struct i2c_driver sta32x_i2c_driver = { .name = "sta32x", .of_match_table = of_match_ptr(st32x_dt_ids), }, - .probe_new = sta32x_i2c_probe, + .probe = sta32x_i2c_probe, .id_table = sta32x_i2c_id, }; diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index b033a5fcd6c0..d05f3fd57661 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1249,7 +1249,7 @@ static struct i2c_driver sta350_i2c_driver = { .name = "sta350", .of_match_table = of_match_ptr(st350_dt_ids), }, - .probe_new = sta350_i2c_probe, + .probe = sta350_i2c_probe, .remove = sta350_i2c_remove, .id_table = sta350_i2c_id, }; diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 313957099145..0ac08478ddac 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -379,7 +379,7 @@ static struct i2c_driver sta529_i2c_driver = { .name = "sta529", .of_match_table = sta529_of_match, }, - .probe_new = sta529_i2c_probe, + .probe = sta529_i2c_probe, .id_table = sta529_i2c_id, }; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 59a4ea5f6e30..8c9dc318b0e8 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -761,7 +761,7 @@ static struct i2c_driver tas2552_i2c_driver = { .of_match_table = of_match_ptr(tas2552_of_match), .pm = &tas2552_pm, }, - .probe_new = tas2552_probe, + .probe = tas2552_probe, .remove = tas2552_i2c_remove, .id_table = tas2552_id, }; diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index b486d0bd86c9..962c2cdfa017 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -8,7 +8,6 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/i2c.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/gpio/consumer.h> @@ -784,7 +783,7 @@ static struct i2c_driver tas2562_i2c_driver = { .name = "tas2562", .of_match_table = of_match_ptr(tas2562_of_match), }, - .probe_new = tas2562_probe, + .probe = tas2562_probe, .id_table = tas2562_id, }; diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 2e0ed3e68fa5..a9838e0738cc 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -756,7 +756,7 @@ static struct i2c_driver tas2764_i2c_driver = { .name = "tas2764", .of_match_table = of_match_ptr(tas2764_of_match), }, - .probe_new = tas2764_i2c_probe, + .probe = tas2764_i2c_probe, .id_table = tas2764_i2c_id, }; module_i2c_driver(tas2764_i2c_driver); diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 8557759acb1f..99bf402eb566 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -720,7 +720,7 @@ static struct i2c_driver tas2770_i2c_driver = { .name = "tas2770", .of_match_table = of_match_ptr(tas2770_of_match), }, - .probe_new = tas2770_i2c_probe, + .probe = tas2770_i2c_probe, .id_table = tas2770_i2c_id, }; module_i2c_driver(tas2770_i2c_driver); diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c index 09e7ada1bca4..86bd6c18a944 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -645,7 +645,7 @@ static struct i2c_driver tas2780_i2c_driver = { .name = "tas2780", .of_match_table = of_match_ptr(tas2780_of_match), }, - .probe_new = tas2780_i2c_probe, + .probe = tas2780_i2c_probe, .id_table = tas2780_i2c_id, }; module_i2c_driver(tas2780_i2c_driver); diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index f9e7122894bd..60e59e993ba6 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -990,7 +990,7 @@ static struct i2c_driver tas5086_i2c_driver = { .of_match_table = of_match_ptr(tas5086_dt_ids), }, .id_table = tas5086_i2c_id, - .probe_new = tas5086_i2c_probe, + .probe = tas5086_i2c_probe, .remove = tas5086_i2c_remove, }; diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index f39c3273b2fd..1756edb35961 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -975,7 +975,7 @@ static struct i2c_driver tas571x_i2c_driver = { .name = "tas571x", .of_match_table = of_match_ptr(tas571x_of_match), }, - .probe_new = tas571x_i2c_probe, + .probe = tas571x_i2c_probe, .remove = tas571x_i2c_remove, .id_table = tas571x_i2c_id, }; diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 4d27b60bd804..6dd6c0896eff 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -11,7 +11,6 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/i2c.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> @@ -821,7 +820,7 @@ static struct i2c_driver tas5720_i2c_driver = { .name = "tas5720", .of_match_table = of_match_ptr(tas5720_of_match), }, - .probe_new = tas5720_probe, + .probe = tas5720_probe, .id_table = tas5720_id, }; diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index 4e38eb7acea1..aca3756ffab6 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -597,7 +597,7 @@ MODULE_DEVICE_TABLE(of, tas5805m_of_match); #endif static struct i2c_driver tas5805m_i2c_driver = { - .probe_new = tas5805m_i2c_probe, + .probe = tas5805m_i2c_probe, .remove = tas5805m_i2c_remove, .id_table = tas5805m_i2c_id, .driver = { diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index f8ff69fa2549..da89e8c681dd 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -11,7 +11,6 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/i2c.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> @@ -803,7 +802,7 @@ static struct i2c_driver tas6424_i2c_driver = { .name = "tas6424", .of_match_table = of_match_ptr(tas6424_of_ids), }, - .probe_new = tas6424_i2c_probe, + .probe = tas6424_i2c_probe, .remove = tas6424_i2c_remove, .id_table = tas6424_i2c_ids, }; diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c index d964e5207569..e187d74a1737 100644 --- a/sound/soc/codecs/tda7419.c +++ b/sound/soc/codecs/tda7419.c @@ -629,7 +629,7 @@ static struct i2c_driver tda7419_driver = { .name = "tda7419", .of_match_table = tda7419_of_match, }, - .probe_new = tda7419_probe, + .probe = tda7419_probe, .id_table = tda7419_i2c_id, }; diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index 9f7902ec40db..8cca2ceadd9e 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -312,7 +312,7 @@ static struct i2c_driver tfa9879_i2c_driver = { .name = "tfa9879", .of_match_table = tfa9879_of_match, }, - .probe_new = tfa9879_i2c_probe, + .probe = tfa9879_i2c_probe, .id_table = tfa9879_i2c_id, }; diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c index b853507e65a8..79847a90ac46 100644 --- a/sound/soc/codecs/tfa989x.c +++ b/sound/soc/codecs/tfa989x.c @@ -416,7 +416,7 @@ static struct i2c_driver tfa989x_i2c_driver = { .name = "tfa989x", .of_match_table = tfa989x_of_match, }, - .probe_new = tfa989x_i2c_probe, + .probe = tfa989x_i2c_probe, }; module_i2c_driver(tfa989x_i2c_driver); diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 52bb55724724..b976c1946286 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1451,7 +1451,7 @@ static struct i2c_driver adc3xxx_i2c_driver = { .name = "tlv320adc3xxx-codec", .of_match_table = tlv320adc3xxx_of_match, }, - .probe_new = adc3xxx_i2c_probe, + .probe = adc3xxx_i2c_probe, .remove = __exit_p(adc3xxx_i2c_remove), .id_table = adc3xxx_i2c_id, }; diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 530f321d08e9..41342b340680 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -1208,7 +1208,7 @@ static struct i2c_driver adcx140_i2c_driver = { .name = "tlv320adcx140-codec", .of_match_table = of_match_ptr(tlv320adcx140_of_match), }, - .probe_new = adcx140_i2c_probe, + .probe = adcx140_i2c_probe, .id_table = adcx140_i2c_id, }; module_i2c_driver(adcx140_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index 1f97673a1cc0..9692ae007c91 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -47,7 +47,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { .name = "tlv320aic23-codec", .of_match_table = of_match_ptr(tlv320aic23_of_match), }, - .probe_new = tlv320aic23_i2c_probe, + .probe = tlv320aic23_i2c_probe, .id_table = tlv320aic23_id, }; diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0847302121f6..9611aa8acb0d 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1746,7 +1746,7 @@ static struct i2c_driver aic31xx_i2c_driver = { .of_match_table = of_match_ptr(tlv320aic31xx_of_match), .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), }, - .probe_new = aic31xx_i2c_probe, + .probe = aic31xx_i2c_probe, .id_table = aic31xx_i2c_id, }; module_i2c_driver(aic31xx_i2c_driver); diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index d1e543ca3521..49b33a256cd7 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -71,7 +71,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .name = "tlv320aic32x4", .of_match_table = aic32x4_of_id, }, - .probe_new = aic32x4_i2c_probe, + .probe = aic32x4_i2c_probe, .remove = aic32x4_i2c_remove, .id_table = aic32x4_i2c_id, }; diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c index d7e94d564dbf..bb33fd3dfb4f 100644 --- a/sound/soc/codecs/tlv320aic3x-i2c.c +++ b/sound/soc/codecs/tlv320aic3x-i2c.c @@ -61,7 +61,7 @@ static struct i2c_driver aic3x_i2c_driver = { .name = "tlv320aic3x", .of_match_table = aic3x_of_id, }, - .probe_new = aic3x_i2c_probe, + .probe = aic3x_i2c_probe, .remove = aic3x_i2c_remove, .id_table = aic3x_i2c_id, }; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 16ce3ef1134b..fa46f51d4341 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1560,7 +1560,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .driver = { .name = "tlv320dac33-codec", }, - .probe_new = dac33_i2c_probe, + .probe = dac33_i2c_probe, .remove = dac33_i2c_remove, .id_table = tlv320dac33_i2c_id, }; diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 8c00db32996b..5bc486283fde 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -319,7 +319,7 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .name = "tpa6130a2", .of_match_table = of_match_ptr(tpa6130a2_of_match), }, - .probe_new = tpa6130a2_probe, + .probe = tpa6130a2_probe, .id_table = tpa6130a2_id, }; diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 5282112c7d8d..6d9166d9116a 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -455,7 +455,7 @@ static struct i2c_driver ts3a227e_driver = { .of_match_table = of_match_ptr(ts3a227e_of_match), .acpi_match_table = ACPI_PTR(ts3a227e_acpi_match), }, - .probe_new = ts3a227e_i2c_probe, + .probe = ts3a227e_i2c_probe, .id_table = ts3a227e_i2c_ids, }; module_i2c_driver(ts3a227e_driver); diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index fa0c525189c2..1eefc1fe6ea8 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -1503,7 +1503,7 @@ static struct i2c_driver tscs42xx_i2c_driver = { .name = "tscs42xx", .of_match_table = tscs42xx_of_match, }, - .probe_new = tscs42xx_i2c_probe, + .probe = tscs42xx_i2c_probe, .id_table = tscs42xx_i2c_id, }; diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 38622bc247fc..744aef32a21f 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -3473,7 +3473,7 @@ static struct i2c_driver tscs454_i2c_driver = { .name = "tscs454", .of_match_table = tscs454_of_match, }, - .probe_new = tscs454_i2c_probe, + .probe = tscs454_i2c_probe, .id_table = tscs454_i2c_id, }; diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index fdaaee845176..5c5751dc14e5 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -798,7 +798,7 @@ static struct i2c_driver uda1380_i2c_driver = { .name = "uda1380-codec", .of_match_table = uda1380_of_match, }, - .probe_new = uda1380_i2c_probe, + .probe = uda1380_i2c_probe, .id_table = uda1380_i2c_id, }; diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index 402286dfaea4..5befae414636 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1271,7 +1271,7 @@ static int wcd9380_probe(struct sdw_slave *pdev, /* Start in cache-only until device is enumerated */ regcache_cache_only(wcd->regmap, true); - }; + } pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 0064a607ec68..d7eeb41ba60f 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -243,7 +243,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = { .driver = { .name = "wm1250-ev1", }, - .probe_new = wm1250_ev1_probe, + .probe = wm1250_ev1_probe, .remove = wm1250_ev1_remove, .id_table = wm1250_ev1_i2c_id, }; diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 14b4fd97488c..9571ea53cb3f 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -938,7 +938,7 @@ static struct i2c_driver wm2000_i2c_driver = { .driver = { .name = "wm2000", }, - .probe_new = wm2000_i2c_probe, + .probe = wm2000_i2c_probe, .id_table = wm2000_i2c_id, }; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 0a65afa44a59..277b8c468c78 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2485,7 +2485,7 @@ static struct i2c_driver wm2200_i2c_driver = { .name = "wm2200", .pm = &wm2200_pm, }, - .probe_new = wm2200_i2c_probe, + .probe = wm2200_i2c_probe, .remove = wm2200_i2c_remove, .id_table = wm2200_i2c_id, }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 3b09d4a1684f..a86eacb2a9bb 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2709,7 +2709,7 @@ static struct i2c_driver wm5100_i2c_driver = { .name = "wm5100", .pm = &wm5100_pm, }, - .probe_new = wm5100_i2c_probe, + .probe = wm5100_i2c_probe, .remove = wm5100_i2c_remove, .id_table = wm5100_i2c_id, }; diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index e13f9780a111..c0ed76d5b65f 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -678,7 +678,7 @@ static struct i2c_driver wm8510_i2c_driver = { .name = "wm8510", .of_match_table = wm8510_of_match, }, - .probe_new = wm8510_i2c_probe, + .probe = wm8510_i2c_probe, .id_table = wm8510_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 66f6371d8acf..55c72c5ac845 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -527,7 +527,7 @@ static struct i2c_driver wm8523_i2c_driver = { .name = "wm8523", .of_match_table = wm8523_of_match, }, - .probe_new = wm8523_i2c_probe, + .probe = wm8523_i2c_probe, .id_table = wm8523_i2c_id, }; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index ca796aa0aeb7..34ae7fe05398 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1049,7 +1049,7 @@ static struct i2c_driver wm8580_i2c_driver = { .name = "wm8580", .of_match_table = wm8580_of_match, }, - .probe_new = wm8580_i2c_probe, + .probe = wm8580_i2c_probe, .id_table = wm8580_i2c_id, }; diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 383c6796e8a3..903a0147d584 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -464,7 +464,7 @@ static struct i2c_driver wm8711_i2c_driver = { .name = "wm8711", .of_match_table = wm8711_of_match, }, - .probe_new = wm8711_i2c_probe, + .probe = wm8711_i2c_probe, .id_table = wm8711_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index a3dbdbf40723..5ea6d8fd10f6 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -305,7 +305,7 @@ static struct i2c_driver wm8728_i2c_driver = { .name = "wm8728", .of_match_table = wm8728_of_match, }, - .probe_new = wm8728_i2c_probe, + .probe = wm8728_i2c_probe, .id_table = wm8728_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8731-i2c.c b/sound/soc/codecs/wm8731-i2c.c index fdf03bf91606..c39e637d813d 100644 --- a/sound/soc/codecs/wm8731-i2c.c +++ b/sound/soc/codecs/wm8731-i2c.c @@ -57,7 +57,7 @@ static struct i2c_driver wm8731_i2c_driver = { .name = "wm8731", .of_match_table = wm8731_of_match, }, - .probe_new = wm8731_i2c_probe, + .probe = wm8731_i2c_probe, .id_table = wm8731_i2c_id, }; diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 90b54343370c..9f4e372e90ea 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -649,7 +649,7 @@ static struct i2c_driver wm8737_i2c_driver = { .name = "wm8737", .of_match_table = wm8737_of_match, }, - .probe_new = wm8737_i2c_probe, + .probe = wm8737_i2c_probe, .id_table = wm8737_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index c7afa4f2795d..787156b980a1 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -616,7 +616,7 @@ static struct i2c_driver wm8741_i2c_driver = { .name = "wm8741", .of_match_table = wm8741_of_match, }, - .probe_new = wm8741_i2c_probe, + .probe = wm8741_i2c_probe, .id_table = wm8741_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 2f6ee8d6639f..20dc9ff9fea9 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -813,7 +813,7 @@ static struct i2c_driver wm8750_i2c_driver = { .name = "wm8750", .of_match_table = wm8750_of_match, }, - .probe_new = wm8750_i2c_probe, + .probe = wm8750_i2c_probe, .id_table = wm8750_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index bb18f58dc670..5e8a8eb41b2b 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1590,7 +1590,7 @@ static struct i2c_driver wm8753_i2c_driver = { .name = "wm8753", .of_match_table = wm8753_of_match, }, - .probe_new = wm8753_i2c_probe, + .probe = wm8753_i2c_probe, .id_table = wm8753_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 936ea24621b0..212224a68006 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -523,7 +523,7 @@ static struct i2c_driver wm8776_i2c_driver = { .name = "wm8776", .of_match_table = wm8776_of_match, }, - .probe_new = wm8776_i2c_probe, + .probe = wm8776_i2c_probe, .id_table = wm8776_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index 3ce1a39d76eb..7062a8b2f8b5 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver wm8804_i2c_driver = { .of_match_table = of_match_ptr(wm8804_of_match), .acpi_match_table = ACPI_PTR(wm8804_acpi_match), }, - .probe_new = wm8804_i2c_probe, + .probe = wm8804_i2c_probe, .remove = wm8804_i2c_remove, .id_table = wm8804_i2c_id }; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 03bbd85ebdf4..320ccd92f318 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1295,7 +1295,7 @@ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "wm8900", }, - .probe_new = wm8900_i2c_probe, + .probe = wm8900_i2c_probe, .remove = wm8900_i2c_remove, .id_table = wm8900_i2c_id, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 1dc8e20bdace..901b65ef8de5 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2209,7 +2209,7 @@ static struct i2c_driver wm8903_i2c_driver = { .name = "wm8903", .of_match_table = wm8903_of_match, }, - .probe_new = wm8903_i2c_probe, + .probe = wm8903_i2c_probe, .remove = wm8903_i2c_remove, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 791d8738d1c0..068e610b1b4c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2337,7 +2337,7 @@ static struct i2c_driver wm8904_i2c_driver = { .name = "wm8904", .of_match_table = of_match_ptr(wm8904_of_match), }, - .probe_new = wm8904_i2c_probe, + .probe = wm8904_i2c_probe, .id_table = wm8904_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 8eb4782c9232..53c27986d216 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -860,7 +860,7 @@ static struct i2c_driver wm8940_i2c_driver = { .name = "wm8940", .of_match_table = wm8940_of_match, }, - .probe_new = wm8940_i2c_probe, + .probe = wm8940_i2c_probe, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 05ef45672ebc..78044f580a67 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1003,7 +1003,7 @@ static struct i2c_driver wm8955_i2c_driver = { .driver = { .name = "wm8955", }, - .probe_new = wm8955_i2c_probe, + .probe = wm8955_i2c_probe, .id_table = wm8955_i2c_id, }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 0d167238a369..366f5d769d6d 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1518,7 +1518,7 @@ static struct i2c_driver wm8960_i2c_driver = { .of_match_table = of_match_ptr(wm8960_of_match), .acpi_match_table = ACPI_PTR(wm8960_acpi_match), }, - .probe_new = wm8960_i2c_probe, + .probe = wm8960_i2c_probe, .remove = wm8960_i2c_remove, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a4857024711d..c076f78d04ce 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -982,7 +982,7 @@ static struct i2c_driver wm8961_i2c_driver = { .name = "wm8961", .of_match_table = of_match_ptr(wm8961_of_match), }, - .probe_new = wm8961_i2c_probe, + .probe = wm8961_i2c_probe, .id_table = wm8961_i2c_id, }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index b901e4c65e8a..68ea15be7330 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3946,7 +3946,7 @@ static struct i2c_driver wm8962_i2c_driver = { .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, - .probe_new = wm8962_i2c_probe, + .probe = wm8962_i2c_probe, .remove = wm8962_i2c_remove, .id_table = wm8962_i2c_id, }; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 4db9248de54b..b22d8f0b59be 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -700,7 +700,7 @@ static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", }, - .probe_new = wm8971_i2c_probe, + .probe = wm8971_i2c_probe, .id_table = wm8971_i2c_id, }; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 010a394c705c..044b6f604c09 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -723,7 +723,7 @@ static struct i2c_driver wm8974_i2c_driver = { .name = "wm8974", .of_match_table = wm8974_of_match, }, - .probe_new = wm8974_i2c_probe, + .probe = wm8974_i2c_probe, .id_table = wm8974_i2c_id, }; diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index aa2f55401a88..5c829301cf4c 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1072,7 +1072,7 @@ static struct i2c_driver wm8978_i2c_driver = { .name = "wm8978", .of_match_table = wm8978_of_match, }, - .probe_new = wm8978_i2c_probe, + .probe = wm8978_i2c_probe, .id_table = wm8978_i2c_id, }; diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 50e6ac6ccbe0..2bd26e2478d9 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -1068,7 +1068,7 @@ static struct i2c_driver wm8983_i2c_driver = { .driver = { .name = "wm8983", }, - .probe_new = wm8983_i2c_probe, + .probe = wm8983_i2c_probe, .id_table = wm8983_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 751aa6730833..c0816bcfa294 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1206,7 +1206,7 @@ static struct i2c_driver wm8985_i2c_driver = { .driver = { .name = "wm8985", }, - .probe_new = wm8985_i2c_probe, + .probe = wm8985_i2c_probe, .id_table = wm8985_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 5dbdf647cd97..b440719cca7d 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -905,7 +905,7 @@ static struct i2c_driver wm8988_i2c_driver = { .driver = { .name = "wm8988", }, - .probe_new = wm8988_i2c_probe, + .probe = wm8988_i2c_probe, .id_table = wm8988_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 589af286f133..5a8e765090af 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1247,7 +1247,7 @@ static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", }, - .probe_new = wm8990_i2c_probe, + .probe = wm8990_i2c_probe, .id_table = wm8990_i2c_id, }; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 30121993b7b4..8cb2ae829699 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1323,7 +1323,7 @@ static struct i2c_driver wm8991_i2c_driver = { .driver = { .name = "wm8991", }, - .probe_new = wm8991_i2c_probe, + .probe = wm8991_i2c_probe, .id_table = wm8991_i2c_id, }; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 22a47acbc6d1..feb997c698e2 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1741,7 +1741,7 @@ static struct i2c_driver wm8993_i2c_driver = { .driver = { .name = "wm8993", }, - .probe_new = wm8993_i2c_probe, + .probe = wm8993_i2c_probe, .remove = wm8993_i2c_remove, .id_table = wm8993_i2c_id, }; diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index eed48bf339f2..90588614edcc 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2268,7 +2268,7 @@ static struct i2c_driver wm8995_i2c_driver = { .driver = { .name = "wm8995", }, - .probe_new = wm8995_i2c_probe, + .probe = wm8995_i2c_probe, .id_table = wm8995_i2c_id }; #endif diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index b52ed89d631a..5d0eb0ae0475 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -3086,7 +3086,7 @@ static struct i2c_driver wm8996_i2c_driver = { .driver = { .name = "wm8996", }, - .probe_new = wm8996_i2c_probe, + .probe = wm8996_i2c_probe, .remove = wm8996_i2c_remove, .id_table = wm8996_i2c_id, }; diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 513ec0ba81bb..34a07db7342a 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1369,7 +1369,7 @@ static struct i2c_driver wm9081_i2c_driver = { .driver = { .name = "wm9081", }, - .probe_new = wm9081_i2c_probe, + .probe = wm9081_i2c_probe, .remove = wm9081_i2c_remove, .id_table = wm9081_i2c_id, }; diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index ef3524c3f07f..432729c753dd 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -616,7 +616,7 @@ static struct i2c_driver wm9090_i2c_driver = { .driver = { .name = "wm9090", }, - .probe_new = wm9090_i2c_probe, + .probe = wm9090_i2c_probe, .id_table = wm9090_id, }; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 216120b68b64..5a89abfe8784 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -15,7 +15,6 @@ #include <linux/firmware.h> #include <linux/list.h> #include <linux/pm.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -686,8 +685,6 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, { struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); struct wm_coeff_ctl *ctl; - struct snd_kcontrol *kcontrol; - char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ret; ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); @@ -699,23 +696,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, ctl = cs_ctl->priv; - if (dsp->component->name_prefix) - snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", - dsp->component->name_prefix, ctl->name); - else - snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", - ctl->name); - - kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name); - if (!kcontrol) { - adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name); - return -EINVAL; - } - - snd_ctl_notify(dsp->component->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id); - - return 0; + return snd_soc_component_notify_control(dsp->component, ctl->name); } EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index ca20cade6840..dd5d8d77bdc9 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -17,6 +17,7 @@ #include <linux/io.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/reset.h> #include <linux/slab.h> #include <linux/pm_runtime.h> #include <sound/designware_i2s.h> @@ -480,9 +481,9 @@ static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = { static const u32 formats[COMP_MAX_WORDSIZE] = { SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_FMTBIT_S16_LE, - SNDRV_PCM_FMTBIT_S24_LE, - SNDRV_PCM_FMTBIT_S24_LE, - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 0, 0, 0 @@ -648,6 +649,14 @@ static int dw_i2s_probe(struct platform_device *pdev) if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); + dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(dev->reset)) + return PTR_ERR(dev->reset); + + ret = reset_control_deassert(dev->reset); + if (ret) + return ret; + dev->dev = &pdev->dev; irq = platform_get_irq_optional(pdev, 0); @@ -656,7 +665,7 @@ static int dw_i2s_probe(struct platform_device *pdev) pdev->name, dev); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq\n"); - return ret; + goto err_assert_reset; } } @@ -676,24 +685,27 @@ static int dw_i2s_probe(struct platform_device *pdev) ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res); } if (ret < 0) - return ret; + goto err_assert_reset; if (dev->capability & DW_I2S_MASTER) { if (pdata) { dev->i2s_clk_cfg = pdata->i2s_clk_cfg; if (!dev->i2s_clk_cfg) { dev_err(&pdev->dev, "no clock configure method\n"); - return -ENODEV; + ret = -ENODEV; + goto err_assert_reset; } } dev->clk = devm_clk_get(&pdev->dev, clk_id); - if (IS_ERR(dev->clk)) - return PTR_ERR(dev->clk); + if (IS_ERR(dev->clk)) { + ret = PTR_ERR(dev->clk); + goto err_assert_reset; + } ret = clk_prepare_enable(dev->clk); if (ret < 0) - return ret; + goto err_assert_reset; } dev_set_drvdata(&pdev->dev, dev); @@ -727,6 +739,8 @@ static int dw_i2s_probe(struct platform_device *pdev) err_clk_disable: if (dev->capability & DW_I2S_MASTER) clk_disable_unprepare(dev->clk); +err_assert_reset: + reset_control_assert(dev->reset); return ret; } @@ -737,6 +751,7 @@ static void dw_i2s_remove(struct platform_device *pdev) if (dev->capability & DW_I2S_MASTER) clk_disable_unprepare(dev->clk); + reset_control_assert(dev->reset); pm_runtime_disable(&pdev->dev); } diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index 1c361eb6127e..d64bd4f8fd34 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -89,6 +89,7 @@ union dw_i2s_snd_dma_data { struct dw_i2s_dev { void __iomem *i2s_base; struct clk *clk; + struct reset_control *reset; int active; unsigned int capability; unsigned int quirks; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index abdaffb00fbd..d9344025dc16 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1400,7 +1400,9 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->cpu_dai_drv.symmetric_sample_bits = 0; } - if (of_property_read_bool(np, "fsl,sai-mclk-direction-output") && + sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output"); + + if (sai->mclk_direction_output && of_device_is_compatible(np, "fsl,imx6ul-sai")) { gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); if (IS_ERR(gpr)) { @@ -1443,7 +1445,7 @@ static int fsl_sai_probe(struct platform_device *pdev) dev_warn(dev, "Error reading SAI version: %d\n", ret); /* Select MCLK direction */ - if (of_property_read_bool(np, "fsl,sai-mclk-direction-output") && + if (sai->mclk_direction_output && sai->soc_data->max_register >= FSL_SAI_MCTL) { regmap_update_bits(sai->regmap, FSL_SAI_MCTL, FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); @@ -1562,6 +1564,17 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mm_data = { .max_register = FSL_SAI_MCTL, }; +static const struct fsl_sai_soc_data fsl_sai_imx8mn_data = { + .use_imx_pcm = true, + .use_edma = false, + .fifo_depth = 128, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 8, + .flags = 0, + .max_register = FSL_SAI_MDIV, +}; + static const struct fsl_sai_soc_data fsl_sai_imx8mp_data = { .use_imx_pcm = true, .use_edma = false, @@ -1571,6 +1584,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mp_data = { .pins = 8, .flags = 0, .max_register = FSL_SAI_MDIV, + .mclk_with_tere = true, }; static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = { @@ -1606,7 +1620,7 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx8mm-sai", .data = &fsl_sai_imx8mm_data }, { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data }, { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data }, - { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data }, + { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mn_data }, { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data }, { /* sentinel */ } }; @@ -1671,6 +1685,10 @@ static int fsl_sai_runtime_resume(struct device *dev) if (ret) goto disable_rx_clk; + if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output) + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), + FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); + return 0; disable_rx_clk: diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 197748a888d5..3eb994aef36a 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -230,6 +230,7 @@ struct fsl_sai_soc_data { bool use_imx_pcm; bool use_edma; bool mclk0_is_mclk1; + bool mclk_with_tere; unsigned int fifo_depth; unsigned int pins; unsigned int reg_offset; @@ -287,6 +288,7 @@ struct fsl_sai { bool synchronous[2]; struct fsl_sai_dl_cfg *dl_cfg; unsigned int dl_cfg_cnt; + bool mclk_direction_output; unsigned int mclk_id[2]; unsigned int mclk_streams; diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index b2c5aca92c6b..c93616e50f4d 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -15,7 +15,6 @@ #include <linux/clk.h> #include <sound/soc.h> #include <sound/soc-dapm.h> -#include <linux/pm_runtime.h> #include "fsl_sai.h" #include "fsl_audmix.h" @@ -207,8 +206,8 @@ static int imx_audmix_probe(struct platform_device *pdev) for (i = 0; i < num_dai; i++) { struct snd_soc_dai_link_component *dlc; - /* for CPU/Codec x 2 */ - dlc = devm_kcalloc(&pdev->dev, 4, sizeof(*dlc), GFP_KERNEL); + /* for CPU x 2 */ + dlc = devm_kcalloc(&pdev->dev, 2, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; @@ -244,7 +243,7 @@ static int imx_audmix_probe(struct platform_device *pdev) */ priv->dai[i].cpus = priv->dai[i].platforms = &dlc[0]; - priv->dai[i].codecs = &dlc[1]; + priv->dai[i].codecs = &asoc_dummy_dlc; priv->dai[i].num_cpus = 1; priv->dai[i].num_codecs = 1; @@ -252,8 +251,6 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[i].name = dai_name; priv->dai[i].stream_name = "HiFi-AUDMIX-FE"; - priv->dai[i].codecs->dai_name = "snd-soc-dummy-dai"; - priv->dai[i].codecs->name = "snd-soc-dummy"; priv->dai[i].cpus->of_node = args.np; priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev); priv->dai[i].dynamic = 1; @@ -270,15 +267,13 @@ static int imx_audmix_probe(struct platform_device *pdev) be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL, "AUDMIX-Capture-%d", i); - priv->dai[num_dai + i].cpus = &dlc[2]; - priv->dai[num_dai + i].codecs = &dlc[3]; + priv->dai[num_dai + i].cpus = &dlc[1]; + priv->dai[num_dai + i].codecs = &asoc_dummy_dlc; priv->dai[num_dai + i].num_cpus = 1; priv->dai[num_dai + i].num_codecs = 1; priv->dai[num_dai + i].name = be_name; - priv->dai[num_dai + i].codecs->dai_name = "snd-soc-dummy-dai"; - priv->dai[num_dai + i].codecs->name = "snd-soc-dummy"; priv->dai[num_dai + i].cpus->of_node = audmix_np; priv->dai[num_dai + i].cpus->dai_name = be_name; priv->dai[num_dai + i].no_pcm = 1; diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 64a4d7e9db60..78e2e3932ba5 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -615,17 +615,8 @@ static int imx_card_parse_of(struct imx_card_data *data) plat_data->type = CODEC_AK5552; } else { - dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); - if (!dlc) { - ret = -ENOMEM; - goto err; - } - - link->codecs = dlc; + link->codecs = &asoc_dummy_dlc; link->num_codecs = 1; - - link->codecs->dai_name = "snd-soc-dummy-dai"; - link->codecs->name = "snd-soc-dummy"; } if (!strncmp(link->name, "HiFi-ASRC-FE", 12)) { diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 89178106fe2c..93fc976e98dc 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -92,8 +92,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev) /* Optional codec node */ ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args); if (ret) { - data->dai.codecs->dai_name = "snd-soc-dummy-dai"; - data->dai.codecs->name = "snd-soc-dummy"; + *data->dai.codecs = asoc_dummy_dlc; } else { struct clk *clk; diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index ab978431ac98..44463f92e522 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -26,7 +26,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - comp = devm_kzalloc(&pdev->dev, 2 * sizeof(*comp), GFP_KERNEL); + comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL); if (!data || !comp) { ret = -ENOMEM; goto end; @@ -37,8 +37,8 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) * platform is using soc-generic-dmaengine-pcm */ data->dai.cpus = - data->dai.platforms = &comp[0]; - data->dai.codecs = &comp[1]; + data->dai.platforms = comp; + data->dai.codecs = &asoc_dummy_dlc; data->dai.num_cpus = 1; data->dai.num_codecs = 1; @@ -46,8 +46,6 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) data->dai.name = "S/PDIF PCM"; data->dai.stream_name = "S/PDIF PCM"; - data->dai.codecs->dai_name = "snd-soc-dummy-dai"; - data->dai.codecs->name = "snd-soc-dummy"; data->dai.cpus->of_node = spdif_np; data->dai.playback_only = true; data->dai.capture_only = true; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 467edd96eae5..b5ac0f0d5e8e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -889,11 +889,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, dai_num, cnf_num); - /* dummy CPU/Codec */ - priv->dummy.of_node = NULL; - priv->dummy.dai_name = "snd-soc-dummy-dai"; - priv->dummy.name = "snd-soc-dummy"; - priv->dai_props = dai_props; priv->dai_link = dai_link; priv->dais = dais; @@ -919,7 +914,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, } else { /* DPCM Be's CPU = dummy */ dai_props[i].cpus = - dai_link[i].cpus = &priv->dummy; + dai_link[i].cpus = &asoc_dummy_dlc; dai_props[i].num.cpus = dai_link[i].num_cpus = 1; } @@ -943,7 +938,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, } else { /* DPCM Fe's Codec = dummy */ dai_props[i].codecs = - dai_link[i].codecs = &priv->dummy; + dai_link[i].codecs = &asoc_dummy_dlc; dai_props[i].num.codecs = dai_link[i].num_codecs = 1; } diff --git a/sound/soc/google/Kconfig b/sound/soc/google/Kconfig new file mode 100644 index 000000000000..7603782fb060 --- /dev/null +++ b/sound/soc/google/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_SOC_CHV3_I2S + tristate "Google Chameleon v3 I2S device" + help + Enable support for the Google Chameleon v3 I2S device. diff --git a/sound/soc/google/Makefile b/sound/soc/google/Makefile new file mode 100644 index 000000000000..862496af1ae1 --- /dev/null +++ b/sound/soc/google/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_SND_SOC_CHV3_I2S) += chv3-i2s.o diff --git a/sound/soc/google/chv3-i2s.c b/sound/soc/google/chv3-i2s.c new file mode 100644 index 000000000000..0f6513444906 --- /dev/null +++ b/sound/soc/google/chv3-i2s.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <sound/soc.h> + +/* + * The I2S interface consists of two ring buffers - one for RX and one for + * TX. A ring buffer has a producer index and a consumer index. Depending + * on which way the data is flowing, either the software or the hardware + * writes data and updates the producer index, and the other end reads data + * and updates the consumer index. + * + * The pointer managed by software is updated using the .ack callback + * (see chv3_dma_ack). This seems to be the only way to reliably obtain + * the appl_ptr from within the driver and pass it to hardware. + * + * Because of the two pointer design, the ring buffer can never be full. With + * capture this isn't a problem, because the hardware being the producer + * will wait for the consumer index to move out of the way. With playback, + * however, this is problematic, because ALSA wants to fill up the buffer + * completely when waiting for hardware. In the .ack callback, the driver + * would have to wait for the consumer index to move out of the way by + * busy-waiting, which would keep stalling the kernel for quite a long time. + * + * The workaround to this problem is to "lie" to ALSA that the hw_pointer + * is one frame behind what it actually is (see chv3_dma_pointer). This + * way, ALSA will not try to fill up the entire buffer, and all callbacks + * are wait-free. + */ + +#define I2S_TX_ENABLE 0x00 +#define I2S_TX_BASE_ADDR 0x04 +#define I2S_TX_BUFFER_SIZE 0x08 +#define I2S_TX_PRODUCER_IDX 0x0c +#define I2S_TX_CONSUMER_IDX 0x10 +#define I2S_RX_ENABLE 0x14 +#define I2S_RX_BASE_ADDR 0x18 +#define I2S_RX_BUFFER_SIZE 0x1c +#define I2S_RX_PRODUCER_IDX 0x20 +#define I2S_RX_CONSUMER_IDX 0x24 + +#define I2S_SOFT_RESET 0x2c +#define I2S_SOFT_RESET_RX_BIT 0x1 +#define I2S_SOFT_RESET_TX_BIT 0x2 + +#define I2S_RX_IRQ 0x4c +#define I2S_RX_IRQ_CONST 0x50 +#define I2S_TX_IRQ 0x54 +#define I2S_TX_IRQ_CONST 0x58 + +#define I2S_IRQ_MASK 0x8 +#define I2S_IRQ_CLR 0xc +#define I2S_IRQ_RX_BIT 0x1 +#define I2S_IRQ_TX_BIT 0x2 + +#define I2S_MAX_BUFFER_SIZE 0x200000 + +struct chv3_i2s_dev { + struct device *dev; + void __iomem *iobase; + void __iomem *iobase_irq; + struct snd_pcm_substream *rx_substream; + struct snd_pcm_substream *tx_substream; + int tx_bytes_to_fetch; +}; + +static struct snd_soc_dai_driver chv3_i2s_dai = { + .name = "chv3-i2s", + .capture = { + .channels_min = 1, + .channels_max = 128, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 96000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .playback = { + .channels_min = 1, + .channels_max = 128, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 96000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, +}; + +static const struct snd_pcm_hardware chv3_dma_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = I2S_MAX_BUFFER_SIZE, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 4, + .periods_max = 256, +}; + +static inline void chv3_i2s_wr(struct chv3_i2s_dev *i2s, int offset, u32 val) +{ + writel(val, i2s->iobase + offset); +} + +static inline u32 chv3_i2s_rd(struct chv3_i2s_dev *i2s, int offset) +{ + return readl(i2s->iobase + offset); +} + +static irqreturn_t chv3_i2s_isr(int irq, void *data) +{ + struct chv3_i2s_dev *i2s = data; + u32 reg; + + reg = readl(i2s->iobase_irq + I2S_IRQ_CLR); + if (!reg) + return IRQ_NONE; + + if (reg & I2S_IRQ_RX_BIT) + snd_pcm_period_elapsed(i2s->rx_substream); + + if (reg & I2S_IRQ_TX_BIT) + snd_pcm_period_elapsed(i2s->tx_substream); + + writel(reg, i2s->iobase_irq + I2S_IRQ_CLR); + + return IRQ_HANDLED; +} + +static int chv3_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + int res; + + snd_soc_set_runtime_hwparams(substream, &chv3_dma_hw); + + res = snd_pcm_hw_constraint_pow2(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES); + if (res) + return res; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + i2s->rx_substream = substream; + else + i2s->tx_substream = substream; + + return 0; +} +static int chv3_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + chv3_i2s_wr(i2s, I2S_RX_ENABLE, 0); + else + chv3_i2s_wr(i2s, I2S_TX_ENABLE, 0); + + return 0; +} + +static int chv3_dma_pcm_construct(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + struct snd_pcm_substream *substream; + int res; + + substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream) { + res = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, i2s->dev, + I2S_MAX_BUFFER_SIZE, &substream->dma_buffer); + if (res) + return res; + } + + substream = rtd->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (substream) { + res = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, i2s->dev, + I2S_MAX_BUFFER_SIZE, &substream->dma_buffer); + if (res) + return res; + } + + return 0; +} + +static int chv3_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + return 0; +} + +static int chv3_dma_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + unsigned int buffer_bytes, period_bytes, period_size; + + buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + period_bytes = snd_pcm_lib_period_bytes(substream); + period_size = substream->runtime->period_size; + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + chv3_i2s_wr(i2s, I2S_SOFT_RESET, I2S_SOFT_RESET_RX_BIT); + chv3_i2s_wr(i2s, I2S_RX_BASE_ADDR, substream->dma_buffer.addr); + chv3_i2s_wr(i2s, I2S_RX_BUFFER_SIZE, buffer_bytes); + chv3_i2s_wr(i2s, I2S_RX_IRQ, (period_size << 8) | 1); + chv3_i2s_wr(i2s, I2S_RX_ENABLE, 1); + } else { + chv3_i2s_wr(i2s, I2S_SOFT_RESET, I2S_SOFT_RESET_TX_BIT); + chv3_i2s_wr(i2s, I2S_TX_BASE_ADDR, substream->dma_buffer.addr); + chv3_i2s_wr(i2s, I2S_TX_BUFFER_SIZE, buffer_bytes); + chv3_i2s_wr(i2s, I2S_TX_IRQ, ((period_bytes / i2s->tx_bytes_to_fetch) << 8) | 1); + chv3_i2s_wr(i2s, I2S_TX_ENABLE, 1); + } + writel(I2S_IRQ_RX_BIT | I2S_IRQ_TX_BIT, i2s->iobase_irq + I2S_IRQ_MASK); + + return 0; +} + +static snd_pcm_uframes_t chv3_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + u32 frame_bytes, buffer_bytes; + u32 idx_bytes; + + frame_bytes = substream->runtime->frame_bits * 8; + buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + idx_bytes = chv3_i2s_rd(i2s, I2S_RX_PRODUCER_IDX); + } else { + idx_bytes = chv3_i2s_rd(i2s, I2S_TX_CONSUMER_IDX); + /* lag the pointer by one frame */ + idx_bytes = (idx_bytes - frame_bytes) & (buffer_bytes - 1); + } + + return bytes_to_frames(substream->runtime, idx_bytes); +} + +static int chv3_dma_ack(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); + unsigned int bytes, idx; + + bytes = frames_to_bytes(runtime, runtime->control->appl_ptr); + idx = bytes & (snd_pcm_lib_buffer_bytes(substream) - 1); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + chv3_i2s_wr(i2s, I2S_RX_CONSUMER_IDX, idx); + else + chv3_i2s_wr(i2s, I2S_TX_PRODUCER_IDX, idx); + + return 0; +} + +static const struct snd_soc_component_driver chv3_i2s_comp = { + .name = "chv3-i2s-comp", + .open = chv3_dma_open, + .close = chv3_dma_close, + .pcm_construct = chv3_dma_pcm_construct, + .hw_params = chv3_dma_hw_params, + .prepare = chv3_dma_prepare, + .pointer = chv3_dma_pointer, + .ack = chv3_dma_ack, +}; + +static int chv3_i2s_probe(struct platform_device *pdev) +{ + struct chv3_i2s_dev *i2s; + int res; + int irq; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + i2s->iobase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(i2s->iobase)) + return PTR_ERR(i2s->iobase); + + i2s->iobase_irq = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(i2s->iobase_irq)) + return PTR_ERR(i2s->iobase_irq); + + i2s->tx_bytes_to_fetch = (chv3_i2s_rd(i2s, I2S_TX_IRQ_CONST) >> 8) & 0xffff; + + i2s->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, i2s); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENXIO; + res = devm_request_irq(i2s->dev, irq, chv3_i2s_isr, 0, "chv3-i2s", i2s); + if (res) + return res; + + res = devm_snd_soc_register_component(&pdev->dev, &chv3_i2s_comp, + &chv3_i2s_dai, 1); + if (res) { + dev_err(&pdev->dev, "couldn't register component: %d\n", res); + return res; + } + + return 0; +} + +static const struct of_device_id chv3_i2s_of_match[] = { + { .compatible = "google,chv3-i2s" }, + {}, +}; + +static struct platform_driver chv3_i2s_driver = { + .probe = chv3_i2s_probe, + .driver = { + .name = "chv3-i2s", + .of_match_table = chv3_i2s_of_match, + }, +}; + +module_platform_driver(chv3_i2s_driver); + +MODULE_AUTHOR("Pawel Anikiel <pan@semihalf.com>"); +MODULE_DESCRIPTION("Chameleon v3 I2S interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index d3973936426a..29d44c989e5f 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -15,7 +15,6 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/firmware.h> -#include <linux/pm_runtime.h> #include <linux/pm_qos.h> #include <linux/dmi.h> #include <linux/acpi.h> diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 4e039c7173d8..3fc2c9a6c44d 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -15,7 +15,6 @@ #include <linux/firmware.h> #include <linux/sched.h> #include <linux/delay.h> -#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index eea889001c24..bf4ba6bcc429 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -20,7 +20,6 @@ #include <linux/sched.h> #include <linux/firmware.h> #include <linux/dmaengine.h> -#include <linux/pm_runtime.h> #include <linux/pm_qos.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 5862fe968083..4058b4f80a0c 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -15,7 +15,6 @@ #include <linux/pci.h> #include <linux/fs.h> #include <linux/firmware.h> -#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/soc.h> #include <asm/platform_sst_audio.h> diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index ea1ef8a61fa6..862a19ae5429 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -15,7 +15,6 @@ #include <linux/firmware.h> #include <linux/sched.h> #include <linux/delay.h> -#include <linux/pm_runtime.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 8f0fd87bc866..bc3065c6ceda 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -28,13 +28,11 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); - if (!dl->name || !dl->cpus || !dl->codecs) + if (!dl->name || !dl->cpus) return -ENOMEM; dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); - dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy"); - dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai"); + dl->codecs = &asoc_dummy_dlc; if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index d5235c294c4c..fee80638cba2 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -254,7 +254,6 @@ static void hdmi_link_init(struct snd_soc_card *card, struct sof_card_private *ctx, struct snd_soc_acpi_mach *mach) { - struct snd_soc_dai_link *link; int i; if (mach->mach_params.common_hdmi_codec_drv && @@ -267,11 +266,8 @@ static void hdmi_link_init(struct snd_soc_card *card, * if HDMI is not enabled in kernel config, or * hdmi codec is not supported */ - for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) { - link = &card->dai_link[i]; - link->codecs[0].name = "snd-soc-dummy"; - link->codecs[0].dai_name = "snd-soc-dummy-dai"; - } + for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++) + card->dai_link[i].codecs[0] = asoc_dummy_dlc; } static int snd_ehl_rt5660_probe(struct platform_device *pdev) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 879ebba52832..a06e05154ae1 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -61,9 +61,6 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, }; -SND_SOC_DAILINK_DEF(dummy_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai"))); - static int skl_hda_card_late_probe(struct snd_soc_card *card) { return skl_hda_hdmi_jack_init(card); @@ -158,9 +155,8 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); if (!ctx->idisp_codec) { for (i = 0; i < IDISP_DAI_COUNT; i++) { - skl_hda_be_dai_links[i].codecs = dummy_codec; - skl_hda_be_dai_links[i].num_codecs = - ARRAY_SIZE(dummy_codec); + skl_hda_be_dai_links[i].codecs = &asoc_dummy_dlc; + skl_hda_be_dai_links[i].num_codecs = 1; } } } diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index e9d190cb13b0..e6695e77d594 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -296,13 +296,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component dummy_component[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - static int create_spk_amp_dai_links(struct device *dev, struct snd_soc_dai_link *links, struct snd_soc_dai_link_component *cpus, @@ -510,8 +503,8 @@ static int create_bt_offload_dai_links(struct device *dev, goto devm_err; links[*id].id = *id; - links[*id].codecs = dummy_component; - links[*id].num_codecs = ARRAY_SIZE(dummy_component); + links[*id].codecs = &asoc_dummy_dlc; + links[*id].num_codecs = 1; links[*id].platforms = platform_component; links[*id].num_platforms = ARRAY_SIZE(platform_component); diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index adf5852b2c9a..d6c38d8ea2ff 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -393,13 +393,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component dummy_component[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - static int sof_es8336_late_probe(struct snd_soc_card *card) { struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); @@ -572,8 +565,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!links[id].name) return NULL; links[id].id = id + hdmi_id_offset; - links[id].codecs = dummy_component; - links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].dpcm_capture = 1; diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 6794a0249a9a..4fc6e1c6aef3 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -346,13 +346,6 @@ static struct snd_soc_dai_link_component nau8318_components[] = { } }; -static struct snd_soc_dai_link_component dummy_component[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_codec, int ssp_amp, @@ -532,8 +525,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); if (!links[id].name) goto devm_err; - links[id].codecs = dummy_component; - links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].dpcm_playback = 1; @@ -681,6 +674,16 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_max98373_8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98373_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 5192e02b3cee..9f673ccf81b5 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -331,8 +331,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, devm_kasprintf(dev, GFP_KERNEL, "intel-hdmi-hifi%d", i); } else { - idisp_components[i - 1].name = "snd-soc-dummy"; - idisp_components[i - 1].dai_name = "snd-soc-dummy-dai"; + idisp_components[i - 1] = asoc_dummy_dlc; } if (!idisp_components[i - 1].dai_name) goto devm_err; diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 791a59c5f00d..7f4783592668 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -607,13 +607,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component dummy_component[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - #define IDISP_CODEC_MASK 0x4 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, @@ -745,8 +738,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!idisp_components[i - 1].dai_name) goto devm_err; } else { - idisp_components[i - 1].name = "snd-soc-dummy"; - idisp_components[i - 1].dai_name = "snd-soc-dummy-dai"; + idisp_components[i - 1] = asoc_dummy_dlc; } links[id].codecs = &idisp_components[i - 1]; @@ -841,8 +833,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); if (!links[id].name) goto devm_err; - links[id].codecs = dummy_component; - links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].dpcm_playback = 1; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6faf4a43eaf5..d16ceef702a7 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -192,6 +192,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD1), }, { + /* + * this entry covers HP Spectre x360 where the DMI information + * changed somehow + */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_BOARD_NAME, "8709"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOF_SDW_PCH_DMIC | + RT711_JD1), + }, + { /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ .callback = sof_sdw_quirk_cb, .matches = { @@ -413,7 +427,24 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .matches = { DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), }, - .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI), + .driver_data = (void *)(RT711_JD1), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"), + }, + .driver_data = (void *)(RT711_JD2_100K), + }, + /* LunarLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), + }, + .driver_data = (void *)(RT711_JD2_100K), }, {} }; @@ -902,17 +933,20 @@ static int create_codec_dai_name(struct device *dev, static int set_codec_init_func(struct snd_soc_card *card, const struct snd_soc_acpi_link_adr *link, struct snd_soc_dai_link *dai_links, - bool playback, int group_id) + bool playback, int group_id, int adr_index) { - int i; + int i = adr_index; do { /* * Initialize the codec. If codec is part of an aggregated * group (group_id>0), initialize all codecs belonging to * same group. + * The first link should start with link->adr_d[adr_index] + * because that is the device that we want to initialize and + * we should end immediately if it is not aggregated (group_id=0) */ - for (i = 0; i < link->num_adr; i++) { + for ( ; i < link->num_adr; i++) { int codec_index; codec_index = find_codec_info_part(link->adr_d[i].adr); @@ -928,9 +962,12 @@ static int set_codec_init_func(struct snd_soc_card *card, dai_links, &codec_info_list[codec_index], playback); + if (!group_id) + return 0; } + i = 0; link++; - } while (link->mask && group_id); + } while (link->mask); return 0; } @@ -1180,7 +1217,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, dai_links[*link_index].nonatomic = true; ret = set_codec_init_func(card, link, dai_links + (*link_index)++, - playback, group_id); + playback, group_id, adr_index); if (ret < 0) { dev_err(dev, "failed to init codec %d", codec_index); return ret; @@ -1488,8 +1525,7 @@ HDMI: if (!idisp_components[i].dai_name) return -ENOMEM; } else { - idisp_components[i].name = "snd-soc-dummy"; - idisp_components[i].dai_name = "snd-soc-dummy-dai"; + idisp_components[i] = asoc_dummy_dlc; } cpu_name = devm_kasprintf(dev, GFP_KERNEL, @@ -1514,21 +1550,13 @@ HDMI: if (!name) return -ENOMEM; - ssp_components = devm_kzalloc(dev, sizeof(*ssp_components), - GFP_KERNEL); - if (!ssp_components) - return -ENOMEM; - - ssp_components->name = "snd-soc-dummy"; - ssp_components->dai_name = "snd-soc-dummy-dai"; - cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); if (!cpu_name) return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; init_dai_link(dev, links + link_index, be_id, name, 1, 1, - cpus + cpu_id, 1, ssp_components, 1, NULL, NULL); + cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); } card->dai_link = links; diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index ffd9c583dab1..b33f720b3e6d 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -167,13 +167,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component dummy_component[] = { - { - .name = "snd-soc-dummy", - .dai_name = "snd-soc-dummy-dai", - } -}; - static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -233,8 +226,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!links[id].name) return NULL; links[id].id = id; - links[id].codecs = dummy_component; - links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].dpcm_capture = 1; @@ -331,8 +324,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!idisp_components[i - 1].dai_name) goto devm_err; } else { - idisp_components[i - 1].name = "snd-soc-dummy"; - idisp_components[i - 1].dai_name = "snd-soc-dummy-dai"; + idisp_components[i - 1] = asoc_dummy_dlc; } links[id].codecs = &idisp_components[i - 1]; @@ -360,8 +352,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); if (!links[id].name) goto devm_err; - links[id].codecs = dummy_component; - links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].dpcm_playback = 1; diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 41054cf09ec9..07aa37dd90e9 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -10,6 +10,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \ + soc-acpi-intel-lnl-match.o \ soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c new file mode 100644 index 000000000000..9f35b77deb11 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-lnl-match.c - tables and support for LNL ACPI enumeration. + * + * Copyright (c) 2023, Intel Corporation. All rights reserved. + * + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include "soc-acpi-intel-sdw-mockup-match.h" + +struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_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 rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_link_adr lnl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { + /* mockup tests need to be first */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg", + }, + { + .link_mask = BIT(0), + .links = lnl_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt711.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 7911c3af8071..8fd4d0db201e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -98,6 +98,33 @@ static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { + { + .adr = 0x000230025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { + { + .adr = 0x000331025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { + { + .adr = 0x000130025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = { /* Expected order: jack -> amp */ { @@ -122,6 +149,30 @@ static const struct snd_soc_acpi_link_adr mtl_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_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(rt1316_3_group1_adr), + .adr_d = rt1316_3_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt714_1_adr), + .adr_d = rt714_1_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { /* mockup tests need to be first */ @@ -144,6 +195,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = GENMASK(3, 0), + .links = mtl_3_in_1_sdca, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg", + }, + { .link_mask = BIT(0), .links = mtl_rvp, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 749d371a86ae..c61d654eb1e2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -303,6 +303,11 @@ static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { .codecs = {"MX98360A"}, }; +static const struct snd_soc_acpi_codecs rpl_max98373_amp = { + .num_codecs = 1, + .codecs = {"MX98373"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -311,6 +316,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .quirk_data = &rpl_max98360a_amp, .sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg", }, + { + .id = "10508825", + .drv_name = "rpl_max98373_8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_max98373_amp, + .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index d0f6c945d9ae..578af21769c9 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -375,6 +375,14 @@ static const struct i2s_soc_info jz4760_i2s_soc_info = { .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 3), }; +static const struct i2s_soc_info x1000_i2s_soc_info = { + .dai = &jz4740_i2s_dai, + .field_rx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 24, 27), + .field_tx_fifo_thresh = REG_FIELD(JZ_REG_AIC_CONF, 16, 20), + .field_i2sdiv_capture = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 8), + .field_i2sdiv_playback = REG_FIELD(JZ_REG_AIC_CLK_DIV, 0, 8), +}; + static struct snd_soc_dai_driver jz4770_i2s_dai = { .probe = jz4740_i2s_dai_probe, .playback = { @@ -486,6 +494,7 @@ static const struct of_device_id jz4740_of_matches[] = { { .compatible = "ingenic,jz4760-i2s", .data = &jz4760_i2s_soc_info }, { .compatible = "ingenic,jz4770-i2s", .data = &jz4770_i2s_soc_info }, { .compatible = "ingenic,jz4780-i2s", .data = &jz4780_i2s_soc_info }, + { .compatible = "ingenic,x1000-i2s", .data = &x1000_i2s_soc_info }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, jz4740_of_matches); diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-control.c b/sound/soc/mediatek/mt8186/mt8186-afe-control.c index d714e9641571..55edf6374578 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-control.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-control.c @@ -6,7 +6,6 @@ // Author: Jiaxin Yu <jiaxin.yu@mediatek.com> #include "mt8186-afe-common.h" -#include <linux/pm_runtime.h> enum { MTK_AFE_RATE_8K = 0, diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index cdf54d1eb50d..0432f9d89020 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -10,7 +10,6 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/of_device.h> -#include <linux/pm_runtime.h> #include <sound/jack.h> #include <sound/pcm_params.h> #include <sound/soc.h> diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c index 7538274641fd..9c11016f032c 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c @@ -12,7 +12,6 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/of_device.h> -#include <linux/pm_runtime.h> #include <sound/jack.h> #include <sound/pcm_params.h> #include <sound/rt5682.h> diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c index 743d6a162cb9..4c24d0b9e90d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c @@ -24,14 +24,19 @@ static const char *aud_clks[MT8188_CLK_NUM] = { [MT8188_CLK_APMIXED_APLL2] = "apll2", /* divider */ + [MT8188_CLK_TOP_APLL1_D4] = "apll1_d4", + [MT8188_CLK_TOP_APLL2_D4] = "apll2_d4", [MT8188_CLK_TOP_APLL12_DIV0] = "apll12_div0", [MT8188_CLK_TOP_APLL12_DIV1] = "apll12_div1", [MT8188_CLK_TOP_APLL12_DIV2] = "apll12_div2", [MT8188_CLK_TOP_APLL12_DIV3] = "apll12_div3", + [MT8188_CLK_TOP_APLL12_DIV4] = "apll12_div4", [MT8188_CLK_TOP_APLL12_DIV9] = "apll12_div9", /* mux */ [MT8188_CLK_TOP_A1SYS_HP_SEL] = "top_a1sys_hp", + [MT8188_CLK_TOP_A2SYS_SEL] = "top_a2sys", + [MT8188_CLK_TOP_AUD_IEC_SEL] = "top_aud_iec", [MT8188_CLK_TOP_AUD_INTBUS_SEL] = "top_aud_intbus", [MT8188_CLK_TOP_AUDIO_H_SEL] = "top_audio_h", [MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL] = "top_audio_local_bus", @@ -378,6 +383,19 @@ int mt8188_afe_get_default_mclk_source_by_rate(int rate) MT8188_MCK_SEL_APLL1 : MT8188_MCK_SEL_APLL2; } +int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8188_AUD_PLL1 : MT8188_AUD_PLL2; +} + +int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8188_AUD_PLL1; + + return MT8188_AUD_PLL2; +} + int mt8188_afe_init_clock(struct mtk_base_afe *afe) { struct mt8188_afe_private *afe_priv = afe->platform_priv; @@ -477,8 +495,8 @@ int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, if (clk && parent) { ret = clk_set_parent(clk, parent); if (ret) { - dev_dbg(afe->dev, "%s(), failed to set clk parent\n", - __func__); + dev_dbg(afe->dev, "%s(), failed to set clk parent %d\n", + __func__, ret); return ret; } } @@ -605,54 +623,132 @@ static int mt8188_afe_disable_afe_on(struct mtk_base_afe *afe) return 0; } -static int mt8188_afe_enable_timing_sys(struct mtk_base_afe *afe) +static int mt8188_afe_enable_a1sys(struct mtk_base_afe *afe) { struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; - mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); - mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); + if (ret) + return ret; - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); - mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); + return mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); +} + +static int mt8188_afe_disable_a1sys(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); return 0; } -static int mt8188_afe_disable_timing_sys(struct mtk_base_afe *afe) +static int mt8188_afe_enable_a2sys(struct mtk_base_afe *afe) { struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; - mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A1SYS]); - mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); + if (ret) + return ret; - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); - mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A1SYS_TIMING); + return mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); +} + +static int mt8188_afe_disable_a2sys(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_A2SYS_TIMING); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_A2SYS]); return 0; } -int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe) +int mt8188_apll1_enable(struct mtk_base_afe *afe) { - mt8188_afe_enable_timing_sys(afe); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int ret; - mt8188_afe_enable_afe_on(afe); + ret = mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + if (ret) + return ret; + + ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + if (ret) + goto err_clk_parent; - mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1); - mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2); + ret = mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL1); + if (ret) + goto err_apll_tuner; + + ret = mt8188_afe_enable_a1sys(afe); + if (ret) + goto err_a1sys; return 0; + +err_a1sys: + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1); +err_apll_tuner: + mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_XTAL_26M]); +err_clk_parent: + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); + + return ret; } -int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe) +int mt8188_apll1_disable(struct mtk_base_afe *afe) { - mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + + mt8188_afe_disable_a1sys(afe); mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL1); + mt8188_afe_set_clk_parent(afe, afe_priv->clk[MT8188_CLK_TOP_A1SYS_HP_SEL], + afe_priv->clk[MT8188_CLK_XTAL_26M]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_TOP_APLL1_D4]); - mt8188_afe_disable_afe_on(afe); + return 0; +} + +int mt8188_apll2_enable(struct mtk_base_afe *afe) +{ + int ret; - mt8188_afe_disable_timing_sys(afe); + ret = mt8188_afe_enable_apll_tuner(afe, MT8188_AUD_PLL2); + if (ret) + return ret; + ret = mt8188_afe_enable_a2sys(afe); + if (ret) + goto err_a2sys; + + return 0; +err_a2sys: + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); + + return ret; +} + +int mt8188_apll2_disable(struct mtk_base_afe *afe) +{ + mt8188_afe_disable_a2sys(afe); + mt8188_afe_disable_apll_tuner(afe, MT8188_AUD_PLL2); + return 0; +} + +int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe) +{ + mt8188_afe_enable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); + mt8188_afe_enable_afe_on(afe); + return 0; +} + +int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe) +{ + mt8188_afe_disable_afe_on(afe); + mt8188_afe_disable_top_cg(afe, MT8188_TOP_CG_26M_TIMING); return 0; } diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h index 084fdfb1d877..904505d10841 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h @@ -11,6 +11,10 @@ #ifndef _MT8188_AFE_CLK_H_ #define _MT8188_AFE_CLK_H_ +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" + enum { /* xtal */ MT8188_CLK_XTAL_26M, @@ -18,13 +22,18 @@ enum { MT8188_CLK_APMIXED_APLL1, MT8188_CLK_APMIXED_APLL2, /* divider */ + MT8188_CLK_TOP_APLL1_D4, + MT8188_CLK_TOP_APLL2_D4, MT8188_CLK_TOP_APLL12_DIV0, MT8188_CLK_TOP_APLL12_DIV1, MT8188_CLK_TOP_APLL12_DIV2, MT8188_CLK_TOP_APLL12_DIV3, + MT8188_CLK_TOP_APLL12_DIV4, MT8188_CLK_TOP_APLL12_DIV9, /* mux */ MT8188_CLK_TOP_A1SYS_HP_SEL, + MT8188_CLK_TOP_A2SYS_SEL, + MT8188_CLK_TOP_AUD_IEC_SEL, MT8188_CLK_TOP_AUD_INTBUS_SEL, MT8188_CLK_TOP_AUDIO_H_SEL, MT8188_CLK_TOP_AUDIO_LOCAL_BUS_SEL, @@ -99,6 +108,8 @@ struct mtk_base_afe; int mt8188_afe_get_mclk_source_clk_id(int sel); int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll); int mt8188_afe_get_default_mclk_source_by_rate(int rate); +int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name); int mt8188_afe_init_clock(struct mtk_base_afe *afe); void mt8188_afe_deinit_clock(void *priv); int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk); @@ -107,6 +118,10 @@ int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, unsigned int rate); int mt8188_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, struct clk *parent); +int mt8188_apll1_enable(struct mtk_base_afe *afe); +int mt8188_apll1_disable(struct mtk_base_afe *afe); +int mt8188_apll2_enable(struct mtk_base_afe *afe); +int mt8188_apll2_disable(struct mtk_base_afe *afe); int mt8188_afe_enable_main_clock(struct mtk_base_afe *afe); int mt8188_afe_disable_main_clock(struct mtk_base_afe *afe); int mt8188_afe_enable_reg_rw_clk(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index e5f9373bed56..c3fd32764da0 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -17,6 +17,7 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> +#include <linux/soc/mediatek/infracfg.h> #include <linux/reset.h> #include <sound/pcm_params.h> #include "mt8188-afe-common.h" @@ -1898,10 +1899,6 @@ static const struct snd_kcontrol_new mt8188_memif_controls[] = { MT8188_AFE_MEMIF_UL10), }; -static const struct snd_soc_component_driver mt8188_afe_pcm_dai_component = { - .name = "mt8188-afe-pcm-dai", -}; - static const struct mtk_base_memif_data memif_data[MT8188_AFE_MEMIF_NUM] = { [MT8188_AFE_MEMIF_DL2] = { .name = "DL2", @@ -3137,14 +3134,69 @@ static int mt8188_afe_parse_of(struct mtk_base_afe *afe, return 0; } +#define MT8188_DELAY_US 10 +#define MT8188_TIMEOUT_US USEC_PER_SEC + +static int bus_protect_enable(struct regmap *regmap) +{ + int ret; + u32 val; + u32 mask; + + val = 0; + mask = MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP1; + regmap_write(regmap, MT8188_TOP_AXI_PROT_EN_2_SET, mask); + + ret = regmap_read_poll_timeout(regmap, MT8188_TOP_AXI_PROT_EN_2_STA, + val, (val & mask) == mask, + MT8188_DELAY_US, MT8188_TIMEOUT_US); + if (ret) + return ret; + + val = 0; + mask = MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP2; + regmap_write(regmap, MT8188_TOP_AXI_PROT_EN_2_SET, mask); + + ret = regmap_read_poll_timeout(regmap, MT8188_TOP_AXI_PROT_EN_2_STA, + val, (val & mask) == mask, + MT8188_DELAY_US, MT8188_TIMEOUT_US); + return ret; +} + +static int bus_protect_disable(struct regmap *regmap) +{ + int ret; + u32 val; + u32 mask; + + val = 0; + mask = MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP2; + regmap_write(regmap, MT8188_TOP_AXI_PROT_EN_2_CLR, mask); + + ret = regmap_read_poll_timeout(regmap, MT8188_TOP_AXI_PROT_EN_2_STA, + val, !(val & mask), + MT8188_DELAY_US, MT8188_TIMEOUT_US); + if (ret) + return ret; + + val = 0; + mask = MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP1; + regmap_write(regmap, MT8188_TOP_AXI_PROT_EN_2_CLR, mask); + + ret = regmap_read_poll_timeout(regmap, MT8188_TOP_AXI_PROT_EN_2_STA, + val, !(val & mask), + MT8188_DELAY_US, MT8188_TIMEOUT_US); + return ret; +} + static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8188_afe_private *afe_priv; struct device *dev; - int i, irq_id, ret; - struct snd_soc_component *component; struct reset_control *rstc; + struct regmap *infra_ao; + int i, irq_id, ret; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); if (ret) @@ -3168,18 +3220,37 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(afe->base_addr), "AFE base_addr not found\n"); + infra_ao = syscon_regmap_lookup_by_phandle(dev->of_node, + "mediatek,infracfg"); + if (IS_ERR(infra_ao)) + return dev_err_probe(dev, PTR_ERR(infra_ao), + "%s() Cannot find infra_ao controller\n", + __func__); + /* reset controller to reset audio regs before regmap cache */ rstc = devm_reset_control_get_exclusive(dev, "audiosys"); if (IS_ERR(rstc)) return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n"); + ret = bus_protect_enable(infra_ao); + if (ret) { + dev_err(dev, "bus_protect_enable failed\n"); + return ret; + } + ret = reset_control_reset(rstc); if (ret) { dev_err(dev, "failed to trigger audio reset:%d\n", ret); return ret; } + ret = bus_protect_disable(infra_ao); + if (ret) { + dev_err(dev, "bus_protect_disable failed\n"); + return ret; + } + /* initial audio related clock */ ret = mt8188_afe_init_clock(afe); if (ret) @@ -3280,34 +3351,12 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) /* register component */ ret = devm_snd_soc_register_component(dev, &mt8188_afe_component, - NULL, 0); + afe->dai_drivers, afe->num_dai_drivers); if (ret) { dev_warn(dev, "err_platform\n"); goto err_pm_put; } - component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL); - if (!component) { - ret = -ENOMEM; - goto err_pm_put; - } - - ret = snd_soc_component_initialize(component, - &mt8188_afe_pcm_dai_component, - &pdev->dev); - if (ret) - goto err_pm_put; -#ifdef CONFIG_DEBUG_FS - component->debugfs_prefix = "pcm"; -#endif - ret = snd_soc_add_component(component, - afe->dai_drivers, - afe->num_dai_drivers); - if (ret) { - dev_warn(dev, "err_add_component\n"); - goto err_pm_put; - } - mt8188_afe_init_registers(afe); pm_runtime_put_sync(&pdev->dev); @@ -3323,11 +3372,6 @@ err_pm_put: return ret; } -static void mt8188_afe_pcm_dev_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); -} - static const struct of_device_id mt8188_afe_pcm_dt_match[] = { { .compatible = "mediatek,mt8188-afe", }, {}, @@ -3346,7 +3390,6 @@ static struct platform_driver mt8188_afe_pcm_driver = { .pm = &mt8188_afe_pm_ops, }, .probe = mt8188_afe_pcm_dev_probe, - .remove_new = mt8188_afe_pcm_dev_remove, }; module_platform_driver(mt8188_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c index d71696901553..fed9f927e623 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c @@ -18,7 +18,6 @@ #define ADDA_HIRES_THRES 48000 enum { - SUPPLY_SEQ_CLOCK_SEL, SUPPLY_SEQ_ADDA_DL_ON, SUPPLY_SEQ_ADDA_MTKAIF_CFG, SUPPLY_SEQ_ADDA_UL_ON, @@ -242,34 +241,6 @@ static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, return 0; } -static int mtk_audio_hires_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct clk *clk = afe_priv->clk[MT8188_CLK_TOP_AUDIO_H_SEL]; - struct clk *clk_parent; - - dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", - __func__, w->name, event); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - clk_parent = afe_priv->clk[MT8188_CLK_APMIXED_APLL1]; - break; - case SND_SOC_DAPM_POST_PMD: - clk_parent = afe_priv->clk[MT8188_CLK_XTAL_26M]; - break; - default: - return 0; - } - mt8188_afe_set_clk_parent(afe, clk, clk_parent); - - return 0; -} - static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { @@ -364,12 +335,6 @@ static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { mtk_adda_ul_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY_S("AUDIO_HIRES", SUPPLY_SEQ_CLOCK_SEL, - SND_SOC_NOPM, - 0, 0, - mtk_audio_hires_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, SND_SOC_NOPM, 0, 0, @@ -397,7 +362,6 @@ static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"}, {"ADDA Capture", NULL, "aud_adc"}, {"ADDA Capture", NULL, "aud_adc_hires", mtk_afe_adc_hires_connect}, - {"aud_adc_hires", NULL, "AUDIO_HIRES"}, {"I168", NULL, "ADDA Capture"}, {"I169", NULL, "ADDA Capture"}, @@ -406,7 +370,6 @@ static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { {"ADDA Playback", NULL, "ADDA Playback Enable"}, {"ADDA Playback", NULL, "aud_dac"}, {"ADDA Playback", NULL, "aud_dac_hires", mtk_afe_dac_hires_connect}, - {"aud_dac_hires", NULL, "AUDIO_HIRES"}, {"DL_GAIN", NULL, "O176"}, {"DL_GAIN", NULL, "O177"}, diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c index 7a37752d4244..16440dd0a89c 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c @@ -22,6 +22,14 @@ #define ENUM_TO_STR(x) #x enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_ETDM_MCLK, + SUPPLY_SEQ_ETDM_CG, + SUPPLY_SEQ_DPTX_EN, + SUPPLY_SEQ_ETDM_EN, +}; + +enum { MTK_DAI_ETDM_FORMAT_I2S = 0, MTK_DAI_ETDM_FORMAT_LJ, MTK_DAI_ETDM_FORMAT_RJ, @@ -84,11 +92,11 @@ struct mtk_dai_etdm_rate { }; struct mtk_dai_etdm_priv { - unsigned int clock_mode; unsigned int data_mode; bool slave_mode; bool lrck_inv; bool bck_inv; + unsigned int rate; unsigned int format; unsigned int slots; unsigned int lrck_width; @@ -100,8 +108,6 @@ struct mtk_dai_etdm_priv { unsigned int cowork_slv_count; int cowork_slv_id[MT8188_AFE_IO_ETDM_NUM - 1]; //dai_id bool in_disable_ch[MT8188_ETDM_MAX_CHANNELS]; - unsigned int en_ref_cnt; - bool is_prepared; }; static const struct mtk_dai_etdm_rate mt8188_etdm_rates[] = { @@ -345,13 +351,85 @@ static int mtk_dai_etdm_get_clkdiv_id_by_dai_id(int dai_id) } } +static int get_etdm_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (!strncmp(name, "ETDM1_IN", strlen("ETDM1_IN"))) + return MT8188_AFE_IO_ETDM1_IN; + else if (!strncmp(name, "ETDM2_IN", strlen("ETDM2_IN"))) + return MT8188_AFE_IO_ETDM2_IN; + else if (!strncmp(name, "ETDM1_OUT", strlen("ETDM1_OUT"))) + return MT8188_AFE_IO_ETDM1_OUT; + else if (!strncmp(name, "ETDM2_OUT", strlen("ETDM2_OUT"))) + return MT8188_AFE_IO_ETDM2_OUT; + else if (!strncmp(name, "ETDM3_OUT", strlen("ETDM3_OUT"))) + return MT8188_AFE_IO_ETDM3_OUT; + else if (!strncmp(name, "DPTX", strlen("DPTX"))) + return MT8188_AFE_IO_ETDM3_OUT; + else + return -EINVAL; +} + +static struct mtk_dai_etdm_priv *get_etdm_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_etdm_id_by_name(afe, name); + + if (dai_id < MT8188_AFE_IO_ETDM_START || + dai_id >= MT8188_AFE_IO_ETDM_END) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id) { struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data; + struct etdm_con_reg etdm_reg; + unsigned int val = 0; + unsigned int mask; + int clkmux_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); + int apll_clk_id; + int apll; + int ret; - if (clkdiv_id < 0) + if (!is_valid_etdm_dai(dai_id)) return -EINVAL; + etdm_data = afe_priv->dai_priv[dai_id]; + + apll = etdm_data->mclk_apll; + apll_clk_id = mt8188_afe_get_mclk_source_clk_id(apll); + + if (clkmux_id < 0 || clkdiv_id < 0) + return -EINVAL; + + if (apll_clk_id < 0) + return apll_clk_id; + + ret = get_etdm_reg(dai_id, &etdm_reg); + if (ret < 0) + return ret; + + mask = ETDM_CON1_MCLK_OUTPUT; + if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT) + val = ETDM_CON1_MCLK_OUTPUT; + regmap_update_bits(afe->regmap, etdm_reg.con1, mask, val); + + /* enable parent clock before select apll*/ + mt8188_afe_enable_clk(afe, afe_priv->clk[clkmux_id]); + + /* select apll */ + ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[clkmux_id], + afe_priv->clk[apll_clk_id]); + if (ret) + return ret; + + /* set rate */ + ret = mt8188_afe_set_clk_rate(afe, afe_priv->clk[clkdiv_id], + etdm_data->mclk_freq); mt8188_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]); @@ -361,12 +439,275 @@ static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id) static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_id) { struct mt8188_afe_private *afe_priv = afe->platform_priv; + int clkmux_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); - if (clkdiv_id < 0) + if (clkmux_id < 0 || clkdiv_id < 0) return -EINVAL; mt8188_afe_disable_clk(afe, afe_priv->clk[clkdiv_id]); + mt8188_afe_disable_clk(afe, afe_priv->clk[clkmux_id]); + + return 0; +} + +static int mtk_afe_etdm_apll_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_dai_etdm_priv *etdm_priv; + int cur_apll; + int need_apll; + + etdm_priv = get_etdm_priv_by_name(afe, w->name); + if (!etdm_priv) { + dev_dbg(afe->dev, "etdm_priv == NULL\n"); + return 0; + } + + cur_apll = mt8188_get_apll_by_name(afe, source->name); + need_apll = mt8188_get_apll_by_rate(afe, etdm_priv->rate); + + return (need_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_mclk_apll_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_dai_etdm_priv *etdm_priv; + int cur_apll; + + etdm_priv = get_etdm_priv_by_name(afe, w->name); + + cur_apll = mt8188_get_apll_by_name(afe, source->name); + + return (etdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static int mtk_etdm_mclk_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_priv; + int mclk_id; + + mclk_id = get_etdm_id_by_name(afe, source->name); + if (mclk_id < 0) { + dev_dbg(afe->dev, "mclk_id < 0\n"); + return 0; + } + + etdm_priv = get_etdm_priv_by_name(afe, w->name); + if (!etdm_priv) { + dev_dbg(afe->dev, "etdm_priv == NULL\n"); + return 0; + } + + if (get_etdm_id_by_name(afe, sink->name) == mclk_id) + return !!(etdm_priv->mclk_freq > 0); + + if (etdm_priv->cowork_source_id == mclk_id) { + etdm_priv = afe_priv->dai_priv[mclk_id]; + return !!(etdm_priv->mclk_freq > 0); + } + + return 0; +} + +static int mtk_etdm_cowork_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_priv; + int source_id; + int i; + + source_id = get_etdm_id_by_name(afe, source->name); + if (source_id < 0) { + dev_dbg(afe->dev, "%s() source_id < 0\n", __func__); + return 0; + } + + etdm_priv = get_etdm_priv_by_name(afe, w->name); + if (!etdm_priv) { + dev_dbg(afe->dev, "%s() etdm_priv == NULL\n", __func__); + return 0; + } + + if (etdm_priv->cowork_source_id != COWORK_ETDM_NONE) { + if (etdm_priv->cowork_source_id == source_id) + return 1; + + etdm_priv = afe_priv->dai_priv[etdm_priv->cowork_source_id]; + for (i = 0; i < etdm_priv->cowork_slv_count; i++) { + if (etdm_priv->cowork_slv_id[i] == source_id) + return 1; + } + } else { + for (i = 0; i < etdm_priv->cowork_slv_count; i++) { + if (etdm_priv->cowork_slv_id[i] == source_id) + return 1; + } + } + + return 0; +} + +static int mtk_apll_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8188_apll1_enable(afe); + else + mt8188_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8188_apll1_disable(afe); + else + mt8188_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int mtk_etdm_mclk_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + int mclk_id = get_etdm_id_by_name(afe, w->name); + + if (mclk_id < 0) { + dev_dbg(afe->dev, "%s() mclk_id < 0\n", __func__); + return 0; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mtk_dai_etdm_enable_mclk(afe, mclk_id); + break; + case SND_SOC_DAPM_POST_PMD: + mtk_dai_etdm_disable_mclk(afe, mclk_id); + break; + default: + break; + } + + return 0; +} + +static int mtk_dptx_mclk_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mtk_dai_etdm_enable_mclk(afe, MT8188_AFE_IO_DPTX); + break; + case SND_SOC_DAPM_POST_PMD: + mtk_dai_etdm_disable_mclk(afe, MT8188_AFE_IO_DPTX); + break; + default: + break; + } + + return 0; +} + +static int mtk_etdm_cg_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + int etdm_id; + int cg_id; + + etdm_id = get_etdm_id_by_name(afe, w->name); + if (etdm_id < 0) { + dev_dbg(afe->dev, "%s() etdm_id < 0\n", __func__); + return 0; + } + + cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(etdm_id); + if (cg_id < 0) { + dev_dbg(afe->dev, "%s() cg_id < 0\n", __func__); + return 0; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]); + break; + case SND_SOC_DAPM_POST_PMD: + mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]); + break; + default: + break; + } + + return 0; +} + +static int mtk_etdm3_cg_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 mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_HDMI_OUT]); + break; + case SND_SOC_DAPM_POST_PMD: + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_HDMI_OUT]); + break; + default: + break; + } return 0; } @@ -906,11 +1247,181 @@ static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, &hdmi_ch7_mux_control), + /* mclk en */ + SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_MCLK", SUPPLY_SEQ_ETDM_MCLK, + SND_SOC_NOPM, 0, 0, + mtk_etdm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_MCLK", SUPPLY_SEQ_ETDM_MCLK, + SND_SOC_NOPM, 0, 0, + mtk_etdm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_MCLK", SUPPLY_SEQ_ETDM_MCLK, + SND_SOC_NOPM, 0, 0, + mtk_etdm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_MCLK", SUPPLY_SEQ_ETDM_MCLK, + SND_SOC_NOPM, 0, 0, + mtk_etdm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("DPTX_MCLK", SUPPLY_SEQ_ETDM_MCLK, + SND_SOC_NOPM, 0, 0, + mtk_dptx_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* cg */ + SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_CG", SUPPLY_SEQ_ETDM_CG, + SND_SOC_NOPM, 0, 0, + mtk_etdm_cg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_CG", SUPPLY_SEQ_ETDM_CG, + SND_SOC_NOPM, 0, 0, + mtk_etdm_cg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_CG", SUPPLY_SEQ_ETDM_CG, + SND_SOC_NOPM, 0, 0, + mtk_etdm_cg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_CG", SUPPLY_SEQ_ETDM_CG, + SND_SOC_NOPM, 0, 0, + mtk_etdm_cg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ETDM3_OUT_CG", SUPPLY_SEQ_ETDM_CG, + SND_SOC_NOPM, 0, 0, + mtk_etdm3_cg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* en */ + SND_SOC_DAPM_SUPPLY_S("ETDM1_IN_EN", SUPPLY_SEQ_ETDM_EN, + ETDM_IN1_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ETDM2_IN_EN", SUPPLY_SEQ_ETDM_EN, + ETDM_IN2_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ETDM1_OUT_EN", SUPPLY_SEQ_ETDM_EN, + ETDM_OUT1_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ETDM2_OUT_EN", SUPPLY_SEQ_ETDM_EN, + ETDM_OUT2_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ETDM3_OUT_EN", SUPPLY_SEQ_ETDM_EN, + ETDM_OUT3_CON0, ETDM_CON0_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DPTX_EN", SUPPLY_SEQ_DPTX_EN, + AFE_DPTX_CON, AFE_DPTX_CON_ON_SHIFT, 0, NULL, 0), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("ETDM_INPUT"), SND_SOC_DAPM_OUTPUT("ETDM_OUTPUT"), }; static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { + /* mclk */ + {"ETDM1_IN", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_IN", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_IN", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_IN", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, + + {"ETDM2_IN", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_IN", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_IN", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_IN", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, + + {"ETDM1_OUT", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_OUT", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_OUT", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, + {"ETDM1_OUT", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, + + {"ETDM2_OUT", NULL, "ETDM1_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_OUT", NULL, "ETDM2_IN_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_OUT", NULL, "ETDM1_OUT_MCLK", mtk_etdm_mclk_connect}, + {"ETDM2_OUT", NULL, "ETDM2_OUT_MCLK", mtk_etdm_mclk_connect}, + + {"DPTX", NULL, "DPTX_MCLK"}, + + {"ETDM1_IN_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {"ETDM1_IN_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + {"ETDM2_IN_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {"ETDM2_IN_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + {"ETDM1_OUT_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {"ETDM1_OUT_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + {"ETDM2_OUT_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {"ETDM2_OUT_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + {"DPTX_MCLK", NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {"DPTX_MCLK", NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* cg */ + {"ETDM1_IN", NULL, "ETDM1_IN_CG"}, + {"ETDM1_IN", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM1_IN", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, + {"ETDM1_IN", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, + + {"ETDM2_IN", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM2_IN", NULL, "ETDM2_IN_CG"}, + {"ETDM2_IN", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, + {"ETDM2_IN", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, + + {"ETDM1_OUT", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM1_OUT", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM1_OUT", NULL, "ETDM1_OUT_CG"}, + {"ETDM1_OUT", NULL, "ETDM2_OUT_CG", mtk_etdm_cowork_connect}, + + {"ETDM2_OUT", NULL, "ETDM1_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM2_IN_CG", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM1_OUT_CG", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM2_OUT_CG"}, + + {"ETDM3_OUT", NULL, "ETDM3_OUT_CG"}, + {"DPTX", NULL, "ETDM3_OUT_CG"}, + + /* en */ + {"ETDM1_IN", NULL, "ETDM1_IN_EN"}, + {"ETDM1_IN", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM1_IN", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, + {"ETDM1_IN", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, + + {"ETDM2_IN", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM2_IN", NULL, "ETDM2_IN_EN"}, + {"ETDM2_IN", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, + {"ETDM2_IN", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, + + {"ETDM1_OUT", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM1_OUT", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM1_OUT", NULL, "ETDM1_OUT_EN"}, + {"ETDM1_OUT", NULL, "ETDM2_OUT_EN", mtk_etdm_cowork_connect}, + + {"ETDM2_OUT", NULL, "ETDM1_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM2_IN_EN", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM1_OUT_EN", mtk_etdm_cowork_connect}, + {"ETDM2_OUT", NULL, "ETDM2_OUT_EN"}, + + {"ETDM3_OUT", NULL, "ETDM3_OUT_EN"}, + {"DPTX", NULL, "ETDM3_OUT_EN"}, + {"DPTX", NULL, "DPTX_EN"}, + + {"ETDM1_IN_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, + {"ETDM1_IN_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, + + {"ETDM2_IN_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, + {"ETDM2_IN_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, + + {"ETDM1_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, + {"ETDM1_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, + + {"ETDM2_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, + {"ETDM2_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, + + {"ETDM3_OUT_EN", NULL, APLL1_W_NAME, mtk_afe_etdm_apll_connect}, + {"ETDM3_OUT_EN", NULL, APLL2_W_NAME, mtk_afe_etdm_apll_connect}, + {"I012", NULL, "ETDM2_IN"}, {"I013", NULL, "ETDM2_IN"}, {"I014", NULL, "ETDM2_IN"}, @@ -1163,64 +1674,6 @@ static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { {"ETDM2_IN", NULL, "ETDM_INPUT"}, }; -static int mt8188_afe_enable_etdm(struct mtk_base_afe *afe, int dai_id) -{ - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data; - struct etdm_con_reg etdm_reg; - unsigned long flags; - int ret = 0; - - if (!is_valid_etdm_dai(dai_id)) - return -EINVAL; - etdm_data = afe_priv->dai_priv[dai_id]; - - dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt); - spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); - etdm_data->en_ref_cnt++; - if (etdm_data->en_ref_cnt == 1) { - ret = get_etdm_reg(dai_id, &etdm_reg); - if (ret < 0) - goto out; - - regmap_set_bits(afe->regmap, etdm_reg.con0, ETDM_CON0_EN); - } - -out: - spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); - return ret; -} - -static int mt8188_afe_disable_etdm(struct mtk_base_afe *afe, int dai_id) -{ - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data; - struct etdm_con_reg etdm_reg; - unsigned long flags; - int ret = 0; - - if (!is_valid_etdm_dai(dai_id)) - return -EINVAL; - etdm_data = afe_priv->dai_priv[dai_id]; - - dev_dbg(afe->dev, "%s [%d]%d\n", __func__, dai_id, etdm_data->en_ref_cnt); - spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); - if (etdm_data->en_ref_cnt > 0) { - etdm_data->en_ref_cnt--; - if (etdm_data->en_ref_cnt == 0) { - ret = get_etdm_reg(dai_id, &etdm_reg); - if (ret < 0) - goto out; - regmap_clear_bits(afe->regmap, etdm_reg.con0, - ETDM_CON0_EN); - } - } - -out: - spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); - return ret; -} - static int etdm_cowork_slv_sel(int id, int slave_mode) { if (slave_mode) { @@ -1408,121 +1861,6 @@ static int mt8188_etdm_sync_mode_configure(struct mtk_base_afe *afe, int dai_id) } /* dai ops */ -static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *mst_etdm_data; - int mst_dai_id; - int slv_dai_id; - int cg_id; - int i; - - if (is_cowork_mode(dai)) { - mst_dai_id = get_etdm_cowork_master_id(dai); - if (!is_valid_etdm_dai(mst_dai_id)) - return -EINVAL; - mtk_dai_etdm_enable_mclk(afe, mst_dai_id); - - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id); - if (cg_id >= 0) - mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]); - - mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; - - for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { - slv_dai_id = mst_etdm_data->cowork_slv_id[i]; - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id); - if (cg_id >= 0) - mt8188_afe_enable_clk(afe, - afe_priv->clk[cg_id]); - } - } else { - mtk_dai_etdm_enable_mclk(afe, dai->id); - - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id); - if (cg_id >= 0) - mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]); - } - - return 0; -} - -static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *mst_etdm_data; - int mst_dai_id; - int slv_dai_id; - int cg_id; - int ret; - int i; - - if (!is_valid_etdm_dai(dai->id)) - return; - mst_etdm_data = afe_priv->dai_priv[dai->id]; - - dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id, - mst_etdm_data->is_prepared); - - if (mst_etdm_data->is_prepared) { - mst_etdm_data->is_prepared = false; - - if (is_cowork_mode(dai)) { - mst_dai_id = get_etdm_cowork_master_id(dai); - if (!is_valid_etdm_dai(mst_dai_id)) - return; - mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; - - ret = mt8188_afe_disable_etdm(afe, mst_dai_id); - if (ret) - dev_dbg(afe->dev, "%s disable %d failed\n", - __func__, mst_dai_id); - - for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { - slv_dai_id = mst_etdm_data->cowork_slv_id[i]; - ret = mt8188_afe_disable_etdm(afe, slv_dai_id); - if (ret) - dev_dbg(afe->dev, "%s disable %d failed\n", - __func__, slv_dai_id); - } - } else { - ret = mt8188_afe_disable_etdm(afe, dai->id); - if (ret) - dev_dbg(afe->dev, "%s disable %d failed\n", - __func__, dai->id); - } - } - - if (is_cowork_mode(dai)) { - mst_dai_id = get_etdm_cowork_master_id(dai); - if (!is_valid_etdm_dai(mst_dai_id)) - return; - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id); - if (cg_id >= 0) - mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]); - - mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; - for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { - slv_dai_id = mst_etdm_data->cowork_slv_id[i]; - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id); - if (cg_id >= 0) - mt8188_afe_disable_clk(afe, - afe_priv->clk[cg_id]); - } - mtk_dai_etdm_disable_mclk(afe, mst_dai_id); - } else { - cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id); - if (cg_id >= 0) - mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]); - - mtk_dai_etdm_disable_mclk(afe, dai->id); - } -} - static int mtk_dai_etdm_fifo_mode(struct mtk_base_afe *afe, int dai_id, unsigned int rate) { @@ -1759,60 +2097,6 @@ static int mtk_dai_etdm_out_configure(struct mtk_base_afe *afe, return 0; } -static int mtk_dai_etdm_mclk_configure(struct mtk_base_afe *afe, int dai_id) -{ - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data; - struct etdm_con_reg etdm_reg; - int clk_id = mtk_dai_etdm_get_clk_id_by_dai_id(dai_id); - int clkdiv_id = mtk_dai_etdm_get_clkdiv_id_by_dai_id(dai_id); - int apll_clk_id; - int apll; - int ret; - - if (clk_id < 0 || clkdiv_id < 0) - return -EINVAL; - - if (!is_valid_etdm_dai(dai_id)) - return -EINVAL; - etdm_data = afe_priv->dai_priv[dai_id]; - - ret = get_etdm_reg(dai_id, &etdm_reg); - if (ret < 0) - return ret; - - if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT) - regmap_set_bits(afe->regmap, etdm_reg.con1, - ETDM_CON1_MCLK_OUTPUT); - else - regmap_clear_bits(afe->regmap, etdm_reg.con1, - ETDM_CON1_MCLK_OUTPUT); - - if (etdm_data->mclk_freq) { - apll = etdm_data->mclk_apll; - apll_clk_id = mt8188_afe_get_mclk_source_clk_id(apll); - if (apll_clk_id < 0) - return apll_clk_id; - - /* select apll */ - ret = mt8188_afe_set_clk_parent(afe, afe_priv->clk[clk_id], - afe_priv->clk[apll_clk_id]); - if (ret) - return ret; - - /* set rate */ - ret = mt8188_afe_set_clk_rate(afe, afe_priv->clk[clkdiv_id], - etdm_data->mclk_freq); - if (ret) - return ret; - } else { - if (etdm_data->mclk_dir == SND_SOC_CLOCK_OUT) - dev_dbg(afe->dev, "%s mclk freq = 0\n", __func__); - } - - return 0; -} - static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, unsigned int rate, unsigned int channels, @@ -1834,15 +2118,16 @@ static int mtk_dai_etdm_configure(struct mtk_base_afe *afe, return -EINVAL; etdm_data = afe_priv->dai_priv[dai_id]; slave_mode = etdm_data->slave_mode; + etdm_data->rate = rate; ret = get_etdm_reg(dai_id, &etdm_reg); if (ret < 0) return ret; - dev_dbg(afe->dev, "%s fmt %u data %u lrck %d-%u bck %d, clock %u slv %u\n", + dev_dbg(afe->dev, "%s fmt %u data %u lrck %d-%u bck %d, slv %u\n", __func__, etdm_data->format, etdm_data->data_mode, etdm_data->lrck_inv, etdm_data->lrck_width, etdm_data->bck_inv, - etdm_data->clock_mode, etdm_data->slave_mode); + etdm_data->slave_mode); dev_dbg(afe->dev, "%s rate %u channels %u bitwidth %u, id %d\n", __func__, rate, channels, bit_width, dai_id); @@ -1909,16 +2194,15 @@ static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, if (!is_valid_etdm_dai(mst_dai_id)) return -EINVAL; - ret = mtk_dai_etdm_mclk_configure(afe, mst_dai_id); - if (ret) - return ret; + mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; + if (mst_etdm_data->slots) + channels = mst_etdm_data->slots; ret = mtk_dai_etdm_configure(afe, rate, channels, bit_width, mst_dai_id); if (ret) return ret; - mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { slv_dai_id = mst_etdm_data->cowork_slv_id[i]; ret = mtk_dai_etdm_configure(afe, rate, channels, @@ -1931,9 +2215,11 @@ static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, return ret; } } else { - ret = mtk_dai_etdm_mclk_configure(afe, dai->id); - if (ret) - return ret; + if (!is_valid_etdm_dai(dai->id)) + return -EINVAL; + mst_etdm_data = afe_priv->dai_priv[dai->id]; + if (mst_etdm_data->slots) + channels = mst_etdm_data->slots; ret = mtk_dai_etdm_configure(afe, rate, channels, bit_width, dai->id); @@ -1944,66 +2230,6 @@ static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int mtk_dai_etdm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *mst_etdm_data; - int mst_dai_id; - int slv_dai_id; - int ret; - int i; - - if (!is_valid_etdm_dai(dai->id)) - return -EINVAL; - mst_etdm_data = afe_priv->dai_priv[dai->id]; - - dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id, - mst_etdm_data->is_prepared); - - if (mst_etdm_data->is_prepared) - return 0; - - mst_etdm_data->is_prepared = true; - - if (is_cowork_mode(dai)) { - mst_dai_id = get_etdm_cowork_master_id(dai); - if (!is_valid_etdm_dai(mst_dai_id)) - return -EINVAL; - mst_etdm_data = afe_priv->dai_priv[mst_dai_id]; - - for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) { - slv_dai_id = mst_etdm_data->cowork_slv_id[i]; - ret = mt8188_afe_enable_etdm(afe, slv_dai_id); - if (ret) { - dev_dbg(afe->dev, "%s enable %d failed\n", - __func__, slv_dai_id); - - return ret; - } - } - - ret = mt8188_afe_enable_etdm(afe, mst_dai_id); - if (ret) { - dev_dbg(afe->dev, "%s enable %d failed\n", - __func__, mst_dai_id); - - return ret; - } - } else { - ret = mt8188_afe_enable_etdm(afe, dai->id); - if (ret) { - dev_dbg(afe->dev, "%s enable %d failed\n", - __func__, dai->id); - - return ret; - } - } - - return 0; -} - static int mtk_dai_etdm_cal_mclk(struct mtk_base_afe *afe, int freq, int dai_id) { struct mt8188_afe_private *afe_priv = afe->platform_priv; @@ -2073,10 +2299,16 @@ static int mtk_dai_etdm_set_tdm_slot(struct snd_soc_dai *dai, struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8188_afe_private *afe_priv = afe->platform_priv; struct mtk_dai_etdm_priv *etdm_data; + int dai_id; - if (!is_valid_etdm_dai(dai->id)) + if (is_cowork_mode(dai)) + dai_id = get_etdm_cowork_master_id(dai); + else + dai_id = dai->id; + + if (!is_valid_etdm_dai(dai_id)) return -EINVAL; - etdm_data = afe_priv->dai_priv[dai->id]; + etdm_data = afe_priv->dai_priv[dai_id]; dev_dbg(dai->dev, "%s id %d slot_width %d\n", __func__, dai->id, slot_width); @@ -2151,53 +2383,6 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int mtk_dai_hdmitx_dptx_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id); - - if (cg_id >= 0) - mt8188_afe_enable_clk(afe, afe_priv->clk[cg_id]); - - mtk_dai_etdm_enable_mclk(afe, dai->id); - - return 0; -} - -static void mtk_dai_hdmitx_dptx_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id); - struct mtk_dai_etdm_priv *etdm_data; - int ret; - - if (!is_valid_etdm_dai(dai->id)) - return; - etdm_data = afe_priv->dai_priv[dai->id]; - - if (etdm_data->is_prepared) { - etdm_data->is_prepared = false; - /* disable etdm_out3 */ - ret = mt8188_afe_disable_etdm(afe, dai->id); - if (ret) - dev_dbg(afe->dev, "%s disable failed\n", __func__); - - /* disable dptx interface */ - if (dai->id == MT8188_AFE_IO_DPTX) - regmap_clear_bits(afe->regmap, AFE_DPTX_CON, - AFE_DPTX_CON_ON); - } - - mtk_dai_etdm_disable_mclk(afe, dai->id); - - if (cg_id >= 0) - mt8188_afe_disable_clk(afe, afe_priv->clk[cg_id]); -} - static unsigned int mtk_dai_get_dptx_ch_en(unsigned int channel) { switch (channel) { @@ -2265,42 +2450,11 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN; } - ret = mtk_dai_etdm_mclk_configure(afe, dai->id); - if (ret) - return ret; - ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); return ret; } -static int mtk_dai_hdmitx_dptx_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); - struct mt8188_afe_private *afe_priv = afe->platform_priv; - struct mtk_dai_etdm_priv *etdm_data; - - if (!is_valid_etdm_dai(dai->id)) - return -EINVAL; - etdm_data = afe_priv->dai_priv[dai->id]; - - dev_dbg(afe->dev, "%s(), dai id %d, prepared %d\n", __func__, dai->id, - etdm_data->is_prepared); - - if (etdm_data->is_prepared) - return 0; - - etdm_data->is_prepared = true; - - /* enable dptx interface */ - if (dai->id == MT8188_AFE_IO_DPTX) - regmap_set_bits(afe->regmap, AFE_DPTX_CON, AFE_DPTX_CON_ON); - - /* enable etdm_out3 */ - return mt8188_afe_enable_etdm(afe, dai->id); -} - static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, @@ -2322,20 +2476,14 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { - .startup = mtk_dai_etdm_startup, - .shutdown = mtk_dai_etdm_shutdown, .hw_params = mtk_dai_etdm_hw_params, - .prepare = mtk_dai_etdm_prepare, .set_sysclk = mtk_dai_etdm_set_sysclk, .set_fmt = mtk_dai_etdm_set_fmt, .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, }; static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { - .startup = mtk_dai_hdmitx_dptx_startup, - .shutdown = mtk_dai_hdmitx_dptx_shutdown, .hw_params = mtk_dai_hdmitx_dptx_hw_params, - .prepare = mtk_dai_hdmitx_dptx_prepare, .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, .set_fmt = mtk_dai_etdm_set_fmt, }; diff --git a/sound/soc/mediatek/mt8188/mt8188-reg.h b/sound/soc/mediatek/mt8188/mt8188-reg.h index 51cd1a83dd9d..bdd885419ff3 100644 --- a/sound/soc/mediatek/mt8188/mt8188-reg.h +++ b/sound/soc/mediatek/mt8188/mt8188-reg.h @@ -3007,6 +3007,7 @@ #define ETDM_CON0_SLAVE_MODE BIT(5) #define ETDM_CON0_SYNC_MODE BIT(1) #define ETDM_CON0_EN BIT(0) +#define ETDM_CON0_EN_SHIFT 0 #define ETDM_OUT_CON0_RELATCH_DOMAIN_MASK GENMASK(29, 28) @@ -3108,6 +3109,7 @@ #define AFE_DPTX_CON_CH_NUM_8CH (0x1 << 1) #define AFE_DPTX_CON_CH_NUM_MASK BIT(1) #define AFE_DPTX_CON_ON BIT(0) +#define AFE_DPTX_CON_ON_SHIFT 0 /* AFE_ADDA_DL_SRC2_CON0 */ #define DL_2_INPUT_MODE_CTL_MASK GENMASK(31, 28) diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-control.c b/sound/soc/mediatek/mt8192/mt8192-afe-control.c index 9163e05e54e1..d01b62e10088 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-control.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-control.c @@ -6,8 +6,6 @@ // Author: Shane Chien <shane.chien@mediatek.com> // -#include <linux/pm_runtime.h> - #include "mt8192-afe-common.h" enum { diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 5e163e23a207..4e0d5bf12b47 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -46,7 +46,7 @@ struct mt8192_mt6359_priv { /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin mt8192_jack_pins[] = { { - .pin = "Headphone Jack", + .pin = "Headphone", .mask = SND_JACK_HEADPHONE, }, { diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 9e45efeada55..d22cf1664d8a 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3030,28 +3030,6 @@ static const struct reg_sequence mt8195_cg_patch[] = { { AUDIO_TOP_CON1, 0xfffffff8 }, }; -static int mt8195_afe_init_registers(struct mtk_base_afe *afe) -{ - return regmap_multi_reg_write(afe->regmap, - mt8195_afe_reg_defaults, - ARRAY_SIZE(mt8195_afe_reg_defaults)); -} - -static void mt8195_afe_parse_of(struct mtk_base_afe *afe, - struct device_node *np) -{ -#if IS_ENABLED(CONFIG_SND_SOC_MT6359) - struct mt8195_afe_private *afe_priv = afe->platform_priv; - - afe_priv->topckgen = syscon_regmap_lookup_by_phandle(afe->dev->of_node, - "mediatek,topckgen"); - if (IS_ERR(afe_priv->topckgen)) { - dev_info(afe->dev, "%s() Cannot find topckgen controller: %ld\n", - __func__, PTR_ERR(afe_priv->topckgen)); - } -#endif -} - static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; @@ -3062,10 +3040,8 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) struct snd_soc_component *component; ret = of_reserved_mem_device_init(dev); - if (ret) { - dev_err(dev, "failed to assign memory region: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to assign memory region\n"); ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33)); if (ret) @@ -3089,24 +3065,17 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) /* initial audio related clock */ ret = mt8195_afe_init_clock(afe); - if (ret) { - dev_err(dev, "init clock error\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "init clock error\n"); /* reset controller to reset audio regs before regmap cache */ rstc = devm_reset_control_get_exclusive(dev, "audiosys"); - if (IS_ERR(rstc)) { - ret = PTR_ERR(rstc); - dev_err(dev, "could not get audiosys reset:%d\n", ret); - return ret; - } + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n"); ret = reset_control_reset(rstc); - if (ret) { - dev_err(dev, "failed to trigger audio reset:%d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to trigger audio reset\n"); spin_lock_init(&afe_priv->afe_ctrl_lock); @@ -3143,30 +3112,22 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq_id, mt8195_afe_irq_handler, IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); - if (ret) { - dev_err(dev, "could not request_irq for asys-isr\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "could not request_irq for asys-isr\n"); /* init sub_dais */ INIT_LIST_HEAD(&afe->sub_dais); for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { ret = dai_register_cbs[i](afe); - if (ret) { - dev_warn(dev, "dai register i %d fail, ret %d\n", - i, ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "dai cb%i register fail\n", i); } /* init dai_driver and component_driver */ ret = mtk_afe_combine_sub_dai(afe); - if (ret) { - dev_warn(dev, "mtk_afe_combine_sub_dai fail, ret %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); afe->mtk_afe_hardware = &mt8195_afe_hardware; afe->memif_fs = mt8195_memif_fs; @@ -3177,18 +3138,21 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) platform_set_drvdata(pdev, afe); - mt8195_afe_parse_of(afe, pdev->dev.of_node); - - pm_runtime_enable(dev); - if (!pm_runtime_enabled(dev)) { - ret = mt8195_afe_runtime_resume(dev); - if (ret) - return ret; - } + afe_priv->topckgen = syscon_regmap_lookup_by_phandle(dev->of_node, "mediatek,topckgen"); + if (IS_ERR(afe_priv->topckgen)) + dev_dbg(afe->dev, "Cannot find topckgen controller: %ld\n", + PTR_ERR(afe_priv->topckgen)); /* enable clock for regcache get default value from hw */ afe_priv->pm_runtime_bypass_reg_ctl = true; - pm_runtime_get_sync(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to resume device\n"); afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, &mt8195_afe_regmap_config); @@ -3236,9 +3200,15 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) goto err_pm_put; } - mt8195_afe_init_registers(afe); + ret = regmap_multi_reg_write(afe->regmap, mt8195_afe_reg_defaults, + ARRAY_SIZE(mt8195_afe_reg_defaults)); + if (ret) + goto err_pm_put; + + ret = pm_runtime_put_sync(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to suspend device\n"); - pm_runtime_put_sync(dev); afe_priv->pm_runtime_bypass_reg_ctl = false; regcache_cache_only(afe->regmap, true); @@ -3248,7 +3218,6 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) err_pm_put: pm_runtime_put_sync(dev); - pm_runtime_disable(dev); return ret; } diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index a25c397c66c5..74e7cf0ef8d5 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -120,20 +120,18 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, if (!lb->name) return -ENOMEM; - dlc = devm_kzalloc(card->dev, 2 * sizeof(*dlc), GFP_KERNEL); + dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; - lb->cpus = &dlc[0]; - lb->codecs = &dlc[1]; + lb->cpus = dlc; + lb->codecs = &asoc_dummy_dlc; lb->num_cpus = 1; lb->num_codecs = 1; lb->stream_name = lb->name; lb->cpus->of_node = pad->cpus->of_node; lb->cpus->dai_name = "TDM Loopback"; - lb->codecs->name = "snd-soc-dummy"; - lb->codecs->dai_name = "snd-soc-dummy-dai"; lb->dpcm_capture = 1; lb->no_pcm = 1; lb->ops = &axg_card_tdm_be_ops; diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 2d8d5717fd8b..ffc5111f9e3c 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -183,21 +183,13 @@ int meson_card_set_fe_link(struct snd_soc_card *card, struct device_node *node, bool is_playback) { - struct snd_soc_dai_link_component *codec; - - codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL); - if (!codec) - return -ENOMEM; - - link->codecs = codec; + link->codecs = &asoc_dummy_dlc; link->num_codecs = 1; link->dynamic = 1; link->dpcm_merged_format = 1; link->dpcm_merged_chan = 1; link->dpcm_merged_rate = 1; - link->codecs->dai_name = "snd-soc-dummy-dai"; - link->codecs->name = "snd-soc-dummy"; if (is_playback) link->dpcm_playback = 1; diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index c1f24af17506..cab5a7937a57 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -140,17 +140,8 @@ int qcom_snd_parse_of(struct snd_soc_card *card) } } else { /* DPCM frontend */ - dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); - if (!dlc) { - ret = -ENOMEM; - goto err; - } - - link->codecs = dlc; + link->codecs = &asoc_dummy_dlc; link->num_codecs = 1; - - link->codecs->dai_name = "snd-soc-dummy-dai"; - link->codecs->name = "snd-soc-dummy"; link->dynamic = 1; } diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 41db6617e2ed..56db852f4eab 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -12,7 +12,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> -#include <linux/pm_runtime.h> +#include <linux/pm.h> #include <dt-bindings/sound/sc7180-lpass.h> #include <sound/pcm.h> #include <sound/soc.h> diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index d43f480cbae3..bcf18fe8e14d 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -8,7 +8,7 @@ #include <linux/module.h> #include <sound/pcm.h> #include <sound/soc.h> -#include <linux/pm_runtime.h> +#include <linux/pm.h> #include <dt-bindings/sound/sc7180-lpass.h> diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 1e0c918eb576..8d9410dcbd45 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -196,6 +196,12 @@ struct apm_codec_dma_module_intf_cfg { #define APM_CDMA_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_codec_dma_module_intf_cfg), 8) +struct apm_display_port_module_intf_cfg { + struct apm_module_param_data param_data; + struct param_id_display_port_intf_cfg cfg; +} __packed; +#define APM_DP_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_display_port_module_intf_cfg), 8) + static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token, uint32_t src_port, uint32_t dest_port, bool has_cmd_hdr) { @@ -582,6 +588,72 @@ int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, struct gpr_pkt *pk } EXPORT_SYMBOL_GPL(audioreach_graph_send_cmd_sync); +static int audioreach_display_port_set_media_format(struct q6apm_graph *graph, + struct audioreach_module *module, + struct audioreach_module_config *cfg) +{ + struct apm_display_port_module_intf_cfg *intf_cfg; + struct apm_module_frame_size_factor_cfg *fs_cfg; + struct apm_module_param_data *param_data; + struct apm_module_hw_ep_mf_cfg *hw_cfg; + int ic_sz, ep_sz, fs_sz, dl_sz; + int rc, payload_size; + struct gpr_pkt *pkt; + void *p; + + ic_sz = APM_DP_INTF_CFG_PSIZE; + ep_sz = APM_HW_EP_CFG_PSIZE; + fs_sz = APM_FS_CFG_PSIZE; + dl_sz = 0; + + payload_size = ic_sz + ep_sz + fs_sz + dl_sz; + + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + if (IS_ERR(pkt)) + return PTR_ERR(pkt); + + p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + hw_cfg = p; + param_data = &hw_cfg->param_data; + param_data->module_instance_id = module->instance_id; + param_data->error_code = 0; + param_data->param_id = PARAM_ID_HW_EP_MF_CFG; + param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE; + + hw_cfg->mf.sample_rate = cfg->sample_rate; + hw_cfg->mf.bit_width = cfg->bit_width; + hw_cfg->mf.num_channels = cfg->num_channels; + hw_cfg->mf.data_format = module->data_format; + p += ep_sz; + + fs_cfg = p; + param_data = &fs_cfg->param_data; + param_data->module_instance_id = module->instance_id; + param_data->error_code = 0; + param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR; + param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE; + fs_cfg->frame_size_factor = 1; + p += fs_sz; + + intf_cfg = p; + param_data = &intf_cfg->param_data; + param_data->module_instance_id = module->instance_id; + param_data->error_code = 0; + param_data->param_id = PARAM_ID_DISPLAY_PORT_INTF_CFG; + param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; + + intf_cfg->cfg.channel_allocation = cfg->channel_allocation; + intf_cfg->cfg.mst_idx = 0; + intf_cfg->cfg.dptx_idx = cfg->dp_idx; + + rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); + + kfree(pkt); + + return rc; +} + /* LPASS Codec DMA port Module Media Format Setup */ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, struct audioreach_module *module, @@ -1122,6 +1194,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod case MODULE_ID_PCM_CNV: rc = audioreach_pcm_set_media_format(graph, module, cfg); break; + case MODULE_ID_DISPLAY_PORT_SINK: + rc = audioreach_display_port_set_media_format(graph, module, cfg); + break; case MODULE_ID_I2S_SOURCE: case MODULE_ID_I2S_SINK: rc = audioreach_i2s_set_media_format(graph, module, cfg); diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 1d1d47d47d40..3ebb81cd7cb0 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -22,6 +22,7 @@ struct q6apm_graph; #define MODULE_ID_I2S_SINK 0x0700100A #define MODULE_ID_I2S_SOURCE 0x0700100B #define MODULE_ID_DATA_LOGGING 0x0700101A +#define MODULE_ID_DISPLAY_PORT_SINK 0x07001069 #define APM_CMD_GET_SPF_STATE 0x01001021 #define APM_CMD_RSP_GET_SPF_STATE 0x02001007 @@ -444,6 +445,15 @@ struct param_id_i2s_intf_cfg { #define PORT_ID_I2S_OUPUT 1 #define I2S_STACK_SIZE 2048 +#define PARAM_ID_DISPLAY_PORT_INTF_CFG 0x08001154 + +struct param_id_display_port_intf_cfg { + uint32_t channel_allocation; + /* Multi-Steam Transport index */ + uint32_t mst_idx; + uint32_t dptx_idx; +} __packed; + #define PARAM_ID_HW_EP_MF_CFG 0x08001017 struct param_id_hw_ep_mf { uint32_t sample_rate; @@ -702,6 +712,8 @@ struct audioreach_module_config { u16 data_format; u16 num_channels; u16 active_channels_mask; + u16 dp_idx; + u32 channel_allocation; u32 sd_line_mask; int fmt; u8 channel_map[AR_PCM_MAX_NUM_CHANNEL]; diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 8bb7452b8f18..31e0bad71e95 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -12,6 +12,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> #include "q6dsp-lpass-ports.h" +#include "q6dsp-common.h" #include "q6afe.h" @@ -69,6 +70,7 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); int channels = params_channels(params); struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi; + int ret; hdmi->sample_rate = params_rate(params); switch (params_format(params)) { @@ -80,33 +82,11 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, break; } - /* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */ - switch (channels) { - case 2: - hdmi->channel_allocation = 0; - break; - case 3: - hdmi->channel_allocation = 0x02; - break; - case 4: - hdmi->channel_allocation = 0x06; - break; - case 5: - hdmi->channel_allocation = 0x0A; - break; - case 6: - hdmi->channel_allocation = 0x0B; - break; - case 7: - hdmi->channel_allocation = 0x12; - break; - case 8: - hdmi->channel_allocation = 0x13; - break; - default: - dev_err(dai->dev, "invalid Channels = %u\n", channels); - return -EINVAL; - } + ret = q6dsp_get_channel_allocation(channels); + if (ret < 0) + return ret; + + hdmi->channel_allocation = (u16) ret; return 0; } diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 420e8aa11f42..7ad604b80e25 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -11,6 +11,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> #include "q6dsp-lpass-ports.h" +#include "q6dsp-common.h" #include "audioreach.h" #include "q6apm.h" @@ -91,6 +92,36 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai, return 0; } +static int q6hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; + int channels = params_channels(params); + int ret; + + cfg->bit_width = params_width(params); + cfg->sample_rate = params_rate(params); + cfg->num_channels = channels; + + switch (dai->id) { + case DISPLAY_PORT_RX_0: + cfg->dp_idx = 0; + break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + cfg->dp_idx = dai->id - DISPLAY_PORT_RX_1 + 1; + break; + } + + ret = q6dsp_get_channel_allocation(channels); + if (ret < 0) + return ret; + + cfg->channel_allocation = ret; + + return 0; +} + static int q6dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -215,6 +246,13 @@ static const struct snd_soc_dai_ops q6i2s_ops = { .shutdown = q6apm_lpass_dai_shutdown, .set_channel_map = q6dma_set_channel_map, .hw_params = q6dma_hw_params, +}; + +static const struct snd_soc_dai_ops q6hdmi_ops = { + .prepare = q6apm_lpass_dai_prepare, + .startup = q6apm_lpass_dai_startup, + .shutdown = q6apm_lpass_dai_shutdown, + .hw_params = q6hdmi_hw_params, .set_fmt = q6i2s_set_fmt, }; @@ -242,6 +280,7 @@ static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) memset(&cfg, 0, sizeof(cfg)); cfg.q6i2s_ops = &q6i2s_ops; cfg.q6dma_ops = &q6dma_ops; + cfg.q6hdmi_ops = &q6hdmi_ops; dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais); return devm_snd_soc_register_component(dev, &q6apm_lpass_dai_component, dais, num_dais); diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.c b/sound/soc/qcom/qdsp6/q6dsp-common.c index d393003492c7..95585dea2b36 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-common.c +++ b/sound/soc/qcom/qdsp6/q6dsp-common.c @@ -63,4 +63,39 @@ int q6dsp_map_channels(u8 ch_map[PCM_MAX_NUM_CHANNEL], int ch) return 0; } EXPORT_SYMBOL_GPL(q6dsp_map_channels); + +int q6dsp_get_channel_allocation(int channels) +{ + int channel_allocation; + + /* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */ + switch (channels) { + case 2: + channel_allocation = 0; + break; + case 3: + channel_allocation = 0x02; + break; + case 4: + channel_allocation = 0x06; + break; + case 5: + channel_allocation = 0x0A; + break; + case 6: + channel_allocation = 0x0B; + break; + case 7: + channel_allocation = 0x12; + break; + case 8: + channel_allocation = 0x13; + break; + default: + return -EINVAL; + } + + return channel_allocation; +} +EXPORT_SYMBOL_GPL(q6dsp_get_channel_allocation); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.h b/sound/soc/qcom/qdsp6/q6dsp-common.h index 01094d108b8a..9e704db5f604 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-common.h +++ b/sound/soc/qcom/qdsp6/q6dsp-common.h @@ -20,5 +20,6 @@ #define PCM_CHANNELS 10 /* Top surround channel. */ int q6dsp_map_channels(u8 ch_map[PCM_MAX_NUM_CHANNEL], int ch); +int q6dsp_get_channel_allocation(int channels); #endif /* __Q6DSP_COMMON_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index f67c16fd90b9..ac937a6bf909 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -79,6 +79,22 @@ .id = did, \ } +#define Q6AFE_DP_RX_DAI(did) { \ + .playback = { \ + .stream_name = #did" Playback", \ + .rates = SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE, \ + .channels_min = 2, \ + .channels_max = 8, \ + .rate_min = 48000, \ + .rate_max = 192000, \ + }, \ + .name = #did, \ + .id = did, \ + } static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { { @@ -528,22 +544,14 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5), Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6), Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7), - { - .playback = { - .stream_name = "Display Port Playback", - .rates = SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - .channels_min = 2, - .channels_max = 8, - .rate_max = 192000, - .rate_min = 48000, - }, - .id = DISPLAY_PORT_RX, - .name = "DISPLAY_PORT", - }, + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_0), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_1), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_2), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_3), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_4), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_5), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_6), + Q6AFE_DP_RX_DAI(DISPLAY_PORT_RX_7), Q6AFE_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_0), Q6AFE_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_0), Q6AFE_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_1), @@ -603,6 +611,9 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, case DISPLAY_PORT_RX: q6dsp_audio_fe_dais[i].ops = cfg->q6hdmi_ops; break; + case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7: + q6dsp_audio_fe_dais[i].ops = cfg->q6hdmi_ops; + break; case SLIMBUS_0_RX ... SLIMBUS_6_TX: q6dsp_audio_fe_dais[i].ops = cfg->q6slim_ops; break; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ff25718ff2e8..4356cc320fea 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -236,6 +236,28 @@ int snd_soc_component_force_enable_pin_unlocked( } EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); +int snd_soc_component_notify_control(struct snd_soc_component *component, + const char * const ctl) +{ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + struct snd_kcontrol *kctl; + + if (component->name_prefix) + snprintf(name, ARRAY_SIZE(name), "%s %s", component->name_prefix, ctl); + else + snprintf(name, ARRAY_SIZE(name), "%s", ctl); + + kctl = snd_soc_card_get_kcontrol(component->card, name); + if (!kctl) + return soc_component_ret(component, -EINVAL); + + snd_ctl_notify(component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_notify_control); + /** * snd_soc_component_set_jack - configure component jack. * @component: COMPONENTs diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d8715db5e415..02fdb683f75f 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -20,7 +20,6 @@ #include <sound/initval.h> #include <sound/soc-dpcm.h> #include <sound/soc-link.h> -#include <linux/pm_runtime.h> static int snd_soc_compr_components_open(struct snd_compr_stream *cstream) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index adb69d7820a8..6365ad8ca7ef 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pinctrl/consumer.h> -#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/export.h> diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index d0aca6b9058b..8add361e87c6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -585,11 +585,15 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event); static int soc_tplg_control_load(struct soc_tplg *tplg, struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr) { + int ret = 0; + if (tplg->ops && tplg->ops->control_load) - return tplg->ops->control_load(tplg->comp, tplg->index, k, - hdr); + ret = tplg->ops->control_load(tplg->comp, tplg->index, k, hdr); - return 0; + if (ret) + dev_err(tplg->dev, "ASoC: failed to init %s\n", hdr->name); + + return ret; } @@ -691,17 +695,13 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size) /* pass control to driver for optional further init */ ret = soc_tplg_control_load(tplg, &kc, &be->hdr); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", be->hdr.name); + if (ret < 0) goto err; - } /* register control here */ ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to add %s\n", be->hdr.name); + if (ret < 0) goto err; - } list_add(&sbe->dobj.list, &tplg->comp->dobj_list); @@ -776,17 +776,13 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size) /* pass control to driver for optional further init */ ret = soc_tplg_control_load(tplg, &kc, &mc->hdr); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + if (ret < 0) goto err; - } /* register control here */ ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to add %s\n", mc->hdr.name); + if (ret < 0) goto err; - } list_add(&sm->dobj.list, &tplg->comp->dobj_list); @@ -945,17 +941,13 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size) /* pass control to driver for optional further init */ ret = soc_tplg_control_load(tplg, &kc, &ec->hdr); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name); + if (ret < 0) goto err; - } /* register control here */ ret = soc_tplg_add_kcontrol(tplg, &kc, &se->dobj.control.kcontrol); - if (ret < 0) { - dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n", ec->hdr.name); + if (ret < 0) goto err; - } list_add(&se->dobj.list, &tplg->comp->dobj_list); @@ -1162,11 +1154,8 @@ static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_ /* pass control to driver for optional further init */ err = soc_tplg_control_load(tplg, kc, &mc->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - mc->hdr.name); + if (err < 0) return err; - } return 0; } @@ -1246,11 +1235,8 @@ static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_k /* pass control to driver for optional further init */ err = soc_tplg_control_load(tplg, kc, &ec->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - ec->hdr.name); + if (err < 0) return err; - } return 0; } @@ -1298,11 +1284,8 @@ static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_ /* pass control to driver for optional further init */ err = soc_tplg_control_load(tplg, kc, &be->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - be->hdr.name); + if (err < 0) return err; - } return 0; } @@ -1530,15 +1513,13 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) * If so, just return success. */ if (!snd_soc_card_is_instantiated(card)) { - dev_warn(tplg->dev, "ASoC: Parent card not yet available," - " widget card binding deferred\n"); + dev_warn(tplg->dev, "ASoC: Parent card not yet available, widget card binding deferred\n"); return 0; } ret = snd_soc_dapm_new_widgets(card); if (ret < 0) - dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n", - ret); + dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n", ret); return ret; } @@ -1693,10 +1674,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, dlc = (struct snd_soc_dai_link_component *)(link + 1); link->cpus = &dlc[0]; - link->codecs = &dlc[1]; - link->num_cpus = 1; - link->num_codecs = 1; link->dobj.index = tplg->index; link->dobj.type = SND_SOC_DOBJ_DAI_LINK; @@ -1721,16 +1699,19 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, } } - link->codecs->name = "snd-soc-dummy"; - link->codecs->dai_name = "snd-soc-dummy-dai"; - /* - * Many topology is assuming link has Platform. - * This might be overwritten at soc_tplg_dai_link_load(). + * Many topology are assuming link has Codec / Platform, and + * these might be overwritten at soc_tplg_dai_link_load(). + * Don't use &asoc_dummy_dlc here. */ - link->platforms = &dlc[2]; - link->platforms->name = "snd-soc-dummy"; - link->num_platforms = 1; + link->codecs = &dlc[1]; /* Don't use &asoc_dummy_dlc here */ + link->codecs->name = "snd-soc-dummy"; + link->codecs->dai_name = "snd-soc-dummy-dai"; + link->num_codecs = 1; + + link->platforms = &dlc[2]; /* Don't use &asoc_dummy_dlc here */ + link->platforms->name = "snd-soc-dummy"; + link->num_platforms = 1; /* enable DPCM */ link->dynamic = 1; @@ -2049,11 +2030,11 @@ static struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, if (link->id != id) continue; - if (name && (!link->name || strcmp(name, link->name))) + if (name && (!link->name || !strstr(link->name, name))) continue; - if (stream_name && (!link->stream_name - || strcmp(stream_name, link->stream_name))) + if (stream_name && (!link->stream_name || + !strstr(link->stream_name, stream_name))) continue; return link; @@ -2505,11 +2486,8 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg) /* make sure header is valid before loading */ ret = soc_tplg_valid_header(tplg, hdr); - if (ret < 0) { - dev_err(tplg->dev, - "ASoC: topology: invalid header: %d\n", ret); + if (ret < 0) return ret; - } /* load the header object */ ret = soc_tplg_load_header(tplg, hdr); @@ -2529,9 +2507,6 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg) /* signal DAPM we are complete */ ret = soc_tplg_dapm_complete(tplg); - if (ret < 0) - dev_err(tplg->dev, - "ASoC: failed to initialise DAPM from Firmware\n"); return ret; } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index a4dba0b751e7..11607c5f5d5a 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -224,6 +224,13 @@ int snd_soc_component_is_dummy(struct snd_soc_component *component) (component->driver == &dummy_codec)); } +struct snd_soc_dai_link_component asoc_dummy_dlc = { + .of_node = NULL, + .dai_name = "snd-soc-dummy-dai", + .name = "snd-soc-dummy", +}; +EXPORT_SYMBOL_GPL(asoc_dummy_dlc); + static int snd_soc_dummy_probe(struct platform_device *pdev) { int ret; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 1c535cc6c3a9..dc624f727aa3 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -55,6 +55,9 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 +#define ACP_RN_PCI_ID 0x01 +#define ACP_RMB_PCI_ID 0x6F + #define HOST_BRIDGE_CZN 0x1630 #define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index eaf70ea6e556..58b3092425f1 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -65,6 +65,9 @@ static int acp_pci_rmb_probe(struct pci_dev *pci, const struct pci_device_id *pc { unsigned int flag; + if (pci->revision != ACP_RMB_PCI_ID) + return -ENODEV; + flag = snd_amd_acp_find_config(pci); if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) return -ENODEV; diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 4809cb644152..7409e21ce5aa 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -65,6 +65,9 @@ static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci { unsigned int flag; + if (pci->revision != ACP_RN_PCI_ID) + return -ENODEV; + flag = snd_amd_acp_find_config(pci); if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) return -ENODEV; diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index f4eeacf1f281..69c1a370d3b6 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -284,8 +284,6 @@ if SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK bool "SOF support for HDA Links(HDA/HDMI)" - depends on SND_SOC_SOF_NOCODEC_SUPPORT=n - select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware for Intel(R) platforms. @@ -295,6 +293,7 @@ config SND_SOC_SOF_HDA_LINK config SND_SOC_SOF_HDA_AUDIO_CODEC bool "SOF support for HDAudio codecs" depends on SND_SOC_SOF_HDA_LINK + select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDAudio codecs with Sound Open Firmware for Intel(R) platforms. diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index acb4b85868d0..fc63085d2d74 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -70,9 +70,14 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); -#else /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +#else + snd_hdac_ext_bus_init(bus, dev, NULL, NULL); +#endif +#else + memset(bus, 0, sizeof(*bus)); bus->dev = dev; @@ -87,12 +92,12 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) bus->idx = 0; spin_lock_init(&bus->reg_lock); -#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ } void sof_hda_bus_exit(struct snd_sof_dev *sdev) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) struct hdac_bus *bus = sof_to_bus(sdev); snd_hdac_ext_bus_exit(bus); diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index 4b39cecacd68..1e58256c8003 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -16,7 +16,7 @@ #include "hda.h" /* These ops are only applicable for the HDA DAI's in their current form */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) /* * This function checks if the host dma channel corresponding * to the link DMA stream_tag argument is assigned to one @@ -120,6 +120,26 @@ static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev, return snd_soc_dai_get_dma_data(cpu_dai, substream); } +static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_widget *swidget; + struct snd_soc_dapm_widget *w; + + w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + swidget = w->dobj.private; + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; + + /* mark pipeline so that it can be skipped during FE trigger */ + pipeline->skip_during_fe_trigger = true; + + return snd_soc_dai_get_dma_data(cpu_dai, substream); +} + static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) @@ -158,17 +178,20 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; - int ret; + int ret = 0; w = snd_soc_dai_get_widget(cpu_dai, substream->stream); swidget = w->dobj.private; pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + mutex_lock(&ipc4_data->pipeline_state_mutex); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -179,16 +202,17 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) - return ret; + goto out; pipeline->state = SOF_IPC4_PIPE_PAUSED; break; default: dev_err(sdev->dev, "unknown trigger command %d\n", cmd); - return -EINVAL; + ret = -EINVAL; } - - return 0; +out: + mutex_unlock(&ipc4_data->pipeline_state_mutex); + return ret; } static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, @@ -217,57 +241,66 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { + struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; - int ret; + int ret = 0; w = snd_soc_dai_get_widget(cpu_dai, substream->stream); swidget = w->dobj.private; pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + mutex_lock(&ipc4_data->pipeline_state_mutex); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) - return ret; + goto out; pipeline->state = SOF_IPC4_PIPE_PAUSED; } ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_RUNNING); if (ret < 0) - return ret; + goto out; pipeline->state = SOF_IPC4_PIPE_RUNNING; + swidget->spipe->started_count++; break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, - SOF_IPC4_PIPE_RESET); + SOF_IPC4_PIPE_RUNNING); if (ret < 0) - return ret; - - pipeline->state = SOF_IPC4_PIPE_RESET; + goto out; + pipeline->state = SOF_IPC4_PIPE_RUNNING; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + /* + * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have + * been stopped. So, clear the started_count so that the pipeline can be reset + */ + swidget->spipe->started_count = 0; break; - } case SNDRV_PCM_TRIGGER_PAUSE_PUSH: break; default: dev_err(sdev->dev, "unknown trigger command %d\n", cmd); - return -EINVAL; + ret = -EINVAL; + break; } - - return 0; +out: + mutex_unlock(&ipc4_data->pipeline_state_mutex); + return ret; } static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { - .get_hext_stream = hda_get_hext_stream, + .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, .release_hext_stream = hda_release_hext_stream, .setup_hext_stream = hda_setup_hext_stream, @@ -350,7 +383,7 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = { const struct hda_dai_widget_dma_ops * hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) struct snd_sof_dai *sdai; if (sdev->dspless_mode_selected) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 44a5d94c5050..09d8ee98581d 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -27,20 +27,26 @@ static bool hda_use_tplg_nhlt; module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); +static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_soc_component *component = swidget->scomp; + + return snd_soc_component_get_drvdata(component); +} + int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, struct snd_sof_dai_config_data *data) { struct snd_sof_widget *swidget = w->dobj.private; const struct sof_ipc_tplg_ops *tplg_ops; - struct snd_soc_component *component; struct snd_sof_dev *sdev; int ret; if (!swidget) return 0; - component = swidget->scomp; - sdev = snd_soc_component_get_drvdata(component); + sdev = widget_to_sdev(w); tplg_ops = sof_ipc_get_ops(sdev, tplg); if (tplg_ops && tplg_ops->dai_config) { @@ -55,16 +61,26 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) + +static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + + return widget_to_sdev(w); +} static const struct hda_dai_widget_dma_ops * hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dev *sdev; struct snd_sof_dai *sdai; + sdev = widget_to_sdev(w); + /* * The swidget parameter of hda_select_dai_widget_ops() is ignored in * case of DSPless mode @@ -96,14 +112,16 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, struct snd_soc_dai *codec_dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct hdac_stream *hstream = &hext_stream->hstream; struct hdac_bus *bus = hstream->bus; struct sof_intel_hda_stream *hda_stream; struct hdac_ext_link *hlink; + struct snd_sof_dev *sdev; int stream_tag; + sdev = dai_to_sdev(substream, cpu_dai); + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); if (!hlink) return -EINVAL; @@ -140,7 +158,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, unsigned int link_bps; int stream_tag; - sdev = snd_soc_component_get_drvdata(cpu_dai->component); + sdev = dai_to_sdev(substream, cpu_dai); bus = sof_to_bus(sdev); hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); @@ -188,21 +206,14 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, return 0; } -static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) +static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - int stream = substream->stream; - - return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); -} - -static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct hdac_ext_stream *hext_stream; + struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai); if (!ops) { dev_err(sdev->dev, "DAI widget ops not set\n"); @@ -216,16 +227,16 @@ static int hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_d return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai); } -static int hda_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); struct hdac_ext_stream *hext_stream; struct snd_sof_dai_config_data data = { 0 }; unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; + struct snd_sof_dev *sdev = widget_to_sdev(w); int ret; if (!ops) { @@ -249,50 +260,25 @@ static int hda_dai_hw_params(struct snd_pcm_substream *substream, return hda_dai_config(w, flags, &data); } -static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); - const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); - struct hdac_ext_stream *hext_stream; - struct snd_sof_dai_config_data data = { 0 }; - unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; - int ret; - - hext_stream = ops->get_hext_stream(sdev, dai, substream); - if (hext_stream && hext_stream->link_prepared) - return 0; - - dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream); - - ret = hda_link_dma_prepare(substream, dai); - if (ret < 0) - return ret; - - hext_stream = ops->get_hext_stream(sdev, dai, substream); - - flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; - data.dai_data = hdac_stream(hext_stream)->stream_tag - 1; - - return hda_dai_config(w, flags, &data); -} - /* * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes * (over IPC channel) and DMA state change (direct host register changes). */ -static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); struct hdac_ext_stream *hext_stream; struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; + struct snd_sof_dev *sdev; int ret; dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, dai->name, substream->stream); + sdev = dai_to_sdev(substream, dai); + hext_stream = ops->get_hext_stream(sdev, dai, substream); if (!hext_stream) return -EINVAL; @@ -333,6 +319,16 @@ static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct return 0; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + +static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int stream = substream->stream; + + return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); +} + static const struct snd_soc_dai_ops hda_dai_ops = { .hw_params = hda_dai_hw_params, .hw_free = hda_dai_hw_free, @@ -340,6 +336,8 @@ static const struct snd_soc_dai_ops hda_dai_ops = { .prepare = hda_dai_prepare, }; +#endif + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -372,7 +370,7 @@ static int hda_dai_suspend(struct hdac_bus *bus) codec_dai = asoc_rtd_to_codec(rtd, 0); w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction); swidget = w->dobj.private; - sdev = snd_soc_component_get_drvdata(swidget->scomp); + sdev = widget_to_sdev(w); sdai = swidget->private; ops = sdai->platform_private; @@ -588,7 +586,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) * Since the component suspend is called last, we can trap this corner case * and force the DAIs to release their resources. */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) int ret; ret = hda_dai_suspend(sof_to_bus(sdev)); diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 69fdef8f89ae..1e77ca936f80 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -15,7 +15,6 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/pm_runtime.h> #include <linux/slab.h> #include <sound/hdaudio_ext.h> #include <sound/sof.h> diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 8de422604ad5..b13acb959653 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -15,7 +15,6 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include <linux/pm_runtime.h> #include <sound/hdaudio_ext.h> #include <sound/hda_register.h> #include <sound/sof.h> diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 3153e21f100a..835c2568dd60 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1562,7 +1562,11 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach, mach_params = &mach->mach_params; mach_params->platform = dev_name(sdev->dev); - mach_params->num_dai_drivers = desc->ops->num_drv; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + mach_params->num_dai_drivers = SOF_SKL_NUM_DAIS_NOCODEC; + else + mach_params->num_dai_drivers = desc->ops->num_drv; mach_params->dai_drivers = desc->ops->drv; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c4befacde23e..5b3dad2dadf4 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -414,10 +414,12 @@ (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl)) /* Number of DAIs */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#define SOF_SKL_NUM_DAIS_NOCODEC 8 + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define SOF_SKL_NUM_DAIS 15 #else -#define SOF_SKL_NUM_DAIS 8 +#define SOF_SKL_NUM_DAIS SOF_SKL_NUM_DAIS_NOCODEC #endif /* Intel HD Audio SRAM Window 0*/ diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 46caf3ccde66..93dc2c9d8448 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -613,6 +613,36 @@ static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, return ((u64)llp_u << 32) | llp_l; } +static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) +{ + const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; + + if (core == SOF_DSP_PRIMARY_CORE) + return mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE); + + if (pm_ops->set_core_state) + return pm_ops->set_core_state(sdev, core, true); + + return 0; +} + +static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) +{ + const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; + int ret; + + if (pm_ops->set_core_state) { + ret = pm_ops->set_core_state(sdev, core, false); + if (ret < 0) + return ret; + } + + if (core == SOF_DSP_PRIMARY_CORE) + return mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + + return 0; +} + /* Meteorlake ops */ struct snd_sof_dsp_ops sof_mtl_ops; EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -649,7 +679,8 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) sof_mtl_ops.parse_platform_ext_manifest = NULL; /* dsp core get/put */ - /* TODO: add core_get and core_put */ + sof_mtl_ops.core_get = mtl_dsp_core_get; + sof_mtl_ops.core_put = mtl_dsp_core_put; sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 13efdb94d071..d24e64e71b58 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/pm_runtime.h> #include <sound/hdaudio_ext.h> #include <sound/pcm_params.h> #include <sound/sof.h> diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 2713b7dc7931..8e2b07e1612b 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -39,14 +39,18 @@ static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core) static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; + int ret; + + if (pm_ops->set_core_state) { + ret = pm_ops->set_core_state(sdev, core, false); + if (ret < 0) + return ret; + } /* power down primary core and return */ if (core == SOF_DSP_PRIMARY_CORE) return hda_dsp_core_reset_power_down(sdev, BIT(core)); - if (pm_ops->set_core_state) - return pm_ops->set_core_state(sdev, core, false); - return 0; } diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index ad040e7bb850..a8deec7dc021 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -96,6 +96,26 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, cdata->elems_remaining = 0; ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); + if (!set) + goto unlock; + + /* It is a set-data operation, and we have a backup that we can restore */ + if (ret < 0) { + if (!scontrol->old_ipc_control_data) + goto unlock; + /* + * Current ipc_control_data is not valid, we use the last known good + * configuration + */ + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, + scontrol->max_size); + kfree(scontrol->old_ipc_control_data); + scontrol->old_ipc_control_data = NULL; + /* Send the last known good configuration to firmware */ + ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); + if (ret < 0) + goto unlock; + } unlock: if (lock) @@ -351,6 +371,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol, struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_soc_component *scomp = scontrol->scomp; struct snd_ctl_tlv header; + int ret = -EINVAL; /* * The beginning of bytes data contains a header from where @@ -381,31 +402,52 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol, return -EINVAL; } - if (copy_from_user(cdata->data, tlvd->tlv, header.length)) - return -EFAULT; + if (!scontrol->old_ipc_control_data) { + /* Create a backup of the current, valid bytes control */ + scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data, + scontrol->max_size, GFP_KERNEL); + if (!scontrol->old_ipc_control_data) + return -ENOMEM; + } + + if (copy_from_user(cdata->data, tlvd->tlv, header.length)) { + ret = -EFAULT; + goto err_restore; + } if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic); - return -EINVAL; + goto err_restore; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n", cdata->data->abi); - return -EINVAL; + goto err_restore; } /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) { dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n"); - return -EINVAL; + goto err_restore; } /* notify DSP of byte control updates */ - if (pm_runtime_active(scomp->dev)) + if (pm_runtime_active(scomp->dev)) { + /* Actually send the data to the DSP; this is an opportunity to validate the data */ return sof_ipc3_set_get_kcontrol_data(scontrol, true, true); + } return 0; + +err_restore: + /* If we have an issue, we restore the old, valid bytes control data */ + if (scontrol->old_ipc_control_data) { + memcpy(cdata->data, scontrol->old_ipc_control_data, scontrol->max_size); + kfree(scontrol->old_ipc_control_data); + scontrol->old_ipc_control_data = NULL; + } + return ret; } static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol, diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 6f0698be9451..c6d404d44097 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -54,6 +54,26 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); ret = iops->set_get_data(sdev, msg, msg->data_size, set); + if (!set) + goto unlock; + + /* It is a set-data operation, and we have a valid backup that we can restore */ + if (ret < 0) { + if (!scontrol->old_ipc_control_data) + goto unlock; + /* + * Current ipc_control_data is not valid, we use the last known good + * configuration + */ + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, + scontrol->max_size); + kfree(scontrol->old_ipc_control_data); + scontrol->old_ipc_control_data = NULL; + /* Send the last known good configuration to firmware */ + ret = iops->set_get_data(sdev, msg, msg->data_size, set); + if (ret < 0) + goto unlock; + } unlock: if (lock) @@ -327,13 +347,24 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, return -EINVAL; } + if (!scontrol->old_ipc_control_data) { + /* Create a backup of the current, valid bytes control */ + scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data, + scontrol->max_size, GFP_KERNEL); + if (!scontrol->old_ipc_control_data) + return -ENOMEM; + } + /* Copy the whole binary data which includes the ABI header and the payload */ - if (copy_from_user(data, tlvd->tlv, header.length)) + if (copy_from_user(data, tlvd->tlv, header.length)) { + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, + scontrol->max_size); + kfree(scontrol->old_ipc_control_data); + scontrol->old_ipc_control_data = NULL; return -EFAULT; + } - sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); - - return 0; + return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); } static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index 1321acc402fd..eaa04762eb11 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -112,16 +112,13 @@ static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev, return -EINVAL; } - /* a module's config is always the same size */ - fw_module->bss_size = fm_config[fm_entry->cfg_offset].is_bytes; + fw_module->fw_mod_cfg = &fm_config[fm_entry->cfg_offset]; dev_dbg(sdev->dev, "module %s: UUID %pUL cfg_count: %u, bss_size: %#x\n", fm_entry->name, &fm_entry->uuid, fm_entry->cfg_count, - fw_module->bss_size); + fm_config[fm_entry->cfg_offset].is_bytes); } else { - fw_module->bss_size = 0; - dev_dbg(sdev->dev, "module %s: UUID %pUL\n", fm_entry->name, &fm_entry->uuid); } @@ -426,6 +423,71 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev) return ret; } +/** + * sof_ipc4_update_cpc_from_manifest - Update the cpc in base config from manifest + * @sdev: SOF device + * @fw_module: pointer struct sof_ipc4_fw_module to parse + * @basecfg: Pointer to the base_config to update + */ +void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev, + struct sof_ipc4_fw_module *fw_module, + struct sof_ipc4_base_module_cfg *basecfg) +{ + const struct sof_man4_module_config *fw_mod_cfg; + u32 cpc_pick = 0; + u32 max_cpc = 0; + const char *msg; + int i; + + if (!fw_module->fw_mod_cfg) { + msg = "No mod_cfg available for CPC lookup in the firmware file's manifest"; + goto no_cpc; + } + + /* + * Find the best matching (highest) CPC value based on the module's + * IBS/OBS configuration inferred from the audio format selection. + * + * The CPC value in each module config entry has been measured and + * recorded as a IBS/OBS/CPC triplet and stored in the firmware file's + * manifest + */ + fw_mod_cfg = fw_module->fw_mod_cfg; + for (i = 0; i < fw_module->man4_module_entry.cfg_count; i++) { + if (basecfg->obs == fw_mod_cfg[i].obs && + basecfg->ibs == fw_mod_cfg[i].ibs && + cpc_pick < fw_mod_cfg[i].cpc) + cpc_pick = fw_mod_cfg[i].cpc; + + if (max_cpc < fw_mod_cfg[i].cpc) + max_cpc = fw_mod_cfg[i].cpc; + } + + basecfg->cpc = cpc_pick; + + /* We have a matching configuration for CPC */ + if (basecfg->cpc) + return; + + /* + * No matching IBS/OBS found, the firmware manifest is missing + * information in the module's module configuration table. + */ + if (!max_cpc) + msg = "No CPC value available in the firmware file's manifest"; + else if (!cpc_pick) + msg = "No CPC match in the firmware file's manifest"; + +no_cpc: + dev_warn(sdev->dev, "%s (UUID: %pUL): %s (ibs/obs: %u/%u)\n", + fw_module->man4_module_entry.name, + &fw_module->man4_module_entry.uuid, msg, basecfg->ibs, + basecfg->obs); + dev_warn_once(sdev->dev, "Please try to update the firmware.\n"); + dev_warn_once(sdev->dev, "If the issue persists, file a bug at\n"); + dev_warn_once(sdev->dev, "https://github.com/thesofproject/sof/issues/\n"); +} + const struct sof_ipc_fw_loader_ops ipc4_loader_ops = { .validate = sof_ipc4_validate_firmware, .parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man, diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 9e2b6c45080d..0c905bd0fab4 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -69,7 +69,7 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - if (pipeline->skip_during_fe_trigger) + if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) return; switch (state) { @@ -108,7 +108,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, struct sof_ipc4_pipeline *pipeline = pipe_widget->private; int i; - if (pipeline->skip_during_fe_trigger) + if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET) return; /* set state for pipeline if it was just triggered */ diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index f461b8c70df3..a5d0b2eae464 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -28,14 +28,14 @@ enum sof_ipc4_mtrace_type { /** * struct sof_ipc4_fw_module - IPC4 module info * @sof_man4_module: Module info + * @fw_mod_cfg: Pointer to the module config start of the module * @m_ida: Module instance identifier - * @bss_size: Module object size * @private: Module private data */ struct sof_ipc4_fw_module { struct sof_man4_module man4_module_entry; + const struct sof_man4_module_config *fw_mod_cfg; struct ida m_ida; - u32 bss_size; void *private; }; @@ -114,4 +114,10 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev); int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid); + +struct sof_ipc4_base_module_cfg; +void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev, + struct sof_ipc4_fw_module *fw_module, + struct sof_ipc4_base_module_cfg *basecfg); + #endif diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 5abe616a2054..db64e0cb8663 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -39,8 +39,6 @@ static const struct sof_topology_token pipeline_tokens[] = { }; static const struct sof_topology_token ipc4_comp_tokens[] = { - {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_base_module_cfg, cpc)}, {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, }; @@ -235,7 +233,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, "Number of input audio formats: %d. Number of output audio formats: %d\n", available_fmt->num_input_formats, available_fmt->num_output_formats); - /* set cpc and is_pages in the module's base_config */ + /* set is_pages in the module's base_config */ ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(*module_base_cfg), 1); if (ret) { @@ -244,8 +242,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, return ret; } - dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n", - swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages); + dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name, + module_base_cfg->is_pages); if (available_fmt->num_input_formats) { in_format = kcalloc(available_fmt->num_input_formats, @@ -723,9 +721,9 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) } dev_dbg(scomp->dev, - "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", + "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n", swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l, - gain->data.init_val, gain->base_config.cpc); + gain->data.init_val); ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); if (ret) @@ -936,8 +934,8 @@ static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget) } static void -sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, - struct sof_ipc4_base_module_cfg *base_config) +sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, + struct sof_ipc4_base_module_cfg *base_config) { struct sof_ipc4_fw_module *fw_module = swidget->module_info; struct snd_sof_widget *pipe_widget; @@ -968,6 +966,13 @@ sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widg pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; pipeline->mem_usage += total; + + /* Update base_config->cpc from the module manifest */ + sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); + + dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n", + swidget->widget->name, base_config->ibs, base_config->obs, + base_config->cpc); } static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, @@ -1028,47 +1033,125 @@ static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw return 0; } -static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, - struct sof_ipc4_base_module_cfg *base_config, - struct snd_pcm_hw_params *params, - struct sof_ipc4_available_audio_format *available_fmt, - struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) +static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, + struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) { - u32 valid_bits; - u32 channels; - u32 rate; - int sample_valid_bits; + struct sof_ipc4_audio_format *fmt; + u32 rate, channels, valid_bits; + int i; + + fmt = &pin_fmts[0].audio_fmt; + rate = fmt->sampling_frequency; + channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + /* check if all output formats in topology are the same */ + for (i = 1; i < pin_fmts_size; i++) { + u32 _rate, _channels, _valid_bits; + + fmt = &pin_fmts[i].audio_fmt; + _rate = fmt->sampling_frequency; + _channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); + + if (_rate != rate || _channels != channels || _valid_bits != valid_bits) + return false; + } + + return true; +} + +static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, + struct sof_ipc4_base_module_cfg *base_config, + struct sof_ipc4_available_audio_format *available_fmt, + u32 out_ref_rate, u32 out_ref_channels, + u32 out_ref_valid_bits) +{ + struct sof_ipc4_audio_format *out_fmt; + bool single_format; int i; - if (!pin_fmts) { - dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); + if (!available_fmt->num_output_formats) return -EINVAL; + + single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts, + available_fmt->num_output_formats); + + /* pick the first format if there's only one available or if all formats are the same */ + if (single_format) { + base_config->obs = available_fmt->output_pin_fmts[0].buffer_size; + return 0; + } + + /* + * if there are multiple output formats, then choose the output format that matches + * the reference params + */ + for (i = 0; i < available_fmt->num_output_formats; i++) { + u32 _out_rate, _out_channels, _out_valid_bits; + + out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; + _out_rate = out_fmt->sampling_frequency; + _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); + _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + + if (_out_rate == out_ref_rate && _out_channels == out_ref_channels && + _out_valid_bits == out_ref_valid_bits) { + base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; + return i; + } } + return -EINVAL; +} + +static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) +{ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - sample_valid_bits = 16; - break; + return 16; case SNDRV_PCM_FORMAT_S24_LE: - sample_valid_bits = 24; - break; + return 24; case SNDRV_PCM_FORMAT_S32_LE: - sample_valid_bits = 32; - break; + return 32; default: dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); return -EINVAL; } +} + +static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_base_module_cfg *base_config, + struct snd_pcm_hw_params *params, + struct sof_ipc4_available_audio_format *available_fmt) +{ + struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts; + u32 pin_fmts_size = available_fmt->num_input_formats; + u32 valid_bits; + u32 channels; + u32 rate; + bool single_format; + int sample_valid_bits; + int i = 0; - if (!pin_fmts_size) { - dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); + if (!available_fmt->num_input_formats) { + dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name); return -EINVAL; } + single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts, + available_fmt->num_input_formats); + if (single_format) + goto in_fmt; + + sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params); + if (sample_valid_bits < 0) + return sample_valid_bits; + /* - * Search supported audio formats with pin index 0 to match rate, channels ,and - * sample_valid_bytes from runtime params + * Search supported input audio formats with pin index 0 to match rate, channels and + * sample_valid_bits from reference params */ for (i = 0; i < pin_fmts_size; i++) { struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; @@ -1093,6 +1176,7 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, return -EINVAL; } +in_fmt: /* copy input format */ if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, @@ -1105,10 +1189,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); } - if (available_fmt->num_output_formats && i < available_fmt->num_output_formats) - base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; - - /* Return the index of the matched format */ return i; } @@ -1288,50 +1368,6 @@ static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) return 0; } -static int ipc4_copier_set_capture_fmt(struct snd_sof_dev *sdev, - struct snd_pcm_hw_params *pipeline_params, - struct snd_pcm_hw_params *fe_params, - struct sof_ipc4_available_audio_format *available_fmt) -{ - struct sof_ipc4_audio_format *audio_fmt; - unsigned int sample_valid_bits; - bool multiple_formats = false; - bool fe_format_match = false; - struct snd_mask *fmt; - int i; - - for (i = 0; i < available_fmt->num_output_formats; i++) { - unsigned int val; - - audio_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; - val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(audio_fmt->fmt_cfg); - - if (i == 0) - sample_valid_bits = val; - else if (sample_valid_bits != val) - multiple_formats = true; - - if (snd_pcm_format_width(params_format(fe_params)) == val) - fe_format_match = true; - } - - fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); - snd_mask_none(fmt); - - if (multiple_formats) { - if (fe_format_match) { - /* multiple formats defined and one matches FE */ - snd_mask_set_format(fmt, params_format(fe_params)); - return 0; - } - - dev_err(sdev->dev, "Multiple audio formats for single dai_out not supported\n"); - return -EINVAL; - } - - return ipc4_set_fmt_mask(fmt, sample_valid_bits); -} - static int sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_pcm_hw_params *fe_params, @@ -1341,7 +1377,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt; struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc4_pin_format *format_list_to_search; struct sof_ipc4_copier_data *copier_data; struct snd_pcm_hw_params *ref_params; struct sof_ipc4_copier *ipc4_copier; @@ -1351,9 +1386,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, void **ipc_config_data; int *ipc_config_size; u32 **data; - int ipc_size, ret; + int ipc_size, ret, out_ref_valid_bits; + u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; - u32 format_list_count; + int output_fmt_index; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1417,13 +1453,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts * for capture. */ - if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - format_list_to_search = available_fmt->input_pin_fmts; - format_list_count = available_fmt->num_input_formats; - } else { - format_list_to_search = available_fmt->output_pin_fmts; - format_list_count = available_fmt->num_output_formats; - } + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ref_params = fe_params; + else + ref_params = pipeline_params; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id |= @@ -1431,7 +1464,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* set gateway attributes */ gtw_attr->lp_buffer_alloc = pipeline->lp_mode; - ref_params = fe_params; break; } case snd_soc_dapm_dai_in: @@ -1448,20 +1480,17 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ipc4_copier = (struct sof_ipc4_copier *)dai->private; copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; - if (dir == SNDRV_PCM_STREAM_CAPTURE) { - format_list_to_search = available_fmt->output_pin_fmts; - format_list_count = available_fmt->num_output_formats; - - ret = ipc4_copier_set_capture_fmt(sdev, pipeline_params, fe_params, - available_fmt); - if (ret < 0) - return ret; - } else { - format_list_to_search = available_fmt->input_pin_fmts; - format_list_count = available_fmt->num_input_formats; - } - ref_params = pipeline_params; + /* + * When there is format conversion within a pipeline, the number of supported + * output formats is typically limited to just 1 for the DAI copiers. But when there + * is no format conversion, the DAI copiers input format must match that of the + * FE hw_params for capture and the pipeline params for playback. + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ref_params = pipeline_params; + else + ref_params = fe_params; ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, ipc4_copier->dai_type, dir, @@ -1477,10 +1506,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, ipc4_copier = (struct sof_ipc4_copier *)swidget->private; copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; - - /* Use the input formats to match pcm params */ - format_list_to_search = available_fmt->input_pin_fmts; - format_list_count = available_fmt->num_input_formats; ref_params = pipeline_params; break; @@ -1492,11 +1517,51 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* set input and output audio formats */ - ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, - available_fmt, format_list_to_search, format_list_count); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, + available_fmt); if (ret < 0) return ret; + /* set the reference params for output format selection */ + switch (swidget->id) { + case snd_soc_dapm_aif_in: + case snd_soc_dapm_dai_out: + case snd_soc_dapm_buffer: + { + struct sof_ipc4_audio_format *in_fmt; + + in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + break; + } + case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai_in: + out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); + if (out_ref_valid_bits < 0) + return out_ref_valid_bits; + + out_ref_rate = params_rate(fe_params); + out_ref_channels = params_channels(fe_params); + break; + default: + /* + * Unsupported type should be caught by the former switch default + * case, this should never happen in reality. + */ + return -EINVAL; + } + + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, + available_fmt, out_ref_rate, + out_ref_channels, out_ref_valid_bits); + if (output_fmt_index < 0) { + dev_err(sdev->dev, "Failed to initialize output format for %s", + swidget->widget->name); + return output_fmt_index; + } + /* * Set the output format. Current topology defines pin 0 input and output formats in pairs. * This assumes that the pin 0 formats are defined before all other pins. @@ -1504,10 +1569,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * input format. This logic will need to be updated when the format definitions * in topology change. */ - memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[ret].audio_fmt, + memcpy(&copier_data->out_format, + &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, sizeof(struct sof_ipc4_audio_format)); dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[ret], 1); + sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1); switch (swidget->id) { case snd_soc_dapm_dai_in: @@ -1515,7 +1581,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, { /* * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. - * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt + * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt */ if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { struct sof_ipc4_alh_configuration_blob *blob; @@ -1650,7 +1716,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, *data, copier_data->gtw_cfg.config_length * 4); /* update pipeline memory usage */ - sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); + sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); return 0; } @@ -1664,17 +1730,30 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_gain *gain = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; + struct sof_ipc4_audio_format *in_fmt; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; int ret; - ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, - pipeline_params, available_fmt, - available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->base_config, + pipeline_params, available_fmt); if (ret < 0) return ret; + in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->base_config, available_fmt, + out_ref_rate, out_ref_channels, out_ref_valid_bits); + if (ret < 0) { + dev_err(sdev->dev, "Failed to initialize output format for %s", + swidget->widget->name); + return ret; + } + /* update pipeline memory usage */ - sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); + sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config); return 0; } @@ -1688,17 +1767,30 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_mixer *mixer = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; + struct sof_ipc4_audio_format *in_fmt; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; int ret; - ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, - pipeline_params, available_fmt, - available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config, + pipeline_params, available_fmt); if (ret < 0) return ret; + in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt, + out_ref_rate, out_ref_channels, out_ref_valid_bits); + if (ret < 0) { + dev_err(sdev->dev, "Failed to initialize output format for %s", + swidget->widget->name); + return ret; + } + /* update pipeline memory usage */ - sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); + sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config); return 0; } @@ -1712,18 +1804,30 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_src *src = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; + struct sof_ipc4_audio_format *in_fmt; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; struct snd_interval *rate; int ret; - ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, - pipeline_params, available_fmt, - available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config, + pipeline_params, available_fmt); if (ret < 0) return ret; + in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt, + out_ref_rate, out_ref_channels, out_ref_valid_bits); + if (ret < 0) { + dev_err(sdev->dev, "Failed to initialize output format for %s", + swidget->widget->name); + } + /* update pipeline memory usage */ - sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); + sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config); /* update pipeline_params for sink widgets */ rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); @@ -1820,20 +1924,37 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_process *process = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; + struct sof_ipc4_audio_format *in_fmt; + u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; void *cfg = process->ipc_config_data; + int output_fmt_index; int ret; - ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config, - pipeline_params, available_fmt, - available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config, + pipeline_params, available_fmt); if (ret < 0) return ret; + in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config, + available_fmt, out_ref_rate, + out_ref_channels, out_ref_valid_bits); + if (output_fmt_index < 0 && available_fmt->num_output_formats) { + dev_err(sdev->dev, "Failed to initialize output format for %s", + swidget->widget->name); + return output_fmt_index; + } + /* copy Pin 0 output format */ - if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats && - !available_fmt->output_pin_fmts[ret].pin_index) { - memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt, + if (available_fmt->num_output_formats && + output_fmt_index < available_fmt->num_output_formats && + !available_fmt->output_pin_fmts[output_fmt_index].pin_index) { + memcpy(&process->output_format, + &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, sizeof(struct sof_ipc4_audio_format)); /* modify the pipeline params with the pin 0 output format */ @@ -1843,7 +1964,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, } /* update pipeline memory usage */ - sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config); + sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config); /* ipc_config_data is composed of the base_config followed by an optional extension */ memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg)); @@ -2271,11 +2392,11 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, int sink_id) { struct sof_ipc4_copier_config_set_sink_format format; + const struct sof_ipc_ops *iops = sdev->ipc->ops; struct sof_ipc4_base_module_cfg *src_config; const struct sof_ipc4_audio_format *pin_fmt; struct sof_ipc4_fw_module *fw_module; struct sof_ipc4_msg msg = {{ 0 }}; - u32 header, extension; dev_dbg(sdev->dev, "%s set copier sink %d format\n", src_widget->widget->name, sink_id); @@ -2305,22 +2426,15 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, msg.data_size = sizeof(format); msg.data_ptr = &format; - header = fw_module->man4_module_entry.id; - header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); - header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); - header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); - header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.primary = fw_module->man4_module_entry.id; + msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); - extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size); - extension |= + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); - extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1); - extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); - - msg.primary = header; - msg.extension = extension; - return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, msg.data_size); + return iops->set_get_data(sdev, &msg, msg.data_size, true); } static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) @@ -2507,7 +2621,6 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * } gtw_attr = ipc4_copier->gtw_attr; gtw_attr->lp_buffer_alloc = pipeline->lp_mode; - pipeline->skip_during_fe_trigger = true; fallthrough; case SOF_DAI_INTEL_ALH: /* diff --git a/sound/soc/sof/mediatek/mt8186/mt8186-clk.c b/sound/soc/sof/mediatek/mt8186/mt8186-clk.c index 2df3b7ae1c6f..cb2ab5884b8c 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186-clk.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186-clk.c @@ -8,7 +8,6 @@ // Hardware interface for mt8186 DSP clock #include <linux/clk.h> -#include <linux/pm_runtime.h> #include <linux/io.h> #include "../../sof-audio.h" diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 597cb4476acb..cc91c2928fb6 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -48,47 +48,13 @@ static int mt8186_send_msg(struct snd_sof_dev *sdev, return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); } -static void mt8186_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply has correct size? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc) { struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - mt8186_get_reply(priv->sdev); - snd_sof_ipc_reply(priv->sdev, 0); + snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } @@ -628,7 +594,65 @@ static const struct sof_dev_desc sof_of_mt8186_desc = { .ops = &sof_mt8186_ops, }; +/* + * DL2, DL3, UL4, UL5 are registered as SOF FE, so creating the corresponding + * SOF BE to complete the pipeline. + */ +static struct snd_soc_dai_driver mt8188_dai[] = { +{ + .name = "SOF_DL2", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_DL3", + .playback = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL4", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +{ + .name = "SOF_UL5", + .capture = { + .channels_min = 1, + .channels_max = 2, + }, +}, +}; + +/* mt8188 ops */ +static struct snd_sof_dsp_ops sof_mt8188_ops; + +static int sof_mt8188_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_mt8188_ops, &sof_mt8186_ops, sizeof(sof_mt8188_ops)); + + sof_mt8188_ops.drv = mt8188_dai; + sof_mt8188_ops.num_drv = ARRAY_SIZE(mt8188_dai); + + return 0; +} + +static struct snd_sof_of_mach sof_mt8188_machs[] = { + { + .compatible = "mediatek,mt8188", + .sof_tplg_filename = "sof-mt8188.tplg", + }, + {} +}; + static const struct sof_dev_desc sof_of_mt8188_desc = { + .of_machines = sof_mt8188_machs, .ipc_supported_mask = BIT(SOF_IPC), .ipc_default = SOF_IPC, .default_fw_path = { @@ -641,7 +665,8 @@ static const struct sof_dev_desc sof_of_mt8188_desc = { [SOF_IPC] = "sof-mt8188.ri", }, .nocodec_tplg_filename = "sof-mt8188-nocodec.tplg", - .ops = &sof_mt8186_ops, + .ops = &sof_mt8188_ops, + .ops_init = sof_mt8188_ops_init, }; static const struct of_device_id sof_of_mt8186_ids[] = { diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c index 9ef08e43aa38..7cffcad00f9b 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -7,7 +7,6 @@ // Hardware interface for mt8195 DSP clock #include <linux/clk.h> -#include <linux/pm_runtime.h> #include <linux/io.h> #include "mt8195.h" #include "mt8195-clk.h" diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 42bae574c87a..7d6a568556ea 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -49,47 +49,13 @@ static int mt8195_send_msg(struct snd_sof_dev *sdev, return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); } -static void mt8195_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply has correct size? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc) { struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - mt8195_get_reply(priv->sdev); - snd_sof_ipc_reply(priv->sdev, 0); + snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index b13bfdeb2b70..7c5bb9badb6c 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -32,7 +32,7 @@ static int sof_nocodec_bes_setup(struct device *dev, /* set up BE dai_links */ for (i = 0; i < link_num; i++) { - dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); + dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; @@ -44,8 +44,8 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].stream_name = links[i].name; links[i].cpus = &dlc[0]; - links[i].codecs = &dlc[1]; - links[i].platforms = &dlc[2]; + links[i].codecs = &asoc_dummy_dlc; + links[i].platforms = &dlc[1]; links[i].num_cpus = 1; links[i].num_codecs = 1; @@ -55,8 +55,6 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].no_pcm = 1; links[i].cpus->dai_name = drv[i].name; links[i].platforms->name = dev_name(dev->parent); - links[i].codecs->dai_name = "snd-soc-dummy-dai"; - links[i].codecs->name = "snd-soc-dummy"; if (drv[i].playback.channels_min) links[i].dpcm_playback = 1; if (drv[i].capture.channels_min) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d0ab6f390734..d778717cab10 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -369,7 +369,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ - if (!pcm_ops || (pcm_ops && !pcm_ops->platform_stop_during_hw_free)) + if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free) snd_sof_pcm_platform_trigger(sdev, substream, cmd); break; default: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index a090a9eb4828..5d5eeb1a1a6f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -362,6 +362,7 @@ struct snd_sof_control { size_t priv_size; /* size of private data */ size_t max_size; void *ipc_control_data; + void *old_ipc_control_data; int max; /* applicable to volume controls */ u32 size; /* cdata size */ u32 *volume_table; /* volume table computed from tlv data*/ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f160dc454b44..698129dccc7d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1077,7 +1077,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || - strcmp(w->sname, rtd->dai_link->stream_name)) + !strstr(rtd->dai_link->stream_name, w->sname)) continue; for_each_rtd_cpu_dais(rtd, i, cpu_dai) { diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index f6695dee353b..271ec5b3378d 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1485,12 +1485,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (ret < 0) return ret; } else { - sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK"); - if (IS_ERR(sai->sai_mclk)) { - if (PTR_ERR(sai->sai_mclk) != -ENOENT) - return PTR_ERR(sai->sai_mclk); - sai->sai_mclk = NULL; - } + sai->sai_mclk = devm_clk_get_optional(&pdev->dev, "MCLK"); + if (IS_ERR(sai->sai_mclk)) + return PTR_ERR(sai->sai_mclk); } return 0; diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index c498145e76e0..a4073a746ae3 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -19,7 +19,6 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> -#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/reset.h> #include <linux/slab.h> diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 41117c1d61fb..bd0b10c70c4c 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -109,7 +109,7 @@ static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev) static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, unsigned int channels, - unsigned int format, + snd_pcm_format_t format, unsigned int reg) { struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai); diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index c0892be2992b..172fea764a31 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1328,15 +1328,16 @@ static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params, struct davinci_mcasp_ruledata *rd = rule->private; struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_mask nfmt; - int i, slot_width; + int slot_width; + snd_pcm_format_t i; snd_mask_none(&nfmt); slot_width = rd->mcasp->slot_width; - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(fmt, i)) { + pcm_for_each_format(i) { + if (snd_mask_test_format(fmt, i)) { if (snd_pcm_format_width(i) <= slot_width) { - snd_mask_set(&nfmt, i); + snd_mask_set_format(&nfmt, i); } } } @@ -1350,15 +1351,16 @@ static int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params, struct davinci_mcasp_ruledata *rd = rule->private; struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_mask nfmt; - int i, format_width; + int format_width; + snd_pcm_format_t i; snd_mask_none(&nfmt); format_width = rd->mcasp->max_format_width; - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(fmt, i)) { + pcm_for_each_format(i) { + if (snd_mask_test_format(fmt, i)) { if (snd_pcm_format_width(i) == format_width) { - snd_mask_set(&nfmt, i); + snd_mask_set_format(&nfmt, i); } } } @@ -1431,12 +1433,13 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, struct snd_mask nfmt; int rate = params_rate(params); int slots = rd->mcasp->tdm_slots; - int i, count = 0; + int count = 0; + snd_pcm_format_t i; snd_mask_none(&nfmt); - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(fmt, i)) { + pcm_for_each_format(i) { + if (snd_mask_test_format(fmt, i)) { uint sbits = snd_pcm_format_width(i); unsigned int sysclk_freq; int ppm; @@ -1454,7 +1457,7 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, sbits * slots * rate, false); if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { - snd_mask_set(&nfmt, i); + snd_mask_set_format(&nfmt, i); count++; } } diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index 96c3569d7643..a3663ab065ac 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -365,19 +365,17 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) if (!card->dai_link) return -ENOMEM; - compnent = devm_kzalloc(dev, 2 * sizeof(*compnent), GFP_KERNEL); + compnent = devm_kzalloc(dev, sizeof(*compnent), GFP_KERNEL); if (!compnent) return -ENOMEM; - card->dai_link->cpus = &compnent[0]; + card->dai_link->cpus = compnent; card->dai_link->num_cpus = 1; - card->dai_link->codecs = &compnent[1]; + card->dai_link->codecs = &asoc_dummy_dlc; card->dai_link->num_codecs = 1; card->dai_link->name = card->name; card->dai_link->stream_name = card->name; card->dai_link->cpus->dai_name = dev_name(ad->dssdev); - card->dai_link->codecs->name = "snd-soc-dummy"; - card->dai_link->codecs->dai_name = "snd-soc-dummy-dai"; card->num_links = 1; card->dev = dev; diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c index 8163f453bf36..b047add5d887 100644 --- a/sound/soc/ti/omap-mcbsp-st.c +++ b/sound/soc/ti/omap-mcbsp-st.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/slab.h> -#include <linux/pm_runtime.h> #include "omap-mcbsp.h" #include "omap-mcbsp-priv.h" |