diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml index 37423c2e0fdf..b67fbe0e7a63 100644 --- a/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6357.yaml @@ -37,6 +37,24 @@ properties: "#interrupt-cells": const: 2 + mediatek,hp-pull-down: + description: + Earphone driver positive output stage short to + the audio reference ground. + type: boolean + + mediatek,micbias0-microvolt: + description: Selects MIC Bias 0 output voltage. + enum: [1700000, 1800000, 1900000, 2000000, + 2100000, 2500000, 2600000, 2700000] + default: 1700000 + + mediatek,micbias1-microvolt: + description: Selects MIC Bias 1 output voltage. + enum: [1700000, 1800000, 1900000, 2000000, + 2100000, 2500000, 2600000, 2700000] + default: 1700000 + regulators: type: object $ref: /schemas/regulator/mediatek,mt6357-regulator.yaml @@ -83,6 +101,9 @@ examples: interrupt-controller; #interrupt-cells = <2>; + mediatek,micbias0-microvolt = <1700000>; + mediatek,micbias1-microvolt = <1700000>; + regulators { mt6357_vproc_reg: buck-vproc { regulator-name = "vproc"; diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml index 5db718e4d0e7..4f13e8ab50b2 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml @@ -26,6 +26,13 @@ properties: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name + clocks: + minItems: 1 + maxItems: 3 + description: + Base PLL clocks of audio susbsytem, used to configure base clock + frequencies for different audio use-cases. + patternProperties: "^dai-link-[0-9]+$": type: object diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index 0ecdaf7190e9..413b47778181 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -27,6 +27,13 @@ properties: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name + clocks: + minItems: 1 + maxItems: 3 + description: + Base PLL clocks of audio susbsytem, used to configure base clock + frequencies for different audio use-cases. + patternProperties: "^dai-link-[0-9]+$": type: object diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml new file mode 100644 index 000000000000..68fbf5cc208f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs4271.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS4271 audio CODEC + +maintainers: + - Alexander Sverdlin + - Nikita Shubin + +description: + The CS4271 is a stereo audio codec. This device supports both the I2C + and the SPI bus. + +allOf: + - $ref: dai-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + const: cirrus,cs4271 + + reg: + maxItems: 1 + + spi-cpha: true + + spi-cpol: true + + '#sound-dai-cells': + const: 0 + + reset-gpios: + description: + This pin will be deasserted before communication to the codec starts. + maxItems: 1 + + va-supply: + description: Analog power supply. + + vd-supply: + description: Digital power supply. + + vl-supply: + description: Serial Control Port power supply. + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + + cirrus,amuteb-eq-bmutec: + description: + When given, the Codec's AMUTEB=BMUTEC flag is enabled. + type: boolean + + cirrus,enable-soft-reset: + description: | + The CS4271 requires its LRCLK and MCLK to be stable before its RESET + line is de-asserted. That also means that clocks cannot be changed + without putting the chip back into hardware reset, which also requires + a complete re-initialization of all registers. + + One (undocumented) workaround is to assert and de-assert the PDN bit + in the MODE2 register. This workaround can be enabled with this DT + property. + + Note that this is not needed in case the clocks are stable + throughout the entire runtime of the codec. + type: boolean + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + codec@0 { + compatible = "cirrus,cs4271"; + reg = <0>; + #sound-dai-cells = <0>; + spi-max-frequency = <6000000>; + spi-cpol; + spi-cpha; + reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + port { + endpoint { + remote-endpoint = <&i2s_ep>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt deleted file mode 100644 index 6e699ceabacd..000000000000 --- a/Documentation/devicetree/bindings/sound/cs4271.txt +++ /dev/null @@ -1,57 +0,0 @@ -Cirrus Logic CS4271 DT bindings - -This driver supports both the I2C and the SPI bus. - -Required properties: - - - compatible: "cirrus,cs4271" - -For required properties on SPI, please consult -Documentation/devicetree/bindings/spi/spi-bus.txt - -Required properties on I2C: - - - reg: the i2c address - - -Optional properties: - - - reset-gpio: a GPIO spec to define which pin is connected to the chip's - !RESET pin - - cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag - is enabled. - - cirrus,enable-soft-reset: - The CS4271 requires its LRCLK and MCLK to be stable before its RESET - line is de-asserted. That also means that clocks cannot be changed - without putting the chip back into hardware reset, which also requires - a complete re-initialization of all registers. - - One (undocumented) workaround is to assert and de-assert the PDN bit - in the MODE2 register. This workaround can be enabled with this DT - property. - - Note that this is not needed in case the clocks are stable - throughout the entire runtime of the codec. - - - vd-supply: Digital power - - vl-supply: Logic power - - va-supply: Analog Power - -Examples: - - codec_i2c: cs4271@10 { - compatible = "cirrus,cs4271"; - reg = <0x10>; - reset-gpio = <&gpio 23 0>; - vd-supply = <&vdd_3v3_reg>; - vl-supply = <&vdd_3v3_reg>; - va-supply = <&vdd_3v3_reg>; - }; - - codec_spi: cs4271@0 { - compatible = "cirrus,cs4271"; - reg = <0x0>; - reset-gpio = <&gpio 23 0>; - spi-max-frequency = <6000000>; - }; - diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt deleted file mode 100644 index 94584c96c4ae..000000000000 --- a/Documentation/devicetree/bindings/sound/da7213.txt +++ /dev/null @@ -1,45 +0,0 @@ -Dialog Semiconductor DA7212/DA7213 Audio Codec bindings - -====== - -Required properties: -- compatible : Should be "dlg,da7212" or "dlg,da7213" -- reg: Specifies the I2C slave address - -Optional properties: -- clocks : phandle and clock specifier for codec MCLK. -- clock-names : Clock name string for 'clocks' attribute, should be "mclk". - -- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1 - [<1600>, <2200>, <2500>, <3000>] -- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2 - [<1600>, <2200>, <2500>, <3000>] -- dlg,dmic-data-sel : DMIC channel select based on clock edge. - ["lrise_rfall", "lfall_rrise"] -- dlg,dmic-samplephase : When to sample audio from DMIC. - ["on_clkedge", "between_clkedge"] -- dlg,dmic-clkrate : DMIC clock frequency (Hz). - [<1500000>, <3000000>] - - - VDDA-supply : Regulator phandle for Analogue power supply - - VDDMIC-supply : Regulator phandle for Mic Bias - - VDDIO-supply : Regulator phandle for I/O power supply - -====== - -Example: - - codec_i2c: da7213@1a { - compatible = "dlg,da7213"; - reg = <0x1a>; - - clocks = <&clks 201>; - clock-names = "mclk"; - - dlg,micbias1-lvl = <2500>; - dlg,micbias2-lvl = <2500>; - - dlg,dmic-data-sel = "lrise_rfall"; - dlg,dmic-samplephase = "between_clkedge"; - dlg,dmic-clkrate = <3000000>; - }; diff --git a/Documentation/devicetree/bindings/sound/dlg,da7213.yaml b/Documentation/devicetree/bindings/sound/dlg,da7213.yaml new file mode 100644 index 000000000000..c2dede1e82ff --- /dev/null +++ b/Documentation/devicetree/bindings/sound/dlg,da7213.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/dlg,da7213.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dialog Semiconductor DA7212/DA7213 Audio Codec + +maintainers: + - Support Opensource + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - dlg,da7212 + - dlg,da7213 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + "#sound-dai-cells": + const: 0 + + dlg,micbias1-lvl: + description: Voltage (mV) for Mic Bias 1 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1600, 2200, 2500, 3000 ] + + dlg,micbias2-lvl: + description: Voltage (mV) for Mic Bias 2 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1600, 2200, 2500, 3000 ] + + dlg,dmic-data-sel: + description: DMIC channel select based on clock edge + enum: [ lrise_rfall, lfall_rrise ] + + dlg,dmic-samplephase: + description: When to sample audio from DMIC + enum: [ on_clkedge, between_clkedge ] + + dlg,dmic-clkrate: + description: DMIC clock frequency (Hz) + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1500000, 3000000 ] + + VDDA-supply: + description: Analogue power supply + + VDDIO-supply: + description: I/O power supply + + VDDMIC-supply: + description: Mic Bias + + VDDSP-supply: + description: Speaker supply + + ports: + $ref: audio-graph-port.yaml#/definitions/ports + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "dlg,da7213"; + reg = <0x1a>; + + clocks = <&clks 201>; + clock-names = "mclk"; + + #sound-dai-cells = <0>; + + dlg,micbias1-lvl = <2500>; + dlg,micbias2-lvl = <2500>; + + dlg,dmic-data-sel = "lrise_rfall"; + dlg,dmic-samplephase = "between_clkedge"; + dlg,dmic-clkrate = <3000000>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml new file mode 100644 index 000000000000..5eb6f5812cf2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,imx-audio-es8328.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX audio complex with ES8328 codec + +maintainers: + - Shawn Guo + - Sascha Hauer + +allOf: + - $ref: sound-card-common.yaml# + +properties: + compatible: + const: fsl,imx-audio-es8328 + + model: + $ref: /schemas/types.yaml#/definitions/string + description: The user-visible name of this sound complex + + ssi-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the i.MX SSI controller + + jack-gpio: + description: Optional GPIO for headphone jack + maxItems: 1 + + audio-amp-supply: + description: Power regulator for speaker amps + + audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle to the ES8328 audio codec + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. Each entry + is a pair of strings, the first being the connection's sink, the second + being the connection's source. Valid names could be power supplies, + ES8328 pins, and the jacks on the board: + + Power supplies: + * audio-amp + + ES8328 pins: + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * LINPUT2 + * RINPUT1 + * RINPUT2 + * Mic PGA + + Board connectors: + * Headphone + * Speaker + * Mic Jack + + mux-int-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The internal port of the i.MX audio muxer (AUDMUX) + enum: [1, 2, 7] + default: 1 + + mux-ext-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The external port of the i.MX audio muxer (AUDMIX) + enum: [3, 4, 5, 6] + default: 3 + +required: + - compatible + - model + - ssi-controller + - jack-gpio + - audio-amp-supply + - audio-codec + - audio-routing + - mux-int-port + - mux-ext-port + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "fsl,imx-audio-es8328"; + model = "imx-audio-es8328"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + jack-gpio = <&gpio5 15 0>; + audio-amp-supply = <®_audio_amp>; + audio-routing = + "Speaker", "LOUT2", + "Speaker", "ROUT2", + "Speaker", "audio-amp", + "Headphone", "ROUT1", + "Headphone", "LOUT1", + "LINPUT1", "Mic Jack", + "RINPUT1", "Mic Jack", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <3>; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl,saif.yaml b/Documentation/devicetree/bindings/sound/fsl,saif.yaml new file mode 100644 index 000000000000..0b5db6bb1b7c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,saif.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,saif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale MXS Serial Audio Interface (SAIF) + +maintainers: + - Lukasz Majewski + +allOf: + - $ref: dai-common.yaml# + +description: + The SAIF is based on I2S module that is used to communicate with audio codecs, + but only with half-duplex manner (i.e. it can either transmit or receive PCM + audio). + +properties: + compatible: + const: fsl,imx28-saif + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + interrupts: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + const: rx-tx + + "#clock-cells": + description: Configure the I2S device as MCLK clock provider. + const: 0 + + clocks: + maxItems: 1 + + fsl,saif-master: + description: Indicate that saif is a slave and its phandle points to master + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - reg + - "#sound-dai-cells" + - interrupts + - dmas + - dma-names + - clocks + +unevaluatedProperties: false + +examples: + - | + saif0: saif@80042000 { + compatible = "fsl,imx28-saif"; + reg = <0x80042000 2000>; + #sound-dai-cells = <0>; + interrupts = <59>; + dmas = <&dma_apbx 4>; + dma-names = "rx-tx"; + #clock-cells = <0>; + clocks = <&clks 53>; + }; + - | + saif1: saif@80046000 { + compatible = "fsl,imx28-saif"; + reg = <0x80046000 2000>; + #sound-dai-cells = <0>; + interrupts = <58>; + dmas = <&dma_apbx 5>; + dma-names = "rx-tx"; + clocks = <&clks 53>; + fsl,saif-master = <&saif0>; + }; diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt deleted file mode 100644 index 07b68ab206fb..000000000000 --- a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt +++ /dev/null @@ -1,60 +0,0 @@ -Freescale i.MX audio complex with ES8328 codec - -Required properties: -- compatible : "fsl,imx-audio-es8328" -- model : The user-visible name of this sound complex -- ssi-controller : The phandle of the i.MX SSI controller -- jack-gpio : Optional GPIO for headphone jack -- audio-amp-supply : Power regulator for speaker amps -- audio-codec : The phandle of the ES8328 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, ES8328 - pins, and the jacks on the board: - - Power supplies: - * audio-amp - - ES8328 pins: - * LOUT1 - * LOUT2 - * ROUT1 - * ROUT2 - * LINPUT1 - * LINPUT2 - * RINPUT1 - * RINPUT2 - * Mic PGA - - Board connectors: - * Headphone - * Speaker - * Mic Jack -- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) -- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX) - -Note: The AUDMUX port numbering should start at 1, which is consistent with -hardware manual. - -Example: - -sound { - compatible = "fsl,imx-audio-es8328"; - model = "imx-audio-es8328"; - ssi-controller = <&ssi1>; - audio-codec = <&codec>; - jack-gpio = <&gpio5 15 0>; - audio-amp-supply = <®_audio_amp>; - audio-routing = - "Speaker", "LOUT2", - "Speaker", "ROUT2", - "Speaker", "audio-amp", - "Headphone", "ROUT1", - "Headphone", "LOUT1", - "LINPUT1", "Mic Jack", - "RINPUT1", "Mic Jack", - "Mic Jack", "Mic Bias"; - mux-int-port = <1>; - mux-ext-port = <3>; -}; diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml new file mode 100644 index 000000000000..45ad56d37234 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-afe.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-afe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Audio Front End PCM controller for MT8365 + +maintainers: + - Alexandre Mergnat + +properties: + compatible: + const: mediatek,mt8365-afe-pcm + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + items: + - description: 26M clock + - description: mux for audio clock + - description: audio i2s0 mck + - description: audio i2s1 mck + - description: audio i2s2 mck + - description: audio i2s3 mck + - description: engen 1 clock + - description: engen 2 clock + - description: audio 1 clock + - description: audio 2 clock + - description: mux for i2s0 + - description: mux for i2s1 + - description: mux for i2s2 + - description: mux for i2s3 + + clock-names: + items: + - const: top_clk26m_clk + - const: top_audio_sel + - const: audio_i2s0_m + - const: audio_i2s1_m + - const: audio_i2s2_m + - const: audio_i2s3_m + - const: engen1 + - const: engen2 + - const: aud1 + - const: aud2 + - const: i2s0_m_sel + - const: i2s1_m_sel + - const: i2s2_m_sel + - const: i2s3_m_sel + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + mediatek,dmic-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Indicates how many data pins are used to transmit two channels of PDM + signal. 1 means two wires, 0 means one wire. Default value is 0. + enum: + - 0 # one wire + - 1 # two wires + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + audio-controller@11220000 { + compatible = "mediatek,mt8365-afe-pcm"; + reg = <0 0x11220000 0 0x1000>; + #sound-dai-cells = <0>; + clocks = <&clk26m>, + <&topckgen CLK_TOP_AUDIO_SEL>, + <&topckgen CLK_TOP_AUD_I2S0_M>, + <&topckgen CLK_TOP_AUD_I2S1_M>, + <&topckgen CLK_TOP_AUD_I2S2_M>, + <&topckgen CLK_TOP_AUD_I2S3_M>, + <&topckgen CLK_TOP_AUD_ENGEN1_SEL>, + <&topckgen CLK_TOP_AUD_ENGEN2_SEL>, + <&topckgen CLK_TOP_AUD_1_SEL>, + <&topckgen CLK_TOP_AUD_2_SEL>, + <&topckgen CLK_TOP_APLL_I2S0_SEL>, + <&topckgen CLK_TOP_APLL_I2S1_SEL>, + <&topckgen CLK_TOP_APLL_I2S2_SEL>, + <&topckgen CLK_TOP_APLL_I2S3_SEL>; + clock-names = "top_clk26m_clk", + "top_audio_sel", + "audio_i2s0_m", + "audio_i2s1_m", + "audio_i2s2_m", + "audio_i2s3_m", + "engen1", + "engen2", + "aud1", + "aud2", + "i2s0_m_sel", + "i2s1_m_sel", + "i2s2_m_sel", + "i2s3_m_sel"; + interrupts = ; + power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>; + mediatek,dmic-mode = <1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml new file mode 100644 index 000000000000..ff9ebb63a05f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8365-mt6357.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT8365 ASoC sound card + +maintainers: + - Alexandre Mergnat + +properties: + compatible: + const: mediatek,mt8365-mt6357 + + pinctrl-names: + minItems: 1 + items: + - const: default + - const: dmic + - const: miso_off + - const: miso_on + - const: mosi_off + - const: mosi_on + + mediatek,platform: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of MT8365 ASoC platform. + +patternProperties: + "^dai-link-[0-9]+$": + type: object + description: + Container for dai-link level properties and CODEC sub-nodes. + + properties: + codec: + type: object + description: Holds subnode which indicates codec dai. + + properties: + sound-dai: + maxItems: 1 + description: phandle of the codec DAI + + additionalProperties: false + + link-name: + description: Indicates dai-link name and PCM stream name + enum: + - I2S_IN_BE + - I2S_OUT_BE + - PCM1_BE + - PDM1_BE + - PDM2_BE + - PDM3_BE + - PDM4_BE + - SPDIF_IN_BE + - SPDIF_OUT_BE + - TDM_IN_BE + - TDM_OUT_BE + + sound-dai: + maxItems: 1 + description: phandle of the CPU DAI + + required: + - link-name + - sound-dai + + additionalProperties: false + +required: + - compatible + - pinctrl-names + - mediatek,platform + +additionalProperties: false + +examples: + - | + sound { + compatible = "mediatek,mt8365-mt6357"; + pinctrl-names = "default", + "dmic", + "miso_off", + "miso_on", + "mosi_off", + "mosi_on"; + pinctrl-0 = <&aud_default_pins>; + pinctrl-1 = <&aud_dmic_pins>; + pinctrl-2 = <&aud_miso_off_pins>; + pinctrl-3 = <&aud_miso_on_pins>; + pinctrl-4 = <&aud_mosi_off_pins>; + pinctrl-5 = <&aud_mosi_on_pins>; + mediatek,platform = <&afe>; + + /* hdmi interface */ + dai-link-0 { + link-name = "I2S_OUT_BE"; + sound-dai = <&afe>; + + codec { + sound-dai = <&it66121hdmitx>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml index 2f43c684ab88..7fbab5871be4 100644 --- a/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml +++ b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml @@ -13,6 +13,9 @@ description: The Microchip Sony/Philips Digital Interface Receiver is a serial port compliant with the IEC-60958 standard. +allOf: + - $ref: dai-common.yaml# + properties: "#sound-dai-cells": const: 0 @@ -53,7 +56,7 @@ required: - dmas - dma-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/mxs-saif.txt b/Documentation/devicetree/bindings/sound/mxs-saif.txt deleted file mode 100644 index 7ba07a118e37..000000000000 --- a/Documentation/devicetree/bindings/sound/mxs-saif.txt +++ /dev/null @@ -1,41 +0,0 @@ -* Freescale MXS Serial Audio Interface (SAIF) - -Required properties: -- compatible: Should be "fsl,-saif" -- reg: Should contain registers location and length -- interrupts: Should contain ERROR interrupt number -- dmas: DMA specifier, consisting of a phandle to DMA controller node - and SAIF DMA channel ID. - Refer to dma.txt and fsl-mxs-dma.txt for details. -- dma-names: Must be "rx-tx". - -Optional properties: -- fsl,saif-master: phandle to the master SAIF. It's only required for - the slave SAIF. - -Note: Each SAIF controller should have an alias correctly numbered -in "aliases" node. - -Example: - -aliases { - saif0 = &saif0; - saif1 = &saif1; -}; - -saif0: saif@80042000 { - compatible = "fsl,imx28-saif"; - reg = <0x80042000 2000>; - interrupts = <59>; - dmas = <&dma_apbx 4>; - dma-names = "rx-tx"; -}; - -saif1: saif@80046000 { - compatible = "fsl,imx28-saif"; - reg = <0x80046000 2000>; - interrupts = <58>; - dmas = <&dma_apbx 5>; - dma-names = "rx-tx"; - fsl,saif-master = <&saif0>; -}; diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt deleted file mode 100644 index 47878a6df608..000000000000 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt +++ /dev/null @@ -1,53 +0,0 @@ -PCM512x and TAS575x audio CODECs/amplifiers - -These devices support both I2C and SPI (configured with pin strapping -on the board). The TAS575x devices only support I2C. - -Required properties: - - - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141", - "ti,pcm5142", "ti,pcm5242", "ti,tas5754" or "ti,tas5756" - - - reg : the I2C address of the device for I2C, the chip select - number for SPI. - - - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the - device, as covered in bindings/regulator/regulator.txt - -Optional properties: - - - clocks : A clock specifier for the clock connected as SCLK. If this - is absent the device will be configured to clock from BCLK. If pll-in - and pll-out are specified in addition to a clock, the device is - configured to accept clock input on a specified gpio pin. - - - pll-in, pll-out : gpio pins used to connect the pll using <1> - through <6>. The device will be configured for clock input on the - given pll-in pin and PLL output on the given pll-out pin. An - external connection from the pll-out pin to the SCLK pin is assumed. - Caution: the TAS-desvices only support gpios 1,2 and 3 - -Examples: - - pcm5122: pcm5122@4c { - compatible = "ti,pcm5122"; - reg = <0x4c>; - - AVDD-supply = <®_3v3_analog>; - DVDD-supply = <®_1v8>; - CPVDD-supply = <®_3v3>; - }; - - - pcm5142: pcm5142@4c { - compatible = "ti,pcm5142"; - reg = <0x4c>; - - AVDD-supply = <®_3v3_analog>; - DVDD-supply = <®_1v8>; - CPVDD-supply = <®_3v3>; - - clocks = <&sck>; - pll-in = <3>; - pll-out = <6>; - }; diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml new file mode 100644 index 000000000000..6ad451549036 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml @@ -0,0 +1,205 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,apq8016-sbc-sndcard.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm APQ8016 and similar sound cards + +maintainers: + - Srinivas Kandagatla + - Stephan Gerhold + +properties: + compatible: + enum: + - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard + + reg: + items: + - description: Microphone I/O mux register address + - description: Speaker I/O mux register address + + reg-names: + items: + - const: mic-iomux + - const: spkr-iomux + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: + A list of the connections between audio components. Each entry is a + pair of strings, the first being the connection's sink, the second + being the connection's source. Valid names could be power supplies, + MicBias of codec and the jacks on the board. + + aux-devs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + + model: + $ref: /schemas/types.yaml#/definitions/string + description: User visible long sound card name + + pin-switches: + description: List of widget names for which pin switches should be created. + $ref: /schemas/types.yaml#/definitions/string-array + + widgets: + description: User specified audio sound widgets. + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + +patternProperties: + ".*-dai-link$": + description: + Each subnode represents a dai link. Subnodes of each dai links would be + cpu/codec dais. + + type: object + + properties: + link-name: + description: Indicates dai-link name and PCM stream name. + $ref: /schemas/types.yaml#/definitions/string + maxItems: 1 + + cpu: + description: Holds subnode which indicates cpu dai. + type: object + additionalProperties: false + + properties: + sound-dai: + maxItems: 1 + + platform: + description: Holds subnode which indicates platform dai. + type: object + additionalProperties: false + + properties: + sound-dai: + maxItems: 1 + + codec: + description: Holds subnode which indicates codec dai. + type: object + additionalProperties: false + + properties: + sound-dai: + minItems: 1 + maxItems: 8 + + required: + - link-name + - cpu + + additionalProperties: false + +required: + - compatible + - reg + - reg-names + - model + +additionalProperties: false + +examples: + - | + #include + sound@7702000 { + compatible = "qcom,apq8016-sbc-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "DB410c"; + audio-routing = + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; + pinctrl-names = "default", "sleep"; + + quaternary-dai-link { + link-name = "ADV7533"; + cpu { + sound-dai = <&lpass MI2S_QUATERNARY>; + }; + codec { + sound-dai = <&adv_bridge 0>; + }; + }; + + primary-dai-link { + link-name = "WCD"; + cpu { + sound-dai = <&lpass MI2S_PRIMARY>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + + tertiary-dai-link { + link-name = "WCD-Capture"; + cpu { + sound-dai = <&lpass MI2S_TERTIARY>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; + }; + }; + }; + + - | + #include + #include + sound@7702000 { + compatible = "qcom,msm8916-qdsp6-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "msm8916"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; + audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; + aux-devs = <&speaker_amp>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cdc_pdm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + primary-dai-link { + link-name = "Primary MI2S"; + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index 06b5f7be3608..6f5644a89feb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -64,6 +64,7 @@ allOf: compatible: enum: - qcom,sc7280-lpass-wsa-macro + - qcom,sm8250-lpass-wsa-macro - qcom,sm8450-lpass-wsa-macro - qcom,sc8280xp-lpass-wsa-macro then: @@ -79,24 +80,6 @@ allOf: - const: dcodec - const: fsgen - - if: - properties: - compatible: - enum: - - qcom,sm8250-lpass-wsa-macro - then: - properties: - clocks: - minItems: 6 - clock-names: - items: - - const: mclk - - const: npl - - const: macro - - const: dcodec - - const: va - - const: fsgen - - if: properties: compatible: @@ -130,8 +113,7 @@ examples: <&audiocc 0>, <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&aoncc LPASS_CDC_VA_MCLK>, <&vamacro>; - clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen"; + clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; clock-output-names = "mclk"; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index c9076dcd44c1..1d3acdc0c733 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -27,9 +27,7 @@ properties: - qcom,sm8650-sndcard - const: qcom,sm8450-sndcard - enum: - - qcom,apq8016-sbc-sndcard - qcom,apq8096-sndcard - - qcom,msm8916-qdsp6-sndcard - qcom,qcm6490-idp-sndcard - qcom,qcs6490-rb3gen2-sndcard - qcom,qrb5165-rb5-sndcard @@ -58,18 +56,6 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name - pin-switches: - description: List of widget names for which pin switches should be created. - $ref: /schemas/types.yaml#/definitions/string-array - - widgets: - description: User specified audio sound widgets. - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - - # Only valid for some compatibles (see allOf if below) - reg: true - reg-names: true - patternProperties: ".*-dai-link$": description: @@ -122,34 +108,6 @@ required: - compatible - model -allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,apq8016-sbc-sndcard - - qcom,msm8916-qdsp6-sndcard - then: - properties: - reg: - items: - - description: Microphone I/O mux register address - - description: Speaker I/O mux register address - reg-names: - items: - - const: mic-iomux - - const: spkr-iomux - required: - - compatible - - model - - reg - - reg-names - else: - properties: - reg: false - reg-names: false - additionalProperties: false examples: @@ -231,98 +189,3 @@ examples: }; }; }; - - - | - #include - sound@7702000 { - compatible = "qcom,apq8016-sbc-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - - model = "DB410c"; - audio-routing = - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS External1"; - - pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; - pinctrl-names = "default", "sleep"; - - quaternary-dai-link { - link-name = "ADV7533"; - cpu { - sound-dai = <&lpass MI2S_QUATERNARY>; - }; - codec { - sound-dai = <&adv_bridge 0>; - }; - }; - - primary-dai-link { - link-name = "WCD"; - cpu { - sound-dai = <&lpass MI2S_PRIMARY>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - - tertiary-dai-link { - link-name = "WCD-Capture"; - cpu { - sound-dai = <&lpass MI2S_TERTIARY>; - }; - codec { - sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; - }; - }; - }; - - - | - #include - #include - sound@7702000 { - compatible = "qcom,msm8916-qdsp6-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - - model = "msm8916"; - widgets = - "Speaker", "Speaker", - "Headphone", "Headphones"; - pin-switches = "Speaker"; - audio-routing = - "Speaker", "Speaker Amp OUT", - "Speaker Amp IN", "HPH_R", - "Headphones", "HPH_L", - "Headphones", "HPH_R", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal3"; - aux-devs = <&speaker_amp>; - - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - - mm1-dai-link { - link-name = "MultiMedia1"; - cpu { - sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; - }; - }; - - primary-dai-link { - link-name = "Primary MI2S"; - cpu { - sound-dai = <&q6afedai PRIMARY_MI2S_RX>; - }; - platform { - sound-dai = <&q6routing>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5616.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5616.yaml index 248320804e5f..29071044c66e 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5616.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5616.yaml @@ -30,6 +30,18 @@ properties: reg: maxItems: 1 + clocks: + items: + - description: Master clock to the CODEC + + clock-names: + items: + - const: mclk + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 07ec6247d9de..3bc93c59535e 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -112,6 +112,12 @@ properties: description: List of necessary clock names. # details are defined below + post-init-providers: + description: At least if rsnd is using DPCM connection on Audio-Graph-Card2, + fw_devlink might doesn't have enough information to break the cycle. rsnd + driver will not be probed in such case. Same problem might occur with + Multi-CPU/Codec or Codec2Codec. + # ports is below port: $ref: audio-graph-port.yaml#/definitions/port-base diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml index 8b9695f5decc..f4610eaed1e1 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml @@ -87,6 +87,10 @@ properties: '#sound-dai-cells': const: 0 + port: + $ref: audio-graph-port.yaml#/definitions/port-base + description: Connection to controller providing I2S signals + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml index b77284e3e26a..c3dea852cc8d 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml @@ -27,11 +27,6 @@ properties: - const: samsung,odroid-xu4-audio deprecated: true - assigned-clock-parents: true - assigned-clock-rates: true - assigned-clocks: true - clocks: true - cpu: type: object additionalProperties: false diff --git a/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml b/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml new file mode 100644 index 000000000000..21ea9ff5a2bb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,pcm512x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PCM512x and TAS575x audio CODECs/amplifiers + +maintainers: + - Animesh Agarwal + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - ti,pcm5121 + - ti,pcm5122 + - ti,pcm5141 + - ti,pcm5142 + - ti,pcm5242 + - ti,tas5754 + - ti,tas5756 + + reg: + maxItems: 1 + + AVDD-supply: true + + DVDD-supply: true + + CPVDD-supply: true + + clocks: + maxItems: 1 + description: A clock specifier for the clock connected as SCLK. If this is + absent the device will be configured to clock from BCLK. If pll-in and + pll-out are specified in addition to a clock, the device is configured to + accept clock input on a specified gpio pin. + + '#sound-dai-cells': + const: 0 + + pll-in: + description: GPIO pin used to connect the pll using <1> through <6>. The + device will be configured for clock input on the given pll-in pin. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 6 + + pll-out: + description: GPIO pin used to connect the pll using <1> through <6>. The + device will be configured for PLL output on the given pll-out pin. An + external connection from the pll-out pin to the SCLK pin is assumed. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 6 + +required: + - compatible + - reg + - AVDD-supply + - DVDD-supply + - CPVDD-supply + +if: + properties: + compatible: + contains: + enum: + - ti,tas5754 + - ti,tas5756 + +then: + properties: + pll-in: + maximum: 3 + + pll-out: + maximum: 3 + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@4c { + compatible = "ti,pcm5142"; + reg = <0x4c>; + AVDD-supply = <®_3v3_analog>; + DVDD-supply = <®_1v8>; + CPVDD-supply = <®_3v3>; + #sound-dai-cells = <0>; + clocks = <&sck>; + pll-in = <3>; + pll-out = <6>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml new file mode 100644 index 000000000000..85e937e34962 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tlv320dac3100.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tlv320dac3100.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments - tlv320aic31xx Codec module + +maintainers: + - Shenghao Ding + +description: | + CODEC output pins: + * HPL + * HPR + * SPL, devices with stereo speaker amp + * SPR, devices with stereo speaker amp + * SPK, devices with mono speaker amp + * MICBIAS + + CODEC input pins: + * MIC1LP, devices with ADC + * MIC1RP, devices with ADC + * MIC1LM, devices with ADC + * AIN1, devices without ADC + * AIN2, devices without ADC + + The pins can be used in referring sound node's audio-routing property. + +properties: + compatible: + enum: + - ti,tlv320aic310x # - Generic TLV320AIC31xx with mono speaker amp + - ti,tlv320aic311x # - Generic TLV320AIC31xx with stereo speaker amp + - ti,tlv320aic3100 # - TLV320AIC3100 (mono speaker amp, no MiniDSP) + - ti,tlv320aic3110 # - TLV320AIC3110 (stereo speaker amp, no MiniDSP) + - ti,tlv320aic3120 # - TLV320AIC3120 (mono speaker amp, MiniDSP) + - ti,tlv320aic3111 # - TLV320AIC3111 (stereo speaker amp, MiniDSP) + - ti,tlv320dac3100 # - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP) + - ti,tlv320dac3101 # - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP) + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + HPVDD-supply: true + + SPRVDD-supply: true + + SPLVDD-supply: true + + AVDD-supply: true + + IOVDD-supply: true + + DVDD-supply: true + + reset-gpios: + description: GPIO specification for the active low RESET input. + + ai31xx-micbias-vg: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1 + enum: [1, 2, 3] + description: | + MicBias Voltage setting + 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V + 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V + 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD + + ai31xx-ocmv: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3] + description: | + output common-mode voltage setting + 0 - 1.35V, + 1 - 1.5V, + 2 - 1.65V, + 3 - 1.8V + + gpio-reset: + description: gpio pin number used for codec reset + deprecated: true + + +required: + - compatible + - reg + - HPVDD-supply + - SPRVDD-supply + - SPLVDD-supply + - AVDD-supply + - IOVDD-supply + - DVDD-supply + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sound@18 { + compatible = "ti,tlv320aic311x"; + reg = <0x18>; + + ai31xx-micbias-vg = ; + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + + HPVDD-supply = <®ulator>; + SPRVDD-supply = <®ulator>; + SPLVDD-supply = <®ulator>; + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; + }; + }; + diff --git a/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml b/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml new file mode 100644 index 000000000000..a42bf9bde694 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tpa6130a2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments - tpa6130a2 Codec module + +maintainers: + - Sebastian Reichel + +description: + Stereo, analog input headphone amplifier + +properties: + compatible: + enum: + - ti,tpa6130a2 + - ti,tpa6140a2 + + reg: + maxItems: 1 + + Vdd-supply: + description: power supply regulator + + power-gpio: + description: gpio pin to power the device + +required: + - compatible + - reg + - Vdd-supply + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + amplifier@60 { + compatible = "ti,tpa6130a2"; + reg = <0x60>; + Vdd-supply = <&vmmc2>; + power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; + }; + }; + diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt deleted file mode 100644 index bbad98d5b986..000000000000 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ /dev/null @@ -1,77 +0,0 @@ -Texas Instruments - tlv320aic31xx Codec module - -The tlv320aic31xx serial control bus communicates through I2C protocols - -Required properties: - -- compatible - "string" - One of: - "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp - "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp - "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP) - "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP) - "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP) - "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP) - "ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP) - "ti,tlv320dac3101" - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP) - -- reg - - I2C slave address -- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply, - DVDD-supply : power supplies for the device as covered in - Documentation/devicetree/bindings/regulator/regulator.txt - - -Optional properties: - -- reset-gpios - GPIO specification for the active low RESET input. -- ai31xx-micbias-vg - MicBias Voltage setting - 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V - 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V - 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD - If this node is not mentioned or if the value is unknown, then - micbias is set to 2.0V. -- ai31xx-ocmv - output common-mode voltage setting - 0 - 1.35V, - 1 - 1.5V, - 2 - 1.65V, - 3 - 1.8V - -Deprecated properties: - -- gpio-reset - gpio pin number used for codec reset - -CODEC output pins: - * HPL - * HPR - * SPL, devices with stereo speaker amp - * SPR, devices with stereo speaker amp - * SPK, devices with mono speaker amp - * MICBIAS - -CODEC input pins: - * MIC1LP, devices with ADC - * MIC1RP, devices with ADC - * MIC1LM, devices with ADC - * AIN1, devices without ADC - * AIN2, devices without ADC - -The pins can be used in referring sound node's audio-routing property. - -Example: -#include -#include - -tlv320aic31xx: tlv320aic31xx@18 { - compatible = "ti,tlv320aic311x"; - reg = <0x18>; - - ai31xx-micbias-vg = ; - - reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; - - HPVDD-supply = <®ulator>; - SPRVDD-supply = <®ulator>; - SPLVDD-supply = <®ulator>; - AVDD-supply = <®ulator>; - IOVDD-supply = <®ulator>; - DVDD-supply = <®ulator>; -}; diff --git a/Documentation/devicetree/bindings/sound/tpa6130a2.txt b/Documentation/devicetree/bindings/sound/tpa6130a2.txt deleted file mode 100644 index 6dfa740e4b2d..000000000000 --- a/Documentation/devicetree/bindings/sound/tpa6130a2.txt +++ /dev/null @@ -1,27 +0,0 @@ -Texas Instruments - tpa6130a2 Codec module - -The tpa6130a2 serial control bus communicates through I2C protocols - -Required properties: - -- compatible - "string" - One of: - "ti,tpa6130a2" - TPA6130A2 - "ti,tpa6140a2" - TPA6140A2 - - -- reg - - I2C slave address - -- Vdd-supply - - power supply regulator - -Optional properties: - -- power-gpio - gpio pin to power the device - -Example: - -tpa6130a2: tpa6130a2@60 { - compatible = "ti,tpa6130a2"; - reg = <0x60>; - Vdd-supply = <&vmmc2>; - power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 7b9b0a48cf08..f8a645bcf2b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6500,6 +6500,7 @@ F: Documentation/devicetree/bindings/regulator/da92*.txt F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml F: Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml F: Documentation/devicetree/bindings/sound/da[79]*.txt +F: Documentation/devicetree/bindings/sound/dlg,da7213.yaml F: Documentation/devicetree/bindings/thermal/dlg,da9062-thermal.yaml F: Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml F: Documentation/hwmon/da90??.rst @@ -22578,12 +22579,11 @@ F: Documentation/devicetree/bindings/sound/tas2552.txt F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml +F: Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml -F: Documentation/devicetree/bindings/sound/tlv320aic31xx.txt -F: Documentation/devicetree/bindings/sound/tpa6130a2.txt F: include/sound/tas2*.h F: include/sound/tlv320*.h F: include/sound/tpa6130a2-plat.h diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 68838e843b54..1db4d9d3a3ba 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -222,6 +222,13 @@ static inline bool sdw_intel_sync_check_cmdsync_unlocked(struct sdw_intel *sdw) return false; } +static inline int sdw_intel_get_link_count(struct sdw_intel *sdw) +{ + if (SDW_INTEL_CHECK_OPS(sdw, get_link_count)) + return SDW_INTEL_OPS(sdw, get_link_count)(sdw); + return 4; /* default on older generations */ +} + /* common bus management */ int intel_start_bus(struct sdw_intel *sdw); int intel_start_bus_after_reset(struct sdw_intel *sdw); diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 781fe0aefa68..fff312c6968d 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -706,10 +706,30 @@ static void intel_program_sdi(struct sdw_intel *sdw, int dev_num) __func__, sdw->instance, dev_num); } +static int intel_get_link_count(struct sdw_intel *sdw) +{ + int ret; + + ret = hdac_bus_eml_get_count(sdw->link_res->hbus, true, AZX_REG_ML_LEPTR_ID_SDW); + if (!ret) { + dev_err(sdw->cdns.dev, "%s: could not retrieve link count\n", __func__); + return -ENODEV; + } + + if (ret > SDW_INTEL_MAX_LINKS) { + dev_err(sdw->cdns.dev, "%s: link count %d exceed max %d\n", __func__, ret, SDW_INTEL_MAX_LINKS); + return -EINVAL; + } + + return ret; +} + const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = { .debugfs_init = intel_ace2x_debugfs_init, .debugfs_exit = intel_ace2x_debugfs_exit, + .get_link_count = intel_get_link_count, + .register_dai = intel_register_dai, .check_clock_stop = intel_check_clock_stop, diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 8807e01cbf7c..d110f2b587d5 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -317,6 +317,20 @@ static int intel_link_probe(struct auxiliary_device *auxdev, bus->link_id = auxdev->id; bus->clk_stop_timeout = 1; + /* + * paranoia check: make sure ACPI-reported number of links is aligned with + * hardware capabilities. + */ + ret = sdw_intel_get_link_count(sdw); + if (ret < 0) { + dev_err(dev, "%s: sdw_intel_get_link_count failed: %d\n", __func__, ret); + return ret; + } + if (ret <= sdw->instance) { + dev_err(dev, "%s: invalid link id %d, link count %d\n", __func__, auxdev->id, ret); + return -EINVAL; + } + sdw_cdns_probe(cdns); /* Set ops */ diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index d537587b4499..37ae69365fe2 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -388,6 +388,7 @@ struct sdw_intel; /* struct intel_sdw_hw_ops - SoundWire ops for Intel platforms. * @debugfs_init: initialize all debugfs capabilities * @debugfs_exit: close and cleanup debugfs capabilities + * @get_link_count: fetch link count from hardware registers * @register_dai: read all PDI information and register DAIs * @check_clock_stop: throw error message if clock is not stopped. * @start_bus: normal start @@ -412,6 +413,8 @@ struct sdw_intel_hw_ops { void (*debugfs_init)(struct sdw_intel *sdw); void (*debugfs_exit)(struct sdw_intel *sdw); + int (*get_link_count)(struct sdw_intel *sdw); + int (*register_dai)(struct sdw_intel *sdw); void (*check_clock_stop)(struct sdw_intel *sdw); @@ -447,4 +450,9 @@ extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops; #define SDW_INTEL_DEV_NUM_IDA_MIN 6 +/* + * Max number of links supported in hardware + */ +#define SDW_INTEL_MAX_LINKS 5 + #endif diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index a51acefa785f..94e8185c4795 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -282,9 +282,9 @@ static inline bool cs35l56_is_otp_register(unsigned int reg) return (reg >> 16) == 3; } -extern struct regmap_config cs35l56_regmap_i2c; -extern struct regmap_config cs35l56_regmap_spi; -extern struct regmap_config cs35l56_regmap_sdw; +extern const struct regmap_config cs35l56_regmap_i2c; +extern const struct regmap_config cs35l56_regmap_spi; +extern const struct regmap_config cs35l56_regmap_sdw; extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls; diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 4843b57798f6..daed7123df9d 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -33,6 +33,7 @@ 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_arl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_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[]; @@ -44,6 +45,7 @@ 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[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 38ccec4e3fcd..60d3b86a4660 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -62,7 +62,6 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @platform: string used for HDAudio codec support * @codec_mask: used for HDAudio support * @dmic_num: number of SoC- or chipset-attached PDM digital microphones - * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver * @link_mask: SoundWire links enabled on the board * @links: array of SoundWire link _ADR descriptors, null terminated * @i2s_link_mask: I2S/TDM links enabled on the board @@ -70,15 +69,16 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode * @subsystem_vendor: optional PCI SSID vendor value * @subsystem_device: optional PCI SSID device value + * @subsystem_rev: optional PCI SSID revision value * @subsystem_id_set: true if a value has been written to * subsystem_vendor and subsystem_device. + * @bt_link_mask: BT offload link enabled on the board */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; u32 dmic_num; - bool common_hdmi_codec_drv; u32 link_mask; const struct snd_soc_acpi_link_adr *links; u32 i2s_link_mask; @@ -86,7 +86,9 @@ struct snd_soc_acpi_mach_params { struct snd_soc_dai_driver *dai_drivers; unsigned short subsystem_vendor; unsigned short subsystem_device; + unsigned short subsystem_rev; bool subsystem_id_set; + u32 bt_link_mask; }; /** diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index bbb72ad4c951..0d1b215f24f4 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -219,7 +219,6 @@ void snd_soc_dai_resume(struct snd_soc_dai *dai); int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num); bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream); -void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link); void snd_soc_dai_action(struct snd_soc_dai *dai, int stream, int action); static inline void snd_soc_dai_activate(struct snd_soc_dai *dai, @@ -240,8 +239,6 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd); int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream); int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd, int rollback); -int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, - int cmd); void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream, snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay); @@ -345,8 +342,7 @@ struct snd_soc_dai_ops { */ int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *); - int (*bespoke_trigger)(struct snd_pcm_substream *, int, - struct snd_soc_dai *); + /* * For hardware based FIFO caused delay reporting. * Optional. diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index ebd24753dd00..c6fb350b4b06 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -58,7 +58,6 @@ enum snd_soc_dpcm_state { enum snd_soc_dpcm_trigger { SND_SOC_DPCM_TRIGGER_PRE = 0, SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_BESPOKE, }; /* @@ -114,24 +113,6 @@ struct snd_soc_dpcm_runtime { #define for_each_dpcm_be_rollback(fe, stream, _dpcm) \ list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be) -/* can this BE stop and free */ -int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream); - -/* can this BE perform a hw_params() */ -int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream); - -/* can this BE perform prepare */ -int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream); - -/* is the current PCM operation for this FE ? */ -int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream); - -/* is the current PCM operation for this BE ? */ -int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream); /* get the substream for this BE */ struct snd_pcm_substream * diff --git a/include/sound/soc.h b/include/sound/soc.h index a8e66bbf932b..e6e359c1a2ac 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -815,6 +815,7 @@ struct snd_soc_dai_link { /* This DAI link can route to other DAI links at runtime (Frontend)*/ unsigned int dynamic:1; + /* REMOVE ME */ /* DPCM capture and Playback support */ unsigned int dpcm_capture:1; unsigned int dpcm_playback:1; @@ -1206,11 +1207,11 @@ struct snd_soc_pcm_runtime { /* bit field */ unsigned int pop_wait:1; unsigned int fe_compr:1; /* for Dynamic PCM */ + unsigned int initialized:1; - bool initialized; - + /* CPU/Codec/Platform */ int num_components; - struct snd_soc_component *components[]; /* CPU/Codec/Platform */ + struct snd_soc_component *components[] __counted_by(num_components); }; /* see soc_new_pcm_runtime() */ diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h new file mode 100644 index 000000000000..f68c1f193b3b --- /dev/null +++ b/include/sound/soc_sdw_utils.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * This file incorporates work covered by the following copyright notice: + * Copyright (c) 2020 Intel Corporation + * Copyright(c) 2024 Advanced Micro Devices, Inc. + * + */ + +#ifndef SOC_SDW_UTILS_H +#define SOC_SDW_UTILS_H + +#include +#include + +#define SOC_SDW_MAX_DAI_NUM 8 +#define SOC_SDW_MAX_NO_PROPS 2 +#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) + +/* If a CODEC has an optional speaker output, this quirk will enable it */ +#define SOC_SDW_CODEC_SPKR BIT(15) +/* + * If the CODEC has additional devices attached directly to it. + * + * For the cs42l43: + * - 0 - No speaker output + * - SOC_SDW_CODEC_SPKR - CODEC internal speaker + * - SOC_SDW_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker + * - SOC_SDW_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported + */ +#define SOC_SDW_SIDECAR_AMPS BIT(16) + +#define SOC_SDW_UNUSED_DAI_ID -1 +#define SOC_SDW_JACK_OUT_DAI_ID 0 +#define SOC_SDW_JACK_IN_DAI_ID 1 +#define SOC_SDW_AMP_OUT_DAI_ID 2 +#define SOC_SDW_AMP_IN_DAI_ID 3 +#define SOC_SDW_DMIC_DAI_ID 4 + +#define SOC_SDW_DAI_TYPE_JACK 0 +#define SOC_SDW_DAI_TYPE_AMP 1 +#define SOC_SDW_DAI_TYPE_MIC 2 + +struct asoc_sdw_codec_info; + +struct asoc_sdw_dai_info { + const bool direction[2]; /* playback & capture support */ + const char *dai_name; + const int dai_type; + const int dailink[2]; /* dailink id for each direction */ + const struct snd_kcontrol_new *controls; + const int num_controls; + const struct snd_soc_dapm_widget *widgets; + const int num_widgets; + int (*init)(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + int (*rtd_init)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); + bool rtd_init_done; /* Indicate that the rtd_init callback is done */ + unsigned long quirk; +}; + +struct asoc_sdw_codec_info { + const int part_id; + const int version_id; + const char *codec_name; + int amp_num; + const u8 acpi_id[ACPI_ID_LEN]; + const bool ignore_internal_dmic; + const struct snd_soc_ops *ops; + struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM]; + const int dai_num; + + int (*codec_card_late_probe)(struct snd_soc_card *card); + + int (*count_sidecar)(struct snd_soc_card *card, + int *num_dais, int *num_devs); + int (*add_sidecar)(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf); +}; + +struct asoc_sdw_mc_private { + struct snd_soc_card card; + struct snd_soc_jack sdw_headset; + struct device *headset_codec_dev; /* only one headset per card */ + struct device *amp_dev1, *amp_dev2; + bool append_dai_type; + bool ignore_internal_dmic; + void *private; + unsigned long mc_quirk; + int codec_info_list_count; +}; + +struct asoc_sdw_endpoint { + struct list_head list; + + u32 link_mask; + const char *codec_name; + const char *name_prefix; + bool include_sidecar; + + struct asoc_sdw_codec_info *codec_info; + const struct asoc_sdw_dai_info *dai_info; +}; + +struct asoc_sdw_dailink { + bool initialised; + + u8 group_id; + u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; + int num_devs[SNDRV_PCM_STREAM_LAST + 1]; + struct list_head endpoints; +}; + +extern struct asoc_sdw_codec_info codec_info_list[]; +int asoc_sdw_get_codec_info_list_count(void); + +int asoc_sdw_startup(struct snd_pcm_substream *substream); +int asoc_sdw_prepare(struct snd_pcm_substream *substream); +int asoc_sdw_prepare(struct snd_pcm_substream *substream); +int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd); +int asoc_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int asoc_sdw_hw_free(struct snd_pcm_substream *substream); +void asoc_sdw_shutdown(struct snd_pcm_substream *substream); + +const char *asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, + int *dai_index); + +struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, + const char *dai_name); + +void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card); + +int asoc_sdw_card_late_probe(struct snd_soc_card *card); + +void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + struct snd_soc_dai_link_component *cpus, int cpus_num, + struct snd_soc_dai_link_component *platform_component, + int num_platforms, struct snd_soc_dai_link_component *codecs, + int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops); + +int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + const char *cpu_dai_name, const char *platform_comp_name, + int num_platforms, const char *codec_name, + const char *codec_dai_name, + int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops); + +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends); + +struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new); + +int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dais, + struct asoc_sdw_endpoint *soc_ends, + int *num_devs); + +int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd); + +/* DMIC support */ +int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); + +/* RT711 support */ +int asoc_sdw_rt711_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* RT711-SDCA support */ +int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* RT1308 I2S support */ +extern const struct snd_soc_ops soc_sdw_rt1308_i2s_ops; + +/* generic amp support */ +int asoc_sdw_rt_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* CS42L43 support */ +int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* CS AMP support */ +int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs); +int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf); +int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +int asoc_sdw_cs_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* MAXIM codec support */ +int asoc_sdw_maxim_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* dai_link init callbacks */ +int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); + +#endif diff --git a/include/sound/tas2563-tlv.h b/include/sound/tas2563-tlv.h new file mode 100644 index 000000000000..bb269b21f460 --- /dev/null +++ b/include/sound/tas2563-tlv.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// +// ALSA SoC Texas Instruments TAS2563 Audio Smart Amplifier +// +// Copyright (C) 2022 - 2024 Texas Instruments Incorporated +// https://www.ti.com +// +// The TAS2563 driver implements a flexible and configurable +// algo coefficient setting for one, two, or even multiple +// TAS2563 chips. +// +// Author: Shenghao Ding +// + +#ifndef __TAS2563_TLV_H__ +#define __TAS2563_TLV_H__ + +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1); + +/* pow(10, db/20) * pow(2,30) */ +static const __maybe_unused unsigned char tas2563_dvc_table[][4] = { + { 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */ + { 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */ + { 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */ + { 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */ + { 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */ + { 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */ + { 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */ + { 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */ + { 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */ + { 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */ + { 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */ + { 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */ + { 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */ + { 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */ + { 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */ + { 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */ + { 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */ + { 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */ + { 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */ + { 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */ + { 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */ + { 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */ + { 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */ + { 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */ + { 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */ + { 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */ + { 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */ + { 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */ + { 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */ + { 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */ + { 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */ + { 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */ + { 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */ + { 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */ + { 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */ + { 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */ + { 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */ + { 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */ + { 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */ + { 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */ + { 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */ + { 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */ + { 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */ + { 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */ + { 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */ + { 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */ + { 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */ + { 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */ + { 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */ + { 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */ + { 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */ + { 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */ + { 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */ + { 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */ + { 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */ + { 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */ + { 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */ + { 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */ + { 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */ + { 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */ + { 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */ + { 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */ + { 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */ + { 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */ + { 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */ + { 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */ + { 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */ + { 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */ + { 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */ + { 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */ + { 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */ + { 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */ + { 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */ + { 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */ + { 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */ + { 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */ + { 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */ + { 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */ + { 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */ + { 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */ + { 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */ + { 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */ + { 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */ + { 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */ + { 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */ + { 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */ + { 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */ + { 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */ + { 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */ + { 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */ + { 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */ + { 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */ + { 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */ + { 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */ + { 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */ + { 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */ + { 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */ + { 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */ + { 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */ + { 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */ + { 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */ + { 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */ + { 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */ + { 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */ + { 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */ + { 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */ + { 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */ + { 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */ + { 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */ + { 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */ + { 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */ + { 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */ + { 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */ + { 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */ + { 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */ + { 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */ + { 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */ + { 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */ + { 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */ + { 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */ + { 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */ + { 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */ + { 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */ + { 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */ + { 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */ + { 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */ + { 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */ + { 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */ + { 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */ + { 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */ + { 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */ + { 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */ + { 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */ + { 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */ + { 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */ + { 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */ + { 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */ + { 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */ + { 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */ + { 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */ + { 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */ + { 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */ + { 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */ + { 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */ + { 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */ + { 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */ + { 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */ + { 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */ + { 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */ + { 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */ + { 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */ + { 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */ + { 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */ + { 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */ + { 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */ + { 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */ + { 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */ + { 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */ + { 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */ + { 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */ + { 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */ + { 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */ + { 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */ + { 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */ + { 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */ + { 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */ + { 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */ + { 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */ + { 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */ + { 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */ + { 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */ + { 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */ + { 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */ + { 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */ + { 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */ + { 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */ + { 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */ + { 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */ + { 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */ + { 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */ + { 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */ + { 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */ + { 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */ + { 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */ + { 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */ + { 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */ + { 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */ + { 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */ + { 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */ + { 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */ + { 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */ + { 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */ + { 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */ + { 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */ + { 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */ + { 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */ + { 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */ + { 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */ + { 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */ + { 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */ + { 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */ + { 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */ + { 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */ + { 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */ + { 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */ + { 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */ + { 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */ + { 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */ + { 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */ + { 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */ + { 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */ + { 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */ + { 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */ + { 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */ + { 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */ + { 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */ + { 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */ + { 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */ + { 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */ + { 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */ + { 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */ + { 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */ + { 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */ + { 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */ + { 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */ + { 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */ + { 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */ + { 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */ + { 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */ + { 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */ + { 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */ + { 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */ + { 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */ + { 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */ + { 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */ + { 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */ + { 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */ + { 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */ + { 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */ + { 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */ + { 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */ + { 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */ + { 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */ + { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */ + { 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */ + { 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */ + { 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */ + { 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */ + { 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */ + { 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */ + { 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */ + { 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */ + { 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */ + { 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */ + { 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */ + { 0X7F, 0XFF, 0XFF, 0XFF }, /* 6.0db */ +}; +#endif diff --git a/include/sound/tas2781-tlv.h b/include/sound/tas2781-tlv.h index 00fd4d449ff3..d87263e43fdb 100644 --- a/include/sound/tas2781-tlv.h +++ b/include/sound/tas2781-tlv.h @@ -17,265 +17,5 @@ static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0); static const __maybe_unused DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0); -static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1); -/* pow(10, db/20) * pow(2,30) */ -static const __maybe_unused unsigned char tas2563_dvc_table[][4] = { - { 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */ - { 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */ - { 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */ - { 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */ - { 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */ - { 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */ - { 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */ - { 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */ - { 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */ - { 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */ - { 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */ - { 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */ - { 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */ - { 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */ - { 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */ - { 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */ - { 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */ - { 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */ - { 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */ - { 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */ - { 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */ - { 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */ - { 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */ - { 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */ - { 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */ - { 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */ - { 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */ - { 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */ - { 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */ - { 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */ - { 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */ - { 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */ - { 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */ - { 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */ - { 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */ - { 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */ - { 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */ - { 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */ - { 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */ - { 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */ - { 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */ - { 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */ - { 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */ - { 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */ - { 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */ - { 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */ - { 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */ - { 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */ - { 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */ - { 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */ - { 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */ - { 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */ - { 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */ - { 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */ - { 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */ - { 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */ - { 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */ - { 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */ - { 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */ - { 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */ - { 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */ - { 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */ - { 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */ - { 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */ - { 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */ - { 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */ - { 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */ - { 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */ - { 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */ - { 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */ - { 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */ - { 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */ - { 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */ - { 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */ - { 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */ - { 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */ - { 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */ - { 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */ - { 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */ - { 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */ - { 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */ - { 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */ - { 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */ - { 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */ - { 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */ - { 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */ - { 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */ - { 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */ - { 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */ - { 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */ - { 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */ - { 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */ - { 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */ - { 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */ - { 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */ - { 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */ - { 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */ - { 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */ - { 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */ - { 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */ - { 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */ - { 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */ - { 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */ - { 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */ - { 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */ - { 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */ - { 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */ - { 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */ - { 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */ - { 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */ - { 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */ - { 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */ - { 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */ - { 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */ - { 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */ - { 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */ - { 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */ - { 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */ - { 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */ - { 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */ - { 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */ - { 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */ - { 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */ - { 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */ - { 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */ - { 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */ - { 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */ - { 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */ - { 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */ - { 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */ - { 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */ - { 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */ - { 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */ - { 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */ - { 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */ - { 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */ - { 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */ - { 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */ - { 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */ - { 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */ - { 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */ - { 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */ - { 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */ - { 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */ - { 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */ - { 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */ - { 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */ - { 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */ - { 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */ - { 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */ - { 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */ - { 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */ - { 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */ - { 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */ - { 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */ - { 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */ - { 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */ - { 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */ - { 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */ - { 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */ - { 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */ - { 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */ - { 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */ - { 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */ - { 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */ - { 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */ - { 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */ - { 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */ - { 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */ - { 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */ - { 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */ - { 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */ - { 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */ - { 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */ - { 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */ - { 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */ - { 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */ - { 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */ - { 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */ - { 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */ - { 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */ - { 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */ - { 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */ - { 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */ - { 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */ - { 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */ - { 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */ - { 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */ - { 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */ - { 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */ - { 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */ - { 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */ - { 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */ - { 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */ - { 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */ - { 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */ - { 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */ - { 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */ - { 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */ - { 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */ - { 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */ - { 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */ - { 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */ - { 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */ - { 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */ - { 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */ - { 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */ - { 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */ - { 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */ - { 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */ - { 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */ - { 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */ - { 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */ - { 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */ - { 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */ - { 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */ - { 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */ - { 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */ - { 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */ - { 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */ - { 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */ - { 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */ - { 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */ - { 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */ - { 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */ - { 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */ - { 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */ - { 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */ - { 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */ - { 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */ - { 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */ - { 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */ - { 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */ - { 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */ - { 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */ - { 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */ - { 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */ - { 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */ - { 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */ - { 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */ - { 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */ - { 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */ - { 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */ - { 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */ - { 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */ - { 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */ - { 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */ - { 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */ - { 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */ - { 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */ - { 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */ - { 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */ - { 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */ - { 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */ - { 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */ - { 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */ -}; #endif diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 18161d02a96f..8cd6da0480b7 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -49,12 +49,59 @@ /*I2C Checksum */ #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) +/* XM_340 */ +#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c) +/* XM_341 */ +#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38) + /* Volume control */ #define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C) #define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A) #define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) #define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1) +#define TAS2563_IDLE TASDEVICE_REG(0x00, 0x00, 0x3e) +#define TAS2563_PRM_R0_REG TASDEVICE_REG(0x00, 0x0f, 0x34) + +#define TAS2563_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x02, 0x70) +#define TAS2563_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x02, 0x48) + +#define TAS2563_PRM_ENFF_REG TASDEVICE_REG(0x00, 0x0d, 0x54) +#define TAS2563_PRM_DISTCK_REG TASDEVICE_REG(0x00, 0x0d, 0x58) +#define TAS2563_PRM_TE_SCTHR_REG TASDEVICE_REG(0x00, 0x0f, 0x60) +#define TAS2563_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x0d, 0x74) +#define TAS2563_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x0d, 0x7c) +/* prm_Int_B0 */ +#define TAS2563_TE_TA1_REG TASDEVICE_REG(0x00, 0x10, 0x0c) +/* prm_Int_A1 */ +#define TAS2563_TE_TA1_AT_REG TASDEVICE_REG(0x00, 0x10, 0x10) +/* prm_TE_Beta */ +#define TAS2563_TE_TA2_REG TASDEVICE_REG(0x00, 0x0f, 0x64) +/* prm_TE_Beta1 */ +#define TAS2563_TE_AT_REG TASDEVICE_REG(0x00, 0x0f, 0x68) +/* prm_TE_1_Beta1 */ +#define TAS2563_TE_DT_REG TASDEVICE_REG(0x00, 0x0f, 0x70) + +#define TAS2781_PRM_INT_MASK_REG TASDEVICE_REG(0x00, 0x00, 0x3b) +#define TAS2781_PRM_CLK_CFG_REG TASDEVICE_REG(0x00, 0x00, 0x5c) +#define TAS2781_PRM_RSVD_REG TASDEVICE_REG(0x00, 0x01, 0x19) +#define TAS2781_PRM_TEST_57_REG TASDEVICE_REG(0x00, 0xfd, 0x39) +#define TAS2781_PRM_TEST_62_REG TASDEVICE_REG(0x00, 0xfd, 0x3e) +#define TAS2781_PRM_PVDD_UVLO_REG TASDEVICE_REG(0x00, 0x00, 0x71) +#define TAS2781_PRM_CHNL_0_REG TASDEVICE_REG(0x00, 0x00, 0x03) +#define TAS2781_PRM_NG_CFG0_REG TASDEVICE_REG(0x00, 0x00, 0x35) +#define TAS2781_PRM_IDLE_CH_DET_REG TASDEVICE_REG(0x00, 0x00, 0x66) +#define TAS2781_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x14, 0x38) +#define TAS2781_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x14, 0x40) +#define TAS2781_PRM_SINEGAIN2_REG TASDEVICE_REG(0x00, 0x14, 0x44) + +#define TAS2781_TEST_UNLOCK_REG TASDEVICE_REG(0x00, 0xFD, 0x0D) +#define TAS2781_TEST_PAGE_UNLOCK 0x0D + +#define TAS2781_RUNTIME_LATCH_RE_REG TASDEVICE_REG(0x00, 0x00, 0x49) +#define TAS2781_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x62, 0x48) +#define TAS2781_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x63, 0x44) + #define TASDEVICE_CMD_SING_W 0x1 #define TASDEVICE_CMD_BURST 0x2 #define TASDEVICE_CMD_DELAY 0x3 @@ -70,7 +117,15 @@ enum device_catlog_id { OTHERS }; +struct bulk_reg_val { + int reg; + unsigned char val[4]; + unsigned char val_len; + bool is_locked; +}; + struct tasdevice { + struct bulk_reg_val *cali_data_backup; struct tasdevice_fw *cali_data_fmw; unsigned int dev_addr; unsigned int err_code; @@ -81,19 +136,23 @@ struct tasdevice { bool is_loaderr; }; -struct tasdevice_irqinfo { - int irq_gpio; - int irq; +struct cali_reg { + unsigned int r0_reg; + unsigned int r0_low_reg; + unsigned int invr0_reg; + unsigned int pow_reg; + unsigned int tlimit_reg; }; struct calidata { unsigned char *data; unsigned long total_sz; + struct cali_reg cali_reg_array; + unsigned int cali_dat_sz_per_dev; }; struct tasdevice_priv { struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS]; - struct tasdevice_irqinfo irq_info; struct tasdevice_rca rcabin; struct calidata cali_data; struct tasdevice_fw *fmw; @@ -115,6 +174,7 @@ struct tasdevice_priv { unsigned int chip_id; unsigned int sysclk; + int irq; int cur_prog; int cur_conf; int fw_state; @@ -124,6 +184,7 @@ struct tasdevice_priv { bool force_fwload_status; bool playback_started; bool isacpi; + bool is_user_space_calidata; unsigned int global_addr; int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv, @@ -150,6 +211,8 @@ int tasdevice_init(struct tasdevice_priv *tas_priv); void tasdevice_remove(struct tasdevice_priv *tas_priv); int tasdevice_save_calibration(struct tasdevice_priv *tas_priv); void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv); +int tasdev_chn_switch(struct tasdevice_priv *tas_priv, + unsigned short chn); int tasdevice_dev_read(struct tasdevice_priv *tas_priv, unsigned short chn, unsigned int reg, unsigned int *value); int tasdevice_dev_write(struct tasdevice_priv *tas_priv, diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 913880b09065..f018bd779862 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -56,10 +56,59 @@ static const struct config_entry config_table[] = { }, #endif /* - * Apollolake (Broxton-P) + * Skylake, Kabylake, Apollolake * the legacy HDAudio driver is used except on Up Squared (SOF) and * Chromebooks (SST), as well as devices based on the ES8336 codec */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS) + { + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, + { + .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, + }, + { + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, + { + .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + }, + { + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { .flags = FLAG_SOF, @@ -81,66 +130,6 @@ static const struct config_entry config_table[] = { .codec_hid = &essx_83x6, }, #endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) - { - .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_APL, - .dmi_table = (const struct dmi_system_id []) { - { - .ident = "Google Chromebooks", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - } - }, - {} - } - }, -#endif -/* - * Skylake and Kabylake use legacy HDAudio driver except for Google - * Chromebooks (SST) - */ - -/* Sunrise Point-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) - { - .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, - .dmi_table = (const struct dmi_system_id []) { - { - .ident = "Google Chromebooks", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - } - }, - {} - } - }, - { - .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, - }, -#endif -/* Kabylake-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) - { - .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, - .dmi_table = (const struct dmi_system_id []) { - { - .ident = "Google Chromebooks", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - } - }, - {} - } - }, - { - .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, - }, -#endif /* * Geminilake uses legacy HDAudio driver except for Google diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index f3b2a610df23..04d6b6beabca 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -17,7 +17,6 @@ #include #define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ -#define SDW_MAX_LINKS 4 static int ctrl_link_mask; module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); @@ -87,9 +86,9 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) } /* Check count is within bounds */ - if (count > SDW_MAX_LINKS) { + if (count > SDW_INTEL_MAX_LINKS) { dev_err(&adev->dev, "Link count %d exceeds max %d\n", - count, SDW_MAX_LINKS); + count, SDW_INTEL_MAX_LINKS); return -EINVAL; } diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 89d8235537cd..f58f434e7110 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -818,7 +818,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) } else return -ENODEV; - tas_hda->priv->irq_info.irq = clt->irq; + tas_hda->priv->irq = clt->irq; ret = tas2781_read_acpi(tas_hda->priv, device_name); if (ret) return dev_err_probe(tas_hda->dev, ret, diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index a52afb423b46..e87bd15a8b43 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -126,6 +126,8 @@ source "sound/soc/xtensa/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" +source "sound/soc/sdw_utils/Kconfig" + # generic frame-work source "sound/soc/generic/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index fd61847dd1eb..775bb38c2ed4 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_SND_SOC) += uniphier/ obj-$(CONFIG_SND_SOC) += ux500/ obj-$(CONFIG_SND_SOC) += xilinx/ obj-$(CONFIG_SND_SOC) += xtensa/ +obj-$(CONFIG_SND_SOC) += sdw_utils/ diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index 7b2563075743..41f89384f8fd 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -264,8 +264,8 @@ static int axi_i2s_probe(struct platform_device *pdev) goto err_clk_disable; dev_info(&pdev->dev, "probed, capture %s, playback %s\n", - i2s->has_capture ? "enabled" : "disabled", - i2s->has_playback ? "enabled" : "disabled"); + str_enabled_disabled(i2s->has_capture), + str_enabled_disabled(i2s->has_playback)); return 0; @@ -293,7 +293,7 @@ static struct platform_driver axi_i2s_driver = { .of_match_table = axi_i2s_of_match, }, .probe = axi_i2s_probe, - .remove_new = axi_i2s_dev_remove, + .remove = axi_i2s_dev_remove, }; module_platform_driver(axi_i2s_driver); diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index 10545bd99704..5581134201a3 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -258,7 +258,7 @@ static struct platform_driver axi_spdif_driver = { .of_match_table = axi_spdif_of_match, }, .probe = axi_spdif_probe, - .remove_new = axi_spdif_dev_remove, + .remove = axi_spdif_dev_remove, }; module_platform_driver(axi_spdif_driver); diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 42c2322cd11b..365209ea53f3 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -321,5 +321,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = { + { + .id = "AMDI1010", + .drv_name = "acp70-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-acp_7_0.ri", + .sof_tplg_filename = "sof-acp_7_0.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines); + MODULE_DESCRIPTION("AMD ACP Machine Configuration Module"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index b857e2676fe8..897dde630022 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1426,7 +1426,7 @@ static const struct dev_pm_ops acp_pm_ops = { static struct platform_driver acp_dma_driver = { .probe = acp_audio_probe, - .remove_new = acp_audio_remove, + .remove = acp_audio_remove, .driver = { .name = DRV_NAME, .pm = &acp_pm_ops, diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 30590a23ad63..88391e4c17e3 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -13,6 +13,10 @@ config SND_SOC_AMD_ACP_COMMON This option enables common modules for Audio-Coprocessor i.e. ACP IP block on AMD platforms. +config SND_SOC_ACPI_AMD_MATCH + tristate + select SND_SOC_ACPI if ACPI + if SND_SOC_AMD_ACP_COMMON config SND_SOC_AMD_ACP_PDM @@ -115,6 +119,24 @@ config SND_SOC_AMD_SOF_MACH help This option enables SOF sound card support for ACP audio. +config SND_SOC_AMD_SOF_SDW_MACH + tristate "AMD SOF Soundwire Machine Driver Support" + depends on X86 && PCI && ACPI + depends on SOUNDWIRE + select SND_SOC_SDW_UTILS + select SND_SOC_DMIC + select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW + select SND_SOC_RT1316_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW + help + This option enables SOF sound card support for SoundWire enabled + AMD platforms along with ACP PDM controller. + Say Y if you want to enable SoundWire based machine driver support + on AMD platform. + If unsure select "N". + endif # SND_SOC_AMD_ACP_COMMON config SND_AMD_SOUNDWIRE_ACPI diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index b068bf1f920e..82cf5d180b3a 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -22,6 +22,8 @@ snd-acp70-y := acp70.o snd-acp-mach-y := acp-mach-common.o snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o snd-acp-sof-mach-y := acp-sof-mach.o +snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o +snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o @@ -38,3 +40,5 @@ obj-$(CONFIG_SND_AMD_SOUNDWIRE_ACPI) += snd-amd-sdw-acpi.o obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o +obj-$(CONFIG_SND_SOC_ACPI_AMD_MATCH) += snd-soc-acpi-amd-match.o +obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 97258b4cf89b..56ce9e4b6acc 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -60,6 +60,8 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) switch (chip->acp_rev) { case ACP63_DEV: + case ACP70_DEV: + case ACP71_DEV: val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div); val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div); break; @@ -95,9 +97,11 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas { struct device *dev = dai->component->dev; struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai); + struct acp_chip_info *chip; struct acp_stream *stream; int slot_len, no_of_slots; + chip = dev_get_platdata(dev); switch (slot_width) { case SLOT_WIDTH_8: slot_len = 8; @@ -116,15 +120,38 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas return -EINVAL; } - switch (slots) { - case 1 ... 7: - no_of_slots = slots; + switch (chip->acp_rev) { + case ACP3X_DEV: + case ACP6X_DEV: + switch (slots) { + case 1 ... 7: + no_of_slots = slots; + break; + case 8: + no_of_slots = 0; + break; + default: + dev_err(dev, "Unsupported slots %d\n", slots); + return -EINVAL; + } break; - case 8: - no_of_slots = 0; + case ACP63_DEV: + case ACP70_DEV: + case ACP71_DEV: + switch (slots) { + case 1 ... 31: + no_of_slots = slots; + break; + case 32: + no_of_slots = 0; + break; + default: + dev_err(dev, "Unsupported slots %d\n", slots); + return -EINVAL; + } break; default: - dev_err(dev, "Unsupported slots %d\n", slots); + dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev); return -EINVAL; } @@ -132,12 +159,30 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas spin_lock_irq(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { - if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) - adata->tdm_tx_fmt[stream->dai_id - 1] = + switch (chip->acp_rev) { + case ACP3X_DEV: + case ACP6X_DEV: + if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + adata->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); - else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) - adata->tdm_rx_fmt[stream->dai_id - 1] = + else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) + adata->tdm_rx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); + break; + case ACP63_DEV: + case ACP70_DEV: + case ACP71_DEV: + if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + adata->tdm_tx_fmt[stream->dai_id - 1] = + FRM_LEN | (slots << 13) | (slot_len << 18); + else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) + adata->tdm_rx_fmt[stream->dai_id - 1] = + FRM_LEN | (slots << 13) | (slot_len << 18); + break; + default: + dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev); + return -EINVAL; + } } spin_unlock_irq(&adata->acp_lock); return 0; @@ -296,6 +341,41 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ default: return -EINVAL; } + + switch (params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 48000: + case 96000: + case 192000: + switch (params_channels(params)) { + case 2: + break; + case 4: + bclk_div_val = bclk_div_val >> 1; + lrclk_div_val = lrclk_div_val << 1; + break; + case 8: + bclk_div_val = bclk_div_val >> 2; + lrclk_div_val = lrclk_div_val << 2; + break; + case 16: + bclk_div_val = bclk_div_val >> 3; + lrclk_div_val = lrclk_div_val << 3; + break; + case 32: + bclk_div_val = bclk_div_val >> 4; + lrclk_div_val = lrclk_div_val << 4; + break; + default: + dev_err(dev, "Unsupported channels %#x\n", + params_channels(params)); + } + break; + default: + break; + } adata->lrclk_div = lrclk_div_val; adata->bclk_div = bclk_div_val; } @@ -321,16 +401,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { switch (dai->driver->id) { case I2S_BT_INSTANCE: - water_val = ACP_BT_TX_INTR_WATERMARK_SIZE; + water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata); reg_val = ACP_BTTDM_ITER; ier_val = ACP_BTTDM_IER; - buf_reg = ACP_BT_TX_RINGBUFSIZE; + buf_reg = ACP_BT_TX_RINGBUFSIZE(adata); break; case I2S_SP_INSTANCE: - water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE; + water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata); reg_val = ACP_I2STDM_ITER; ier_val = ACP_I2STDM_IER; - buf_reg = ACP_I2S_TX_RINGBUFSIZE; + buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata); break; case I2S_HS_INSTANCE: water_val = ACP_HS_TX_INTR_WATERMARK_SIZE; @@ -345,16 +425,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct } else { switch (dai->driver->id) { case I2S_BT_INSTANCE: - water_val = ACP_BT_RX_INTR_WATERMARK_SIZE; + water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata); reg_val = ACP_BTTDM_IRER; ier_val = ACP_BTTDM_IER; - buf_reg = ACP_BT_RX_RINGBUFSIZE; + buf_reg = ACP_BT_RX_RINGBUFSIZE(adata); break; case I2S_SP_INSTANCE: - water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE; + water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata); reg_val = ACP_I2STDM_IRER; ier_val = ACP_I2STDM_IER; - buf_reg = ACP_I2S_RX_RINGBUFSIZE; + buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata); break; case I2S_HS_INSTANCE: water_val = ACP_HS_RX_INTR_WATERMARK_SIZE; @@ -367,6 +447,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct return -EINVAL; } } + writel(period_bytes, adata->acp_base + water_val); writel(buf_size, adata->acp_base + buf_reg); if (rsrc->soc_mclk) @@ -436,52 +517,67 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip; struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream = substream->runtime->private_data; u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0; u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl; unsigned int dir = substream->stream; + chip = dev_get_platdata(dev); switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_I2S_TX_DMA_SIZE; + reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_TX_FIFOADDR; - reg_fifo_size = ACP_I2S_TX_FIFOSIZE; + reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); + reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); - phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata)); } else { - reg_dma_size = ACP_I2S_RX_DMA_SIZE; + reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_RX_FIFOADDR; - reg_fifo_size = ACP_I2S_RX_FIFOSIZE; - phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR); + reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); + reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); + + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; + else + phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata)); } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_BT_TX_DMA_SIZE; + reg_dma_size = ACP_BT_TX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_TX_FIFOADDR; - reg_fifo_size = ACP_BT_TX_FIFOSIZE; + reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); + reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata)); } else { - reg_dma_size = ACP_BT_RX_DMA_SIZE; + reg_dma_size = ACP_BT_RX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_RX_FIFOADDR; - reg_fifo_size = ACP_BT_RX_FIFOSIZE; + reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); + reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); - phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; + else + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); } break; case I2S_HS_INSTANCE: @@ -492,7 +588,10 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_HS_TX_FIFOADDR; reg_fifo_size = ACP_HS_TX_FIFOSIZE; - phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); } else { reg_dma_size = ACP_HS_RX_DMA_SIZE; @@ -501,7 +600,10 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_HS_RX_FIFOADDR; reg_fifo_size = ACP_HS_RX_FIFOSIZE; - phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + if (chip->acp_rev >= ACP70_DEV) + phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; + else + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); } break; diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 4422cec81e3c..be01b178172e 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -113,40 +113,40 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_I2S_TX_DMA_SIZE; + reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_TX_FIFOADDR; - reg_fifo_size = ACP_I2S_TX_FIFOSIZE; + reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); + reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); + writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata)); } else { - reg_dma_size = ACP_I2S_RX_DMA_SIZE; + reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_RX_FIFOADDR; - reg_fifo_size = ACP_I2S_RX_FIFOSIZE; + reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); + reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR); + writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata)); } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_BT_TX_DMA_SIZE; + reg_dma_size = ACP_BT_TX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_TX_FIFOADDR; - reg_fifo_size = ACP_BT_TX_FIFOSIZE; + reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); + reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); + writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata)); } else { - reg_dma_size = ACP_BT_RX_DMA_SIZE; + reg_dma_size = ACP_BT_RX_DMA_SIZE(adata); acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_RX_FIFOADDR; - reg_fifo_size = ACP_BT_RX_FIFOSIZE; + reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); + reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); + writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); } break; case I2S_HS_INSTANCE: @@ -270,6 +270,7 @@ static int acp_power_on(struct acp_chip_info *chip) acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL; break; case ACP70_DEV: + case ACP71_DEV: acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL; break; @@ -321,6 +322,8 @@ int acp_init(struct acp_chip_info *chip) pr_err("ACP reset failed\n"); return ret; } + if (chip->acp_rev >= ACP70_DEV) + writel(0, chip->base + ACP_ZSC_DSP_CTRL); return 0; } EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON); @@ -334,8 +337,10 @@ int acp_deinit(struct acp_chip_info *chip) if (ret) return ret; - if (chip->acp_rev != ACP70_DEV) + if (chip->acp_rev < ACP70_DEV) writel(0, chip->base + ACP_CONTROL); + else + writel(0x01, chip->base + ACP_ZSC_DSP_CTRL); return 0; } EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); @@ -456,6 +461,7 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) check_acp6x_config(chip); break; case ACP70_DEV: + case ACP71_DEV: pdm_addr = ACP70_PDM_ADDR; check_acp70_config(chip); break; diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 0d529e32e552..d104f7e8fdcd 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -242,11 +242,4 @@ module_platform_driver(acp_asoc_audio); MODULE_IMPORT_NS(SND_SOC_AMD_MACH); MODULE_DESCRIPTION("ACP chrome audio support"); -MODULE_ALIAS("platform:acp3xalc56821019"); -MODULE_ALIAS("platform:acp3xalc5682sm98360"); -MODULE_ALIAS("platform:acp3xalc5682s1019"); -MODULE_ALIAS("platform:acp3x-es83xx"); -MODULE_ALIAS("platform:rmb-nau8825-max"); -MODULE_ALIAS("platform:rmb-rt5682s-rt1019"); -MODULE_ALIAS("platform:acp-pdm-mach"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index a36300a4ed8a..e9ff4815c12c 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -1766,7 +1766,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) } else if (drv_data->platform == ACP63) { links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else if (drv_data->platform == ACP70) { + } else if ((drv_data->platform == ACP70) || (drv_data->platform == ACP71)) { links[i].platforms = platform_acp70_component; links[i].num_platforms = ARRAY_SIZE(platform_acp70_component); } else { diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index a48546d8d407..93d9e3886b7e 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -56,6 +56,7 @@ enum platform_end_point { REMBRANDT, ACP63, ACP70, + ACP71, }; struct acp_mach_ops { diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index b0304b813cad..f7450a5bd103 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -95,6 +95,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id chip->name = "acp_asoc_acp70"; chip->acp_rev = ACP70_DEV; break; + case 0x71: + chip->name = "acp_asoc_acp70"; + chip->acp_rev = ACP71_DEV; + break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); ret = -EINVAL; diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index bb79269c2fc1..22dd8988d005 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -31,9 +31,11 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip; u32 physical_addr, size_dmic, period_bytes; unsigned int dmic_ctrl; + chip = dev_get_platdata(dev); /* Enable default DMIC clk */ writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); dmic_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); @@ -45,7 +47,10 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, size_dmic = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); - physical_addr = stream->reg_offset + MEM_WINDOW_START; + if (chip->acp_rev >= ACP70_DEV) + physical_addr = ACP7x_DMIC_MEM_WINDOW_START; + else + physical_addr = stream->reg_offset + MEM_WINDOW_START; /* Init DMIC Ring buffer */ writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 4f409cd09c11..3a7a467b7063 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -68,6 +68,46 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = { .periods_max = CAPTURE_MAX_NUM_PERIODS, }; +static const struct snd_pcm_hardware acp6x_pcm_hardware_playback = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, + .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, + .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, + .periods_min = PLAYBACK_MIN_NUM_PERIODS, + .periods_max = PLAYBACK_MAX_NUM_PERIODS, +}; + +static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, + .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, + .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, + .periods_min = CAPTURE_MIN_NUM_PERIODS, + .periods_max = CAPTURE_MAX_NUM_PERIODS, +}; + int acp_machine_select(struct acp_dev_data *adata) { struct snd_soc_acpi_mach *mach; @@ -137,17 +177,20 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { struct acp_resource *rsrc = adata->rsrc; - u32 pte_reg, pte_size, reg_val; + u32 reg_val; - /* Use ATU base Group5 */ - pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5; - pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5; + reg_val = rsrc->sram_pte_offset; stream->reg_offset = 0x02000000; - /* Group Enable */ - reg_val = rsrc->sram_pte_offset; - writel(reg_val | BIT(31), adata->acp_base + pte_reg); - writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); + writel((reg_val + GRP1_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); + writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + + writel((reg_val + GRP2_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2); + writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2); + + writel(reg_val | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5); + writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5); + writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); @@ -161,7 +204,40 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s u32 low, high, val; u16 page_idx; - val = stream->pte_offset; + switch (adata->platform) { + case ACP70: + case ACP71: + switch (stream->dai_id) { + case I2S_SP_INSTANCE: + if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + val = 0x0; + else + val = 0x1000; + break; + case I2S_BT_INSTANCE: + if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + val = 0x2000; + else + val = 0x3000; + break; + case I2S_HS_INSTANCE: + if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) + val = 0x4000; + else + val = 0x5000; + break; + case DMIC_INSTANCE: + val = 0x6000; + break; + default: + dev_err(adata->dev, "Invalid dai id %x\n", stream->dai_id); + return; + } + break; + default: + val = stream->pte_offset; + break; + } for (page_idx = 0; page_idx < num_pages; page_idx++) { /* Load the low address of page int ACP SRAM through SRBM */ @@ -183,6 +259,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs struct snd_pcm_runtime *runtime = substream->runtime; struct device *dev = component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip; struct acp_stream *stream; int ret; @@ -191,11 +268,23 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs return -ENOMEM; stream->substream = substream; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - runtime->hw = acp_pcm_hardware_playback; - else - runtime->hw = acp_pcm_hardware_capture; + chip = dev_get_platdata(dev); + switch (chip->acp_rev) { + case ACP63_DEV: + case ACP70_DEV: + case ACP71_DEV: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = acp6x_pcm_hardware_playback; + else + runtime->hw = acp6x_pcm_hardware_capture; + break; + default: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = acp_pcm_hardware_playback; + else + runtime->hw = acp_pcm_hardware_capture; + break; + } ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE); if (ret) { diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index e19981c7d65a..396434a45eea 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -295,7 +295,7 @@ static const struct dev_pm_ops rmb_dma_pm_ops = { static struct platform_driver rembrandt_driver = { .probe = rembrandt_audio_probe, - .remove_new = rembrandt_audio_remove, + .remove = rembrandt_audio_remove, .driver = { .name = "acp_asoc_rembrandt", .pm = &rmb_dma_pm_ops, diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index db835ed7c208..5e3f730aa6bf 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -244,7 +244,7 @@ static const struct dev_pm_ops rn_dma_pm_ops = { static struct platform_driver renoir_driver = { .probe = renoir_audio_probe, - .remove_new = renoir_audio_remove, + .remove = renoir_audio_remove, .driver = { .name = "acp_asoc_renoir", .pm = &rn_dma_pm_ops, diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c new file mode 100644 index 000000000000..6c50c8276538 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-sof-mach - ASoC Machine driver for AMD SoundWire platforms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "soc_amd_sdw_common.h" +#include "../../codecs/rt711.h" + +static unsigned long sof_sdw_quirk = RT711_JD1; +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (SOC_JACK_JDSRC(sof_sdw_quirk)) + dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", + SOC_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC) + dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n"); +} + +static int sof_sdw_quirk_cb(const struct dmi_system_id *id) +{ + sof_sdw_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_sdw_quirk_table[] = { + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"), + }, + .driver_data = (void *)RT711_JD2, + }, + {} +}; + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:04:00.5", + } +}; + +static const struct snd_soc_ops sdw_ops = { + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, +}; + +static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) +{ + switch (sdw_link_id) { + case AMD_SDW0: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_RX; + break; + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_TX; + break; + case SOC_SDW_AMP_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_RX; + break; + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO2_RX; + break; + default: + dev_err(dev, "Invalid be id:%d\n", be_id); + return -EINVAL; + } + break; + case AMD_SDW1: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + case SOC_SDW_AMP_IN_DAI_ID: + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_RX; + break; + default: + dev_err(dev, "invalid be_id:%d\n", be_id); + return -EINVAL; + } + break; + default: + dev_err(dev, "Invalid link id:%d\n", sdw_link_id); + return -EINVAL; + } + return 0; +} + +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; + +static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *sof_dai, + struct snd_soc_dai_link **dai_links, + int *be_id, struct snd_soc_codec_conf **codec_conf) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; + struct asoc_sdw_endpoint *sof_end; + int cpu_pin_id; + int stream; + int ret; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->name_prefix) { + (*codec_conf)->dlc.name = sof_end->codec_name; + (*codec_conf)->name_prefix = sof_end->name_prefix; + (*codec_conf)++; + } + + if (sof_end->include_sidecar) { + ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); + if (ret) + return ret; + } + } + + for_each_pcm_streams(stream) { + static const char * const sdw_stream_name[] = { + "SDW%d-PIN%d-PLAYBACK", + "SDW%d-PIN%d-CAPTURE", + "SDW%d-PIN%d-PLAYBACK-%s", + "SDW%d-PIN%d-CAPTURE-%s", + }; + struct snd_soc_dai_link_ch_map *codec_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + int num_cpus = hweight32(sof_dai->link_mask[stream]); + int num_codecs = sof_dai->num_devs[stream]; + int playback, capture; + int i = 0, j = 0; + char *name; + + if (!sof_dai->num_devs[stream]) + continue; + + sof_end = list_first_entry(&sof_dai->endpoints, + struct asoc_sdw_endpoint, list); + + *be_id = sof_end->dai_info->dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); + return -EINVAL; + } + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask - 1), + *be_id, &cpu_pin_id, dev); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + /* create stream name according to first link id */ + if (ctx->append_dai_type) { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream + 2], + ffs(sof_end->link_mask) - 1, + cpu_pin_id, + type_strings[sof_end->dai_info->dai_type]); + } else { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], + ffs(sof_end->link_mask) - 1, + cpu_pin_id); + } + if (!name) + return -ENOMEM; + + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (!sof_end->dai_info->direction[stream]) + continue; + + int link_num = ffs(sof_end->link_mask) - 1; + + cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu[%d].dai_name:%s\n", i, cpus[i].dai_name); + if (!cpus[i].dai_name) + return -ENOMEM; + + codec_maps[j].cpu = i; + codec_maps[j].codec = j; + + codecs[j].name = sof_end->codec_name; + codecs[j].dai_name = sof_end->dai_info->dai_name; + j++; + } + + WARN_ON(j != num_codecs); + + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); + capture = (stream == SNDRV_PCM_STREAM_CAPTURE); + + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform_component, + ARRAY_SIZE(platform_component), codecs, num_codecs, + asoc_sdw_rtd_init, &sdw_ops); + + /* + * SoundWire DAILINKs use 'stream' functions and Bank Switch operations + * based on wait_for_completion(), tag them as 'nonatomic'. + */ + (*dai_links)->nonatomic = true; + (*dai_links)->ch_maps = codec_maps; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->dai_info->init) + sof_end->dai_info->init(card, *dai_links, + sof_end->codec_info, + playback); + } + + (*dai_links)++; + } + + return 0; +} + +static int create_sdw_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_dailink *sof_dais, + struct snd_soc_codec_conf **codec_conf) +{ + int ret; + + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { + int current_be_id; + + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_be_id, codec_conf); + if (ret) + return ret; + + /* Update the be_id to match the highest ID used for SDW link */ + if (*be_id < current_be_id) + *be_id = current_be_id; + + sof_dais++; + } + + return 0; +} + +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) +{ + struct device *dev = card->dev; + int ret; + + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec", + 0, 1, // DMIC only supports capture + "acp-sof-dmic", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + asoc_sdw_dmic_init, NULL); + if (ret) + return ret; + + (*dai_links)++; + + return 0; +} + +static int sof_card_dai_links_create(struct snd_soc_card *card) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + int sdw_be_num = 0, dmic_num = 0; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct snd_soc_codec_conf *codec_conf; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; + struct snd_soc_dai_link *dai_links; + int num_devs = 0; + int num_ends = 0; + int num_links; + int be_id = 0; + int ret; + + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + if (ret < 0) { + dev_err(dev, "failed to count devices/endpoints: %d\n", ret); + return ret; + } + + /* One per DAI link, worst case is a DAI link for every endpoint */ + sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); + if (!sof_dais) + return -ENOMEM; + + /* One per endpoint, ie. each DAI on each codec/amp */ + sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); + if (!sof_ends) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + if (ret < 0) + goto err_end; + + sdw_be_num = ret; + + /* enable dmic */ + if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num) + dmic_num = 1; + + dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); + + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) { + ret = -ENOMEM; + goto err_end; + } + + /* allocate BE dailinks */ + num_links = sdw_be_num + dmic_num; + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) { + ret = -ENOMEM; + goto err_end; + } + + card->codec_conf = codec_conf; + card->num_configs = num_devs; + card->dai_link = dai_links; + card->num_links = num_links; + + /* SDW */ + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + sof_dais, &codec_conf); + if (ret) + goto err_end; + } + + /* dmic */ + if (dmic_num > 0) { + if (ctx->ignore_internal_dmic) { + dev_warn(dev, "Ignoring ACP DMIC\n"); + } else { + ret = create_dmic_dailinks(card, &dai_links, &be_id); + if (ret) + goto err_end; + } + } + + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); + +err_end: + kfree(sof_ends); +err_dai: + kfree(sof_dais); + + return ret; +} + +/* SoC card */ +static const char sdw_card_long_name[] = "AMD Soundwire SOF"; + +static int mc_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card; + struct amd_mc_ctx *amd_ctx; + struct asoc_sdw_mc_private *ctx; + int amp_num = 0, i; + int ret; + + amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL); + if (!amd_ctx) + return -ENOMEM; + + amd_ctx->acp_rev = mach->mach_params.subsystem_rev; + amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); + ctx->private = amd_ctx; + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "amd-soundwire"; + card->owner = THIS_MODULE; + card->late_probe = asoc_sdw_card_late_probe; + + snd_soc_card_set_drvdata(card, ctx); + + dmi_check_system(sof_sdw_quirk_table); + + if (quirk_override != -1) { + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + sof_sdw_quirk, quirk_override); + sof_sdw_quirk = quirk_override; + } + + log_quirks(card->dev); + + ctx->mc_quirk = sof_sdw_quirk; + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ctx->codec_info_list_count; i++) + codec_info_list[i].amp_num = 0; + + ret = sof_card_dai_links_create(card); + if (ret < 0) + return ret; + + /* + * the default amp_num is zero for each codec and + * amp_num will only be increased for active amp + * codecs on used platform + */ + for (i = 0; i < ctx->codec_info_list_count; i++) + amp_num += codec_info_list[i].amp_num; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + " cfg-amp:%d", amp_num); + if (!card->components) + return -ENOMEM; + + card->long_name = sdw_card_long_name; + + /* Register the card */ + ret = devm_snd_soc_register_card(card->dev, card); + if (ret) { + dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + asoc_sdw_mc_dailink_exit_loop(card); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static void mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + asoc_sdw_mc_dailink_exit_loop(card); +} + +static const struct platform_device_id mc_id_table[] = { + { "amd_sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + +static struct platform_driver sof_sdw_driver = { + .driver = { + .name = "amd_sof_sdw", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, + .remove = mc_remove, + .id_table = mc_id_table, +}; + +module_platform_driver(sof_sdw_driver); + +MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda platform == ACP70) + device_id = 0x1507; + else if (adata->platform == ACP71) + device_id = 0x1122; + else + return -ENODEV; + + smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL); + + if (!smn_dev) + return -ENODEV; + + /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/ + smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER); + + return 0; +} + static int acp_acp70_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; struct acp_dev_data *adata; struct resource *res; + int ret; chip = dev_get_platdata(&pdev->dev); if (!chip || !chip->base) { @@ -147,7 +174,11 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP70_DEV) { + switch (chip->acp_rev) { + case ACP70_DEV: + case ACP71_DEV: + break; + default: dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -178,11 +209,21 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) adata->num_dai = ARRAY_SIZE(acp70_dai); adata->rsrc = &rsrc; adata->machines = snd_soc_acpi_amd_acp70_acp_machines; - adata->platform = ACP70; + if (chip->acp_rev == ACP70_DEV) + adata->platform = ACP70; + else + adata->platform = ACP71; + adata->flag = chip->flag; acp_machine_select(adata); dev_set_drvdata(dev, adata); + + ret = acp70_i2s_master_clock_generate(adata); + if (ret) { + dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n"); + return ret; + } acp_enable_interrupts(adata); acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); @@ -237,7 +278,7 @@ static const struct dev_pm_ops acp70_dma_pm_ops = { static struct platform_driver acp70_driver = { .probe = acp_acp70_audio_probe, - .remove_new = acp_acp70_audio_remove, + .remove = acp_acp70_audio_remove, .driver = { .name = "acp_asoc_acp70", .pm = &acp70_dma_pm_ops, diff --git a/sound/soc/amd/acp/amd-acp63-acpi-match.c b/sound/soc/amd/acp/amd-acp63-acpi-match.c new file mode 100644 index 000000000000..be9367913073 --- /dev/null +++ b/sound/soc/amd/acp/amd-acp63-acpi-match.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * amd-acp63-acpi-match.c - tables and support for ACP 6.3 platform + * ACPI enumeration. + * + * Copyright 2024 Advanced Micro Devices, Inc. + */ + +#include +#include "../mach-config.h" + +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_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1 +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1 +}; + +static const struct snd_soc_acpi_adr_device rt711_rt1316_group_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + }, + { + .adr = 0x000030025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + }, + { + .adr = 0x000032025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + }, +}; + +static const struct snd_soc_acpi_adr_device rt714_adr[] = { + { + .adr = 0x130025d071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_link_adr acp63_4_in_1_sdca[] = { + { .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_rt1316_group_adr), + .adr_d = rt711_rt1316_group_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt714_adr), + .adr_d = rt714_adr, + }, + {} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { + { + .link_mask = BIT(0) | BIT(1), + .links = acp63_4_in_1_sdca, + .drv_name = "amd_sof_sdw", + .sof_tplg_filename = "sof-acp_6_3-rt711-l0-rt1316-l0-rt714-l1.tplg", + .fw_filename = "sof-acp_6_3.ri", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_sdw_machines); + +MODULE_DESCRIPTION("AMD ACP6.3 tables and support for ACPI enumeration"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 87a4813783f9..854269fea875 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -22,6 +22,7 @@ #define ACP6X_DEV 6 #define ACP63_DEV 0x63 #define ACP70_DEV 0x70 +#define ACP71_DEV 0x71 #define DMIC_INSTANCE 0x00 #define I2S_SP_INSTANCE 0x01 @@ -61,6 +62,14 @@ #define I2S_HS_TX_MEM_WINDOW_START 0x40A0000 #define I2S_HS_RX_MEM_WINDOW_START 0x40C0000 +#define ACP7x_I2S_SP_TX_MEM_WINDOW_START 0x4000000 +#define ACP7x_I2S_SP_RX_MEM_WINDOW_START 0x4200000 +#define ACP7x_I2S_BT_TX_MEM_WINDOW_START 0x4400000 +#define ACP7x_I2S_BT_RX_MEM_WINDOW_START 0x4600000 +#define ACP7x_I2S_HS_TX_MEM_WINDOW_START 0x4800000 +#define ACP7x_I2S_HS_RX_MEM_WINDOW_START 0x4A00000 +#define ACP7x_DMIC_MEM_WINDOW_START 0x4C00000 + #define SP_PB_FIFO_ADDR_OFFSET 0x500 #define SP_CAPT_FIFO_ADDR_OFFSET 0x700 #define BT_PB_FIFO_ADDR_OFFSET 0x900 @@ -103,6 +112,8 @@ #define ACP70_PGFSM_CONTROL ACP6X_PGFSM_CONTROL #define ACP70_PGFSM_STATUS ACP6X_PGFSM_STATUS +#define ACP_ZSC_DSP_CTRL 0x0001014 +#define ACP_ZSC_STS 0x0001018 #define ACP_SOFT_RST_DONE_MASK 0x00010001 #define ACP_PGFSM_CNTL_POWER_ON_MASK 0xffffffff @@ -256,12 +267,12 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int if (direction == SNDRV_PCM_STREAM_PLAYBACK) { switch (dai_id) { case I2S_BT_INSTANCE: - high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW); + high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(adata)); + low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW(adata)); break; case I2S_SP_INSTANCE: - high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW); + high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(adata)); + low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(adata)); break; case I2S_HS_INSTANCE: high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH); @@ -274,12 +285,12 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int } else { switch (dai_id) { case I2S_BT_INSTANCE: - high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW); + high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(adata)); + low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW(adata)); break; case I2S_SP_INSTANCE: - high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW); + high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(adata)); + low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(adata)); break; case I2S_HS_INSTANCE: high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH); diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h index 18da734c0e9e..117ea63e85c6 100644 --- a/sound/soc/amd/acp/chip_offset_byte.h +++ b/sound/soc/amd/acp/chip_offset_byte.h @@ -12,9 +12,16 @@ #define _ACP_IP_OFFSET_HEADER #define ACPAXI2AXI_ATU_CTRL 0xC40 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04 +#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0xC08 +#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0xC0C #define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20 #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24 +#define GRP1_OFFSET 0x0 +#define GRP2_OFFSET 0x4000 + #define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_STATUS 0x1420 #define ACP_SOFT_RESET 0x1000 @@ -32,42 +39,47 @@ /* Registers from ACP_AUDIO_BUFFERS block */ -#define ACP_I2S_RX_RINGBUFADDR 0x2000 -#define ACP_I2S_RX_RINGBUFSIZE 0x2004 -#define ACP_I2S_RX_LINKPOSITIONCNTR 0x2008 -#define ACP_I2S_RX_FIFOADDR 0x200C -#define ACP_I2S_RX_FIFOSIZE 0x2010 -#define ACP_I2S_RX_DMA_SIZE 0x2014 -#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x2018 -#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x201C -#define ACP_I2S_RX_INTR_WATERMARK_SIZE 0x2020 -#define ACP_I2S_TX_RINGBUFADDR 0x2024 -#define ACP_I2S_TX_RINGBUFSIZE 0x2028 -#define ACP_I2S_TX_LINKPOSITIONCNTR 0x202C -#define ACP_I2S_TX_FIFOADDR 0x2030 -#define ACP_I2S_TX_FIFOSIZE 0x2034 -#define ACP_I2S_TX_DMA_SIZE 0x2038 -#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x203C -#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x2040 -#define ACP_I2S_TX_INTR_WATERMARK_SIZE 0x2044 -#define ACP_BT_RX_RINGBUFADDR 0x2048 -#define ACP_BT_RX_RINGBUFSIZE 0x204C -#define ACP_BT_RX_LINKPOSITIONCNTR 0x2050 -#define ACP_BT_RX_FIFOADDR 0x2054 -#define ACP_BT_RX_FIFOSIZE 0x2058 -#define ACP_BT_RX_DMA_SIZE 0x205C -#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x2060 -#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x2064 -#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x2068 -#define ACP_BT_TX_RINGBUFADDR 0x206C -#define ACP_BT_TX_RINGBUFSIZE 0x2070 -#define ACP_BT_TX_LINKPOSITIONCNTR 0x2074 -#define ACP_BT_TX_FIFOADDR 0x2078 -#define ACP_BT_TX_FIFOSIZE 0x207C -#define ACP_BT_TX_DMA_SIZE 0x2080 -#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084 -#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088 -#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x208C +#define ACP_I2S_REG_ADDR(acp_adata, addr) \ + ((addr) + (acp_adata->rsrc->irqp_used * \ + acp_adata->rsrc->irq_reg_offset)) + +#define ACP_I2S_RX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2000) +#define ACP_I2S_RX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2004) +#define ACP_I2S_RX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2008) +#define ACP_I2S_RX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x200C) +#define ACP_I2S_RX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2010) +#define ACP_I2S_RX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2014) +#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2018) +#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x201C) +#define ACP_I2S_RX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2020) +#define ACP_I2S_TX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2024) +#define ACP_I2S_TX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2028) +#define ACP_I2S_TX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x202C) +#define ACP_I2S_TX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2030) +#define ACP_I2S_TX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2034) +#define ACP_I2S_TX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2038) +#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x203C) +#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2040) +#define ACP_I2S_TX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2044) +#define ACP_BT_RX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2048) +#define ACP_BT_RX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x204C) +#define ACP_BT_RX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2050) +#define ACP_BT_RX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2054) +#define ACP_BT_RX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2058) +#define ACP_BT_RX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x205C) +#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2060) +#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2064) +#define ACP_BT_RX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2068) +#define ACP_BT_TX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x206C) +#define ACP_BT_TX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2070) +#define ACP_BT_TX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2074) +#define ACP_BT_TX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2078) +#define ACP_BT_TX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x207C) +#define ACP_BT_TX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2080) +#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2084) +#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2088) +#define ACP_BT_TX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x208C) + #define ACP_HS_RX_RINGBUFADDR 0x3A90 #define ACP_HS_RX_RINGBUFSIZE 0x3A94 #define ACP_HS_RX_LINKPOSITIONCNTR 0x3A98 diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h new file mode 100644 index 000000000000..f1bd5a7afc8e --- /dev/null +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved + */ + +/* + * soc_amd_sdw_common.h - prototypes for common helpers + */ + +#ifndef SOC_AMD_SDW_COMMON_H +#define SOC_AMD_SDW_COMMON_H + +#include +#include +#include +#include + +#define ACP63_SDW_MAX_CPU_DAIS 8 +#define ACP63_SDW_MAX_LINKS 2 + +#define AMD_SDW_MAX_GROUPS 9 +#define ACP63_PCI_REV 0x63 +#define SOC_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) +#define ASOC_SDW_FOUR_SPK BIT(4) +#define ASOC_SDW_ACP_DMIC BIT(5) + +#define AMD_SDW0 0 +#define AMD_SDW1 1 +#define ACP63_SW0_AUDIO0_TX 0 +#define ACP63_SW0_AUDIO1_TX 1 +#define ACP63_SW0_AUDIO2_TX 2 + +#define ACP63_SW0_AUDIO0_RX 3 +#define ACP63_SW0_AUDIO1_RX 4 +#define ACP63_SW0_AUDIO2_RX 5 + +#define ACP63_SW1_AUDIO0_TX 0 +#define ACP63_SW1_AUDIO0_RX 1 + +struct amd_mc_ctx { + unsigned int acp_rev; + unsigned int max_sdw_links; +}; + +#endif diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 7af0f9cf3921..1a967da35a0f 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -23,6 +23,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c index 7bbacbab1095..318fc260f293 100644 --- a/sound/soc/amd/ps/ps-pdm-dma.c +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -448,7 +448,7 @@ static const struct dev_pm_ops acp63_pdm_pm_ops = { static struct platform_driver acp63_pdm_dma_driver = { .probe = acp63_pdm_audio_probe, - .remove_new = acp63_pdm_audio_remove, + .remove = acp63_pdm_audio_remove, .driver = { .name = "acp_ps_pdm_dma", .pm = &acp63_pdm_pm_ops, diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 2f630753278d..3b4b9c6b3171 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -551,7 +551,7 @@ static const struct dev_pm_ops acp63_pm_ops = { static struct platform_driver acp63_sdw_dma_driver = { .probe = acp63_sdw_platform_probe, - .remove_new = acp63_sdw_platform_remove, + .remove = acp63_sdw_platform_remove, .driver = { .name = "amd_ps_sdw_dma", .pm = &acp63_pm_ops, diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 3a50558f6751..bb9ed52d744d 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -509,7 +509,7 @@ static const struct dev_pm_ops acp3x_pm_ops = { static struct platform_driver acp3x_dma_driver = { .probe = acp3x_audio_probe, - .remove_new = acp3x_audio_remove, + .remove = acp3x_audio_remove, .driver = { .name = "acp3x_rv_i2s_dma", .pm = &acp3x_pm_ops, diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index c3b47e9bd239..95ac8c680037 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -489,7 +489,7 @@ static const struct dev_pm_ops acp_pdm_pm_ops = { static struct platform_driver acp_pdm_dma_driver = { .probe = acp_pdm_audio_probe, - .remove_new = acp_pdm_audio_remove, + .remove = acp_pdm_audio_remove, .driver = { .name = "acp_rn_pdm_dma", .pm = &acp_pdm_pm_ops, diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c index 491b16e52a72..d5965f2b09bc 100644 --- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c +++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c @@ -499,7 +499,7 @@ static const struct dev_pm_ops acp5x_pm_ops = { static struct platform_driver acp5x_dma_driver = { .probe = acp5x_audio_probe, - .remove_new = acp5x_audio_remove, + .remove = acp5x_audio_remove, .driver = { .name = "acp5x_i2s_dma", .pm = &acp5x_pm_ops, diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c index 72c4591e451b..3eb3e82efb10 100644 --- a/sound/soc/amd/yc/acp6x-pdm-dma.c +++ b/sound/soc/amd/yc/acp6x-pdm-dma.c @@ -440,7 +440,7 @@ static const struct dev_pm_ops acp6x_pdm_pm_ops = { static struct platform_driver acp6x_pdm_dma_driver = { .probe = acp6x_pdm_audio_probe, - .remove_new = acp6x_pdm_audio_remove, + .remove = acp6x_pdm_audio_remove, .driver = { .name = "acp_yc_pdm_dma", .pm = &acp6x_pdm_pm_ops, diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 3780aca71076..c9e7d40c47cc 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -1179,7 +1179,7 @@ static struct platform_driver apple_mca_driver = { .of_match_table = apple_mca_of_match, }, .probe = apple_mca_probe, - .remove_new = apple_mca_remove, + .remove = apple_mca_remove, }; module_platform_driver(apple_mca_driver); diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 6c20c643f321..762199faf872 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -733,7 +733,7 @@ static struct platform_driver atmel_i2s_driver = { .of_match_table = atmel_i2s_dt_ids, }, .probe = atmel_i2s_probe, - .remove_new = atmel_i2s_remove, + .remove = atmel_i2s_remove, }; module_platform_driver(atmel_i2s_driver); diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index b7f16ea0cdfc..0f4021c6c588 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -187,7 +187,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = { .pm = &snd_soc_pm_ops, }, .probe = atmel_asoc_wm8904_probe, - .remove_new = atmel_asoc_wm8904_remove, + .remove = atmel_asoc_wm8904_remove, }; module_platform_driver(atmel_asoc_wm8904_driver); diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 193dd7acceb0..17d138bb9064 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -221,6 +221,15 @@ #define MCHP_I2SMCC_MAX_CHANNELS 8 #define MCHP_I2MCC_TDM_SLOT_WIDTH 32 +/* + * ---- DMA chunk size allowed ---- + */ +#define MCHP_I2SMCC_DMA_8_WORD_CHUNK 8 +#define MCHP_I2SMCC_DMA_4_WORD_CHUNK 4 +#define MCHP_I2SMCC_DMA_2_WORD_CHUNK 2 +#define MCHP_I2SMCC_DMA_1_WORD_CHUNK 1 +#define DMA_BURST_ALIGNED(_p, _s, _w) !(_p % (_s * _w)) + static const struct regmap_config mchp_i2s_mcc_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -504,12 +513,30 @@ static int mchp_i2s_mcc_is_running(struct mchp_i2s_mcc_dev *dev) return !!(sr & (MCHP_I2SMCC_SR_TXEN | MCHP_I2SMCC_SR_RXEN)); } +static inline int mchp_i2s_mcc_period_to_maxburst(int period_size, int sample_size) +{ + int p_size = period_size; + int s_size = sample_size; + + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_8_WORD_CHUNK)) + return MCHP_I2SMCC_DMA_8_WORD_CHUNK; + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_4_WORD_CHUNK)) + return MCHP_I2SMCC_DMA_4_WORD_CHUNK; + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_2_WORD_CHUNK)) + return MCHP_I2SMCC_DMA_2_WORD_CHUNK; + return MCHP_I2SMCC_DMA_1_WORD_CHUNK; +} + static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { unsigned long rate = 0; struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); + int sample_bytes = params_physical_width(params) / 8; + int period_bytes = params_period_size(params) * + params_channels(params) * sample_bytes; + int maxburst; u32 mra = 0; u32 mrb = 0; unsigned int channels = params_channels(params); @@ -519,9 +546,9 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, int ret; bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n", + dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n", __func__, params_rate(params), params_format(params), - params_width(params), params_channels(params)); + params_width(params), params_channels(params), period_bytes); switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -630,11 +657,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, * We must have the same burst size configured * in the DMA transfer and in out IP */ - mrb |= MCHP_I2SMCC_MRB_DMACHUNK(channels); + maxburst = mchp_i2s_mcc_period_to_maxburst(period_bytes, sample_bytes); + mrb |= MCHP_I2SMCC_MRB_DMACHUNK(maxburst); if (is_playback) - dev->playback.maxburst = 1 << (fls(channels) - 1); + dev->playback.maxburst = maxburst; else - dev->capture.maxburst = 1 << (fls(channels) - 1); + dev->capture.maxburst = maxburst; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -908,14 +936,14 @@ static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { .playback = { - .stream_name = "I2SMCC-Playback", + .stream_name = "Playback", .channels_min = 1, .channels_max = 8, .rates = MCHP_I2SMCC_RATES, .formats = MCHP_I2SMCC_FORMATS, }, .capture = { - .stream_name = "I2SMCC-Capture", + .stream_name = "Capture", .channels_min = 1, .channels_max = 8, .rates = MCHP_I2SMCC_RATES, @@ -1101,7 +1129,7 @@ static struct platform_driver mchp_i2s_mcc_driver = { .of_match_table = mchp_i2s_mcc_dt_ids, }, .probe = mchp_i2s_mcc_probe, - .remove_new = mchp_i2s_mcc_remove, + .remove = mchp_i2s_mcc_remove, }; module_platform_driver(mchp_i2s_mcc_driver); diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index dcc4e14b3dde..939cd44ebc8a 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -90,6 +90,15 @@ #define MCHP_PDMC_DS_NO 2 #define MCHP_PDMC_EDGE_NO 2 +/* + * ---- DMA chunk size allowed ---- + */ +#define MCHP_PDMC_DMA_8_WORD_CHUNK 8 +#define MCHP_PDMC_DMA_4_WORD_CHUNK 4 +#define MCHP_PDMC_DMA_2_WORD_CHUNK 2 +#define MCHP_PDMC_DMA_1_WORD_CHUNK 1 +#define DMA_BURST_ALIGNED(_p, _s, _w) !(_p % (_s * _w)) + struct mic_map { int ds_pos; int clk_edge; @@ -115,6 +124,7 @@ struct mchp_pdmc { int mic_no; int sinc_order; bool audio_filter_en; + atomic_t busy_stream; }; static const char *const mchp_pdmc_sinc_filter_order_text[] = { @@ -158,6 +168,10 @@ static int mchp_pdmc_sinc_order_put(struct snd_kcontrol *kcontrol, return -EINVAL; val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + if (atomic_read(&dd->busy_stream)) + return -EBUSY; + if (val == dd->sinc_order) return 0; @@ -184,6 +198,9 @@ static int mchp_pdmc_af_put(struct snd_kcontrol *kcontrol, struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component); bool af = uvalue->value.integer.value[0] ? true : false; + if (atomic_read(&dd->busy_stream)) + return -EBUSY; + if (dd->audio_filter_en == af) return 0; @@ -370,52 +387,10 @@ static const struct snd_kcontrol_new mchp_pdmc_snd_controls[] = { }, }; -static int mchp_pdmc_close(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - return snd_soc_add_component_controls(component, mchp_pdmc_snd_controls, - ARRAY_SIZE(mchp_pdmc_snd_controls)); -} - -static int mchp_pdmc_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - int i; - - /* remove controls that can't be changed at runtime */ - for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) { - const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i]; - struct snd_ctl_elem_id id; - int err; - - if (component->name_prefix) - snprintf(id.name, sizeof(id.name), "%s %s", component->name_prefix, - control->name); - else - strscpy(id.name, control->name, sizeof(id.name)); - - id.numid = 0; - id.iface = control->iface; - id.device = control->device; - id.subdevice = control->subdevice; - id.index = control->index; - err = snd_ctl_remove_id(component->card->snd_card, &id); - if (err < 0) - dev_err(component->dev, "%d: Failed to remove %s\n", err, - control->name); - } - - return 0; -} - static const struct snd_soc_component_driver mchp_pdmc_dai_component = { .name = "mchp-pdmc", .controls = mchp_pdmc_snd_controls, .num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls), - .open = &mchp_pdmc_open, - .close = &mchp_pdmc_close, - .legacy_dai_naming = 1, - .trigger_start = SND_SOC_TRIGGER_ORDER_LDC, }; static const unsigned int mchp_pdmc_1mic[] = {1}; @@ -511,15 +486,18 @@ static u32 mchp_pdmc_mr_set_osr(int audio_filter_en, unsigned int osr) return 0; } -static inline int mchp_pdmc_period_to_maxburst(int period_size) +static inline int mchp_pdmc_period_to_maxburst(int period_size, int sample_size) { - if (!(period_size % 8)) - return 8; - if (!(period_size % 4)) - return 4; - if (!(period_size % 2)) - return 2; - return 1; + int p_size = period_size; + int s_size = sample_size; + + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_8_WORD_CHUNK)) + return MCHP_PDMC_DMA_8_WORD_CHUNK; + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_4_WORD_CHUNK)) + return MCHP_PDMC_DMA_4_WORD_CHUNK; + if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_2_WORD_CHUNK)) + return MCHP_PDMC_DMA_2_WORD_CHUNK; + return MCHP_PDMC_DMA_1_WORD_CHUNK; } static struct snd_pcm_chmap_elem mchp_pdmc_std_chmaps[] = { @@ -547,14 +525,18 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); unsigned int osr = 0, osr_start; unsigned int fs = params_rate(params); + int sample_bytes = params_physical_width(params) / 8; + int period_bytes = params_period_size(params) * + params_channels(params) * sample_bytes; + int maxburst; u32 mr_val = 0; u32 cfgr_val = 0; int i; int ret; - dev_dbg(comp->dev, "%s() rate=%u format=%#x width=%u channels=%u\n", + dev_dbg(comp->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n", __func__, params_rate(params), params_format(params), - params_width(params), params_channels(params)); + params_width(params), params_channels(params), period_bytes); if (channels > dd->mic_no) { dev_err(comp->dev, "more channels %u than microphones %d\n", @@ -571,6 +553,11 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i); } + /* + * from these point forward, we consider the controller busy, so the + * audio filter and SINC order can't be changed + */ + atomic_set(&dd->busy_stream, 1); for (osr_start = dd->audio_filter_en ? 64 : 8; osr_start <= 256 && best_diff_rate; osr_start *= 2) { long round_rate; @@ -608,7 +595,8 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, mr_val |= FIELD_PREP(MCHP_PDMC_MR_SINCORDER_MASK, dd->sinc_order); - dd->addr.maxburst = mchp_pdmc_period_to_maxburst(snd_pcm_lib_period_bytes(substream)); + maxburst = mchp_pdmc_period_to_maxburst(period_bytes, sample_bytes); + dd->addr.maxburst = maxburst; mr_val |= FIELD_PREP(MCHP_PDMC_MR_CHUNK_MASK, dd->addr.maxburst); dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst); @@ -760,6 +748,7 @@ static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { }; static struct snd_soc_dai_driver mchp_pdmc_dai = { + .name = "mchp-pdmc", .capture = { .stream_name = "Capture", .channels_min = 1, @@ -1125,6 +1114,8 @@ static void mchp_pdmc_remove(struct platform_device *pdev) { struct mchp_pdmc *dd = platform_get_drvdata(pdev); + atomic_set(&dd->busy_stream, 0); + if (!pm_runtime_status_suspended(dd->dev)) mchp_pdmc_runtime_suspend(dd->dev); @@ -1153,7 +1144,7 @@ static struct platform_driver mchp_pdmc_driver = { .pm = pm_ptr(&mchp_pdmc_pm_ops), }, .probe = mchp_pdmc_probe, - .remove_new = mchp_pdmc_remove, + .remove = mchp_pdmc_remove, }; module_platform_driver(mchp_pdmc_driver); diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index 33ce5e54482b..b2507a1491b7 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -1194,7 +1194,7 @@ static void mchp_spdifrx_remove(struct platform_device *pdev) static struct platform_driver mchp_spdifrx_driver = { .probe = mchp_spdifrx_probe, - .remove_new = mchp_spdifrx_remove, + .remove = mchp_spdifrx_remove, .driver = { .name = "mchp_spdifrx", .of_match_table = mchp_spdifrx_dt_ids, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index a201a96fa690..4c60ea652896 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -888,7 +888,7 @@ static void mchp_spdiftx_remove(struct platform_device *pdev) static struct platform_driver mchp_spdiftx_driver = { .probe = mchp_spdiftx_probe, - .remove_new = mchp_spdiftx_remove, + .remove = mchp_spdiftx_remove, .driver = { .name = "mchp_spdiftx", .of_match_table = mchp_spdiftx_dt_ids, diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index d3ec9826d505..335e216ea7b4 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -207,7 +207,7 @@ static struct platform_driver at91sam9g20ek_audio_driver = { .of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids), }, .probe = at91sam9g20ek_audio_probe, - .remove_new = at91sam9g20ek_audio_remove, + .remove = at91sam9g20ek_audio_remove, }; module_platform_driver(at91sam9g20ek_audio_driver); diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index d1c1f370a9cd..1b5ef4e9d2b8 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -196,7 +196,7 @@ static struct platform_driver sam9x5_wm8731_driver = { .of_match_table = of_match_ptr(sam9x5_wm8731_of_match), }, .probe = sam9x5_wm8731_driver_probe, - .remove_new = sam9x5_wm8731_driver_remove, + .remove = sam9x5_wm8731_driver_remove, }; module_platform_driver(sam9x5_wm8731_driver); diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 5d208e0b4b90..0a9efd5f2861 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -431,7 +431,7 @@ static struct platform_driver tse850_driver = { .of_match_table = tse850_dt_ids, }, .probe = tse850_probe, - .remove_new = tse850_remove, + .remove = tse850_remove, }; module_platform_driver(tse850_driver); diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index b0e1a1253e10..f8ab936250dc 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -336,7 +336,7 @@ static struct platform_driver au1xac97c_driver = { .pm = AU1XPSCAC97_PMOPS, }, .probe = au1xac97c_drvprobe, - .remove_new = au1xac97c_drvremove, + .remove = au1xac97c_drvremove, }; module_platform_driver(au1xac97c_driver); diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 064406080d72..7d296f29dade 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -313,7 +313,7 @@ static struct platform_driver au1xi2s_driver = { .pm = AU1XI2SC_PMOPS, }, .probe = au1xi2s_drvprobe, - .remove_new = au1xi2s_drvremove, + .remove = au1xi2s_drvremove, }; module_platform_driver(au1xi2s_driver); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 1727eeb12b64..8a59a50978b9 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -486,7 +486,7 @@ static struct platform_driver au1xpsc_ac97_driver = { .pm = AU1XPSCAC97_PMOPS, }, .probe = au1xpsc_ac97_drvprobe, - .remove_new = au1xpsc_ac97_drvremove, + .remove = au1xpsc_ac97_drvremove, }; module_platform_driver(au1xpsc_ac97_driver); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 52734dec8247..bee013555e7a 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -404,7 +404,7 @@ static struct platform_driver au1xpsc_i2s_driver = { .pm = AU1XPSCI2S_PMOPS, }, .probe = au1xpsc_i2s_drvprobe, - .remove_new = au1xpsc_i2s_drvremove, + .remove = au1xpsc_i2s_drvremove, }; module_platform_driver(au1xpsc_i2s_driver); diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c index c64609718738..c47ed1e6ea2b 100644 --- a/sound/soc/bcm/bcm63xx-i2s-whistler.c +++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c @@ -293,7 +293,7 @@ static struct platform_driver bcm63xx_i2s_driver = { .of_match_table = of_match_ptr(snd_soc_bcm_audio_match), }, .probe = bcm63xx_i2s_dev_probe, - .remove_new = bcm63xx_i2s_dev_remove, + .remove = bcm63xx_i2s_dev_remove, }; module_platform_driver(bcm63xx_i2s_driver); diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 90088516fed0..e0ce0232eb1e 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1390,7 +1390,7 @@ MODULE_DEVICE_TABLE(of, cygnus_ssp_of_match); static struct platform_driver cygnus_ssp_driver = { .probe = cygnus_ssp_probe, - .remove_new = cygnus_ssp_remove, + .remove = cygnus_ssp_remove, .driver = { .name = "cygnus-ssp", .of_match_table = cygnus_ssp_of_match, diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 8bb67d7d2b4b..8dac754ddb0d 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -105,7 +105,7 @@ static struct platform_driver edb93xx_driver = { .name = "edb93xx-audio", }, .probe = edb93xx_probe, - .remove_new = edb93xx_remove, + .remove = edb93xx_remove, }; module_platform_driver(edb93xx_driver); diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 522de4b80293..d45862ceb0c9 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -523,7 +523,7 @@ MODULE_DEVICE_TABLE(of, ep93xx_i2s_of_ids); static struct platform_driver ep93xx_i2s_driver = { .probe = ep93xx_i2s_probe, - .remove_new = ep93xx_i2s_remove, + .remove = ep93xx_i2s_remove, .driver = { .name = "ep93xx-i2s", .of_match_table = ep93xx_i2s_of_ids, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b5e6d0a986c8..7092842480ef 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -157,6 +157,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_MC13783 imply SND_SOC_ML26124 imply SND_SOC_MT6351 + imply SND_SOC_MT6357 imply SND_SOC_MT6358 imply SND_SOC_MT6359 imply SND_SOC_MT6660 @@ -2501,6 +2502,12 @@ config SND_SOC_ML26124 config SND_SOC_MT6351 tristate "MediaTek MT6351 Codec" +config SND_SOC_MT6357 + tristate "MediaTek MT6357 Codec" + help + Enable support for the platform which uses MT6357 as + external codec device. + config SND_SOC_MT6358 tristate "MediaTek MT6358 Codec" help diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 622e360f0086..54cbc3feae32 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -177,6 +177,7 @@ snd-soc-ml26124-y := ml26124.o snd-soc-msm8916-analog-y := msm8916-wcd-analog.o snd-soc-msm8916-digital-y := msm8916-wcd-digital.o snd-soc-mt6351-y := mt6351.o +snd-soc-mt6357-y := mt6357.o snd-soc-mt6358-y := mt6358.o snd-soc-mt6359-y := mt6359.o snd-soc-mt6359-accdet-y := mt6359-accdet.o @@ -578,6 +579,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o +obj-$(CONFIG_SND_SOC_MT6357) += snd-soc-mt6357.o obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 551738abd1a5..de9e43185555 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv, /* Input 1 - 2 */ for (i = 0; i < 2; i++) { snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); - if (!of_get_property(np, prop, NULL)) + if (!of_property_read_bool(np, prop)) priv->ic |= 1 << i; } /* Output 1 - 6 */ for (i = 0; i < 6; i++) { snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); - if (!of_get_property(np, prop, NULL)) + if (!of_property_read_bool(np, prop)) priv->oc |= 1 << i; } diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c index 8169ec88a8ba..a6e8348a1bd5 100644 --- a/sound/soc/codecs/cs-amp-lib-test.c +++ b/sound/soc/codecs/cs-amp-lib-test.c @@ -515,6 +515,49 @@ static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); } +/* + * If an entry has a timestamp of 0 it should be ignored even if it has + * a matching target UID. + */ +static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test) +{ + struct cs_amp_lib_test_priv *priv = test->priv; + struct cirrus_amp_cal_data result_data; + u64 uid; + + cs_amp_lib_test_init_dummy_cal_blob(test, 8); + + /* Mark the 3rd entry invalid by zeroing calTime */ + priv->cal_blob->data[2].calTime[0] = 0; + priv->cal_blob->data[2].calTime[1] = 0; + + /* Get the UID value of the 3rd entry */ + uid = priv->cal_blob->data[2].calTarget[1]; + uid <<= 32; + uid |= priv->cal_blob->data[2].calTarget[0]; + + /* Redirect calls to get EFI data */ + kunit_activate_static_stub(test, + cs_amp_test_hooks->get_efi_variable, + cs_amp_lib_test_get_efi_variable); + + /* Lookup by UID should not find it */ + KUNIT_EXPECT_EQ(test, + cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, + uid, -1, + &result_data), + -ENOENT); + + /* Get by index should ignore it */ + KUNIT_EXPECT_EQ(test, + cs_amp_get_efi_calibration_data(&priv->amp_pdev.dev, + 0, 2, + &result_data), + -ENOENT); + + kunit_deactivate_static_stub(test, cs_amp_test_hooks->get_efi_variable); +} + static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = { .alg_id = 0x9f210, .mem_region = WMFW_ADSP2_YM, @@ -696,6 +739,7 @@ static struct kunit_case cs_amp_lib_test_cases[] = { cs_amp_lib_test_get_cal_gen_params), KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test, cs_amp_lib_test_get_cal_gen_params), + KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test), /* Tests for writing calibration data */ KUNIT_CASE(cs_amp_lib_test_write_cal_data_test), diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index bd74fef33d49..e45e9ae01bc6 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -451,32 +451,23 @@ static const struct reg_sequence cs35l56_hibernate_seq[] = { REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE), }; -static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), -}; - static void cs35l56_issue_wake_event(struct cs35l56_base *cs35l56_base) { + unsigned int val; + /* * Dummy transactions to trigger I2C/SPI auto-wake. Issue two * transactions to meet the minimum required time from the rising edge * to the last falling edge of wake. * - * It uses bypassed write because we must wake the chip before + * It uses bypassed read because we must wake the chip before * disabling regmap cache-only. - * - * This can NAK on I2C which will terminate the write sequence so the - * single-write sequence is issued twice. */ - regmap_multi_reg_write_bypassed(cs35l56_base->regmap, - cs35l56_hibernate_wake_seq, - ARRAY_SIZE(cs35l56_hibernate_wake_seq)); + regmap_read_bypassed(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); usleep_range(CS35L56_WAKE_HOLD_TIME_US, 2 * CS35L56_WAKE_HOLD_TIME_US); - regmap_multi_reg_write_bypassed(cs35l56_base->regmap, - cs35l56_hibernate_wake_seq, - ARRAY_SIZE(cs35l56_hibernate_wake_seq)); + regmap_read_bypassed(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); cs35l56_wait_control_port_ready(); } @@ -925,7 +916,7 @@ const unsigned int cs35l56_tx_input_values[] = { }; EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED); -struct regmap_config cs35l56_regmap_i2c = { +const struct regmap_config cs35l56_regmap_i2c = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -941,7 +932,7 @@ struct regmap_config cs35l56_regmap_i2c = { }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); -struct regmap_config cs35l56_regmap_spi = { +const struct regmap_config cs35l56_regmap_spi = { .reg_bits = 32, .val_bits = 32, .pad_bits = 16, @@ -958,7 +949,7 @@ struct regmap_config cs35l56_regmap_spi = { }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); -struct regmap_config cs35l56_regmap_sdw = { +const struct regmap_config cs35l56_regmap_sdw = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index 94a66a325303..29891c1f6bec 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -323,15 +323,15 @@ static int cs42l42_sdw_read_prop(struct sdw_slave *peripheral) prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; /* DP1 - capture */ - ports[0].num = CS42L42_SDW_CAPTURE_PORT, - ports[0].type = SDW_DPN_FULL, - ports[0].ch_prep_timeout = 10, + ports[0].num = CS42L42_SDW_CAPTURE_PORT; + ports[0].type = SDW_DPN_FULL; + ports[0].ch_prep_timeout = 10; prop->src_dpn_prop = &ports[0]; /* DP2 - playback */ - ports[1].num = CS42L42_SDW_PLAYBACK_PORT, - ports[1].type = SDW_DPN_FULL, - ports[1].ch_prep_timeout = 10, + ports[1].num = CS42L42_SDW_PLAYBACK_PORT; + ports[1].type = SDW_DPN_FULL; + ports[1].ch_prep_timeout = 10; prop->sink_dpn_prop = &ports[1]; return 0; diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 5183b4586424..d0098b4558b5 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2461,7 +2461,7 @@ static struct platform_driver cs42l43_codec_driver = { }, .probe = cs42l43_codec_probe, - .remove_new = cs42l43_codec_remove, + .remove = cs42l43_codec_remove, .id_table = cs42l43_codec_id_table, }; module_platform_driver(cs42l43_codec_driver); diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index be4037890fdb..f8e2fb69ada2 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -1415,7 +1415,7 @@ static const char * const bypass_mux_text[] = { static SOC_ENUM_SINGLE_DECL(bypass_enum, SND_SOC_NOPM, 0, bypass_mux_text); static const struct snd_kcontrol_new bypass_ctrl = SOC_DAPM_ENUM("Switch", bypass_enum); -static const struct snd_soc_dapm_widget digital_hp_widgets[] = { +static const struct snd_soc_dapm_widget hp_widgets[] = { SND_SOC_DAPM_MUX("Bypass Switch", SND_SOC_NOPM, 0, 0, &bypass_ctrl), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -1447,19 +1447,16 @@ static const struct snd_soc_dapm_widget digital_hp_widgets[] = { CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event, (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD)), -}; -static const struct snd_soc_dapm_widget analog_hp_widgets[] = { +/* Some devices have some extra analog widgets */ +#define NUM_ANALOG_WIDGETS 1 + SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1, CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event, (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)), }; -static struct snd_soc_dapm_widget all_hp_widgets[ - ARRAY_SIZE(digital_hp_widgets) + - ARRAY_SIZE(analog_hp_widgets)]; - -static const struct snd_soc_dapm_route digital_hp_routes[] = { +static const struct snd_soc_dapm_route hp_routes[] = { {"ASPIN PCM", NULL, "ASP PCM Playback"}, {"ASPIN DoP", NULL, "ASP DoP Playback"}, {"XSPIN DoP", NULL, "XSP DoP Playback"}, @@ -1472,15 +1469,12 @@ static const struct snd_soc_dapm_route digital_hp_routes[] = { {"Bypass Switch", "Internal", "HiFi DAC"}, {"HPOUTA", NULL, "Bypass Switch"}, {"HPOUTB", NULL, "Bypass Switch"}, -}; -static const struct snd_soc_dapm_route analog_hp_routes[] = { +/* Some devices have some extra analog routes */ +#define NUM_ANALOG_ROUTES 1 {"Bypass Switch", "Alternative", "Analog Playback"}, }; -static struct snd_soc_dapm_route all_hp_routes[ - ARRAY_SIZE(digital_hp_routes) + - ARRAY_SIZE(analog_hp_routes)]; static const unsigned int cs43130_asp_src_rates[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 @@ -1811,7 +1805,7 @@ static struct attribute *hpload_attrs[] = { }; ATTRIBUTE_GROUPS(hpload); -static struct reg_sequence hp_en_cal_seq[] = { +static const struct reg_sequence hp_en_cal_seq[] = { {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, {CS43130_HP_MEAS_LOAD_1, 0}, {CS43130_HP_MEAS_LOAD_2, 0}, @@ -1826,7 +1820,7 @@ static struct reg_sequence hp_en_cal_seq[] = { {CS43130_HP_LOAD_1, 0x80}, }; -static struct reg_sequence hp_en_cal_seq2[] = { +static const struct reg_sequence hp_en_cal_seq2[] = { {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, {CS43130_HP_MEAS_LOAD_1, 0}, {CS43130_HP_MEAS_LOAD_2, 0}, @@ -1834,7 +1828,7 @@ static struct reg_sequence hp_en_cal_seq2[] = { {CS43130_HP_LOAD_1, 0x80}, }; -static struct reg_sequence hp_dis_cal_seq[] = { +static const struct reg_sequence hp_dis_cal_seq[] = { {CS43130_HP_LOAD_1, 0x80}, {CS43130_DXD1, 0x99}, {CS43130_DXD12, 0}, @@ -1842,12 +1836,12 @@ static struct reg_sequence hp_dis_cal_seq[] = { {CS43130_HP_LOAD_1, 0}, }; -static struct reg_sequence hp_dis_cal_seq2[] = { +static const struct reg_sequence hp_dis_cal_seq2[] = { {CS43130_HP_LOAD_1, 0x80}, {CS43130_HP_LOAD_1, 0}, }; -static struct reg_sequence hp_dc_ch_l_seq[] = { +static const struct reg_sequence hp_dc_ch_l_seq[] = { {CS43130_DXD1, 0x99}, {CS43130_DXD19, 0x0A}, {CS43130_DXD17, 0x93}, @@ -1857,12 +1851,12 @@ static struct reg_sequence hp_dc_ch_l_seq[] = { {CS43130_HP_LOAD_1, 0x81}, }; -static struct reg_sequence hp_dc_ch_l_seq2[] = { +static const struct reg_sequence hp_dc_ch_l_seq2[] = { {CS43130_HP_LOAD_1, 0x80}, {CS43130_HP_LOAD_1, 0x81}, }; -static struct reg_sequence hp_dc_ch_r_seq[] = { +static const struct reg_sequence hp_dc_ch_r_seq[] = { {CS43130_DXD1, 0x99}, {CS43130_DXD19, 0x8A}, {CS43130_DXD17, 0x15}, @@ -1872,12 +1866,12 @@ static struct reg_sequence hp_dc_ch_r_seq[] = { {CS43130_HP_LOAD_1, 0x91}, }; -static struct reg_sequence hp_dc_ch_r_seq2[] = { +static const struct reg_sequence hp_dc_ch_r_seq2[] = { {CS43130_HP_LOAD_1, 0x90}, {CS43130_HP_LOAD_1, 0x91}, }; -static struct reg_sequence hp_ac_ch_l_seq[] = { +static const struct reg_sequence hp_ac_ch_l_seq[] = { {CS43130_DXD1, 0x99}, {CS43130_DXD19, 0x0A}, {CS43130_DXD17, 0x93}, @@ -1887,12 +1881,12 @@ static struct reg_sequence hp_ac_ch_l_seq[] = { {CS43130_HP_LOAD_1, 0x82}, }; -static struct reg_sequence hp_ac_ch_l_seq2[] = { +static const struct reg_sequence hp_ac_ch_l_seq2[] = { {CS43130_HP_LOAD_1, 0x80}, {CS43130_HP_LOAD_1, 0x82}, }; -static struct reg_sequence hp_ac_ch_r_seq[] = { +static const struct reg_sequence hp_ac_ch_r_seq[] = { {CS43130_DXD1, 0x99}, {CS43130_DXD19, 0x8A}, {CS43130_DXD17, 0x15}, @@ -1902,24 +1896,24 @@ static struct reg_sequence hp_ac_ch_r_seq[] = { {CS43130_HP_LOAD_1, 0x92}, }; -static struct reg_sequence hp_ac_ch_r_seq2[] = { +static const struct reg_sequence hp_ac_ch_r_seq2[] = { {CS43130_HP_LOAD_1, 0x90}, {CS43130_HP_LOAD_1, 0x92}, }; -static struct reg_sequence hp_cln_seq[] = { +static const struct reg_sequence hp_cln_seq[] = { {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, {CS43130_HP_MEAS_LOAD_1, 0}, {CS43130_HP_MEAS_LOAD_2, 0}, }; struct reg_sequences { - struct reg_sequence *seq; - int size; - unsigned int msk; + const struct reg_sequence *seq; + int size; + unsigned int msk; }; -static struct reg_sequences hpload_seq1[] = { +static const struct reg_sequences hpload_seq1[] = { { .seq = hp_en_cal_seq, .size = ARRAY_SIZE(hp_en_cal_seq), @@ -1957,7 +1951,7 @@ static struct reg_sequences hpload_seq1[] = { }, }; -static struct reg_sequences hpload_seq2[] = { +static const struct reg_sequences hpload_seq2[] = { { .seq = hp_en_cal_seq2, .size = ARRAY_SIZE(hp_en_cal_seq2), @@ -2047,7 +2041,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, } static int cs43130_hpload_proc(struct cs43130_private *cs43130, - struct reg_sequence *seq, int seq_size, + const struct reg_sequence *seq, int seq_size, unsigned int rslt_msk, int ac_idx) { int ret; @@ -2128,7 +2122,7 @@ static void cs43130_imp_meas(struct work_struct *wk) int i, ret, ac_idx; struct cs43130_private *cs43130; struct snd_soc_component *component; - struct reg_sequences *hpload_seq; + const struct reg_sequences *hpload_seq; cs43130 = container_of(wk, struct cs43130_private, work); component = cs43130->component; @@ -2398,7 +2392,7 @@ static int cs43130_probe(struct snd_soc_component *component) return 0; } -static struct snd_soc_component_driver soc_component_dev_cs43130 = { +static const struct snd_soc_component_driver soc_component_dev_cs43130_digital = { .probe = cs43130_probe, .controls = cs43130_snd_controls, .num_controls = ARRAY_SIZE(cs43130_snd_controls), @@ -2407,6 +2401,26 @@ static struct snd_soc_component_driver soc_component_dev_cs43130 = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, + /* Don't take into account the ending analog widgets and routes */ + .dapm_widgets = hp_widgets, + .num_dapm_widgets = ARRAY_SIZE(hp_widgets) - NUM_ANALOG_WIDGETS, + .dapm_routes = hp_routes, + .num_dapm_routes = ARRAY_SIZE(hp_routes) - NUM_ANALOG_ROUTES, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs43130_analog = { + .probe = cs43130_probe, + .controls = cs43130_snd_controls, + .num_controls = ARRAY_SIZE(cs43130_snd_controls), + .set_sysclk = cs43130_component_set_sysclk, + .set_pll = cs43130_set_pll, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .dapm_widgets = hp_widgets, + .num_dapm_widgets = ARRAY_SIZE(hp_widgets), + .dapm_routes = hp_routes, + .num_dapm_routes = ARRAY_SIZE(hp_routes), }; static const struct regmap_config cs43130_regmap = { @@ -2479,6 +2493,7 @@ static int cs43130_handle_device_data(struct cs43130_private *cs43130) static int cs43130_i2c_probe(struct i2c_client *client) { + const struct snd_soc_component_driver *component_driver; struct cs43130_private *cs43130; int ret; unsigned int reg; @@ -2596,39 +2611,15 @@ static int cs43130_i2c_probe(struct i2c_client *client) switch (cs43130->dev_id) { case CS43130_CHIP_ID: case CS43131_CHIP_ID: - memcpy(all_hp_widgets, digital_hp_widgets, - sizeof(digital_hp_widgets)); - memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets), - analog_hp_widgets, sizeof(analog_hp_widgets)); - memcpy(all_hp_routes, digital_hp_routes, - sizeof(digital_hp_routes)); - memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes), - analog_hp_routes, sizeof(analog_hp_routes)); - - soc_component_dev_cs43130.dapm_widgets = - all_hp_widgets; - soc_component_dev_cs43130.num_dapm_widgets = - ARRAY_SIZE(all_hp_widgets); - soc_component_dev_cs43130.dapm_routes = - all_hp_routes; - soc_component_dev_cs43130.num_dapm_routes = - ARRAY_SIZE(all_hp_routes); + component_driver = &soc_component_dev_cs43130_analog; break; case CS43198_CHIP_ID: case CS4399_CHIP_ID: - soc_component_dev_cs43130.dapm_widgets = - digital_hp_widgets; - soc_component_dev_cs43130.num_dapm_widgets = - ARRAY_SIZE(digital_hp_widgets); - soc_component_dev_cs43130.dapm_routes = - digital_hp_routes; - soc_component_dev_cs43130.num_dapm_routes = - ARRAY_SIZE(digital_hp_routes); + component_driver = &soc_component_dev_cs43130_digital; break; } - ret = devm_snd_soc_register_component(cs43130->dev, - &soc_component_dev_cs43130, + ret = devm_snd_soc_register_component(cs43130->dev, component_driver, cs43130_dai, ARRAY_SIZE(cs43130_dai)); if (ret < 0) { dev_err(cs43130->dev, diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index ab6e7cd99733..29a2bcfb3048 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1493,7 +1493,7 @@ static struct platform_driver cs47l15_codec_driver = { .name = "cs47l15-codec", }, .probe = &cs47l15_probe, - .remove_new = cs47l15_remove, + .remove = cs47l15_remove, }; module_platform_driver(cs47l15_codec_driver); diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index ec405ef66a8e..e2a839fae4fc 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1344,7 +1344,7 @@ static struct platform_driver cs47l24_codec_driver = { .name = "cs47l24-codec", }, .probe = cs47l24_probe, - .remove_new = cs47l24_remove, + .remove = cs47l24_remove, }; module_platform_driver(cs47l24_codec_driver); diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index 0d7ee7ea6257..85555c7a2e4b 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1769,7 +1769,7 @@ static struct platform_driver cs47l35_codec_driver = { .name = "cs47l35-codec", }, .probe = &cs47l35_probe, - .remove_new = cs47l35_remove, + .remove = cs47l35_remove, }; module_platform_driver(cs47l35_codec_driver); diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index 2dfb867e6edd..d34f4e8c26d3 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2720,7 +2720,7 @@ static struct platform_driver cs47l85_codec_driver = { .name = "cs47l85-codec", }, .probe = &cs47l85_probe, - .remove_new = cs47l85_remove, + .remove = cs47l85_remove, }; module_platform_driver(cs47l85_codec_driver); diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 2549cb1fc121..a9e703981f37 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2644,7 +2644,7 @@ static struct platform_driver cs47l90_codec_driver = { .name = "cs47l90-codec", }, .probe = &cs47l90_probe, - .remove_new = cs47l90_remove, + .remove = cs47l90_remove, }; module_platform_driver(cs47l90_codec_driver); diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 0c05ae0b09fb..2c355c61acd8 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -2092,7 +2092,7 @@ static struct platform_driver cs47l92_codec_driver = { .name = "cs47l92-codec", }, .probe = &cs47l92_probe, - .remove_new = cs47l92_remove, + .remove = cs47l92_remove, }; module_platform_driver(cs47l92_codec_driver); diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index be3c79232a31..d5362b3be484 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -805,6 +805,7 @@ static void es8326_jack_button_handler(struct work_struct *work) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); button_to_report = 0; } + es8326_disable_micbias(es8326->component); } mutex_unlock(&es8326->lock); } @@ -880,7 +881,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x00); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x00); - es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x10); @@ -899,6 +899,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) dev_dbg(comp->dev, "button pressed\n"); regmap_write(es8326->regmap, ES8326_INT_SOURCE, (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + es8326_enable_micbias(es8326->component); queue_delayed_work(system_wq, &es8326->button_press_work, 10); goto exit; } @@ -1069,6 +1070,9 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f); regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); + es8326_disable_micbias(es8326->component); msleep(200); regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 11320423c69c..fdd19f8e8864 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -476,7 +476,7 @@ static struct platform_driver rk3036_codec_platform_driver = { .of_match_table = of_match_ptr(rk3036_codec_of_match), }, .probe = rk3036_codec_platform_probe, - .remove_new = rk3036_codec_platform_remove, + .remove = rk3036_codec_platform_remove, }; module_platform_driver(rk3036_codec_platform_driver); diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index ce42749660c8..71e0d3bffd3f 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -4024,7 +4024,7 @@ static struct platform_driver rx_macro_driver = { .pm = &rx_macro_pm_ops, }, .probe = rx_macro_probe, - .remove_new = rx_macro_remove, + .remove = rx_macro_remove, }; module_platform_driver(rx_macro_driver); diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 209c12ec16dd..a134584acf90 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -2534,7 +2534,7 @@ static struct platform_driver tx_macro_driver = { .pm = &tx_macro_pm_ops, }, .probe = tx_macro_probe, - .remove_new = tx_macro_remove, + .remove = tx_macro_remove, }; module_platform_driver(tx_macro_driver); diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index e95d1f29ef18..c781da476240 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1738,7 +1738,7 @@ static struct platform_driver va_macro_driver = { .pm = &va_macro_pm_ops, }, .probe = va_macro_probe, - .remove_new = va_macro_remove, + .remove = va_macro_remove, }; module_platform_driver(va_macro_driver); diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 73a588289408..c989d82d1d3c 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2297,36 +2297,37 @@ static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); u32 enable = ucontrol->value.integer.value[0]; u32 spk_tx_id = mixer->shift; + u32 dai_id = widget->shift; if (enable) { if (spk_tx_id == WSA_MACRO_TX0 && !test_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { set_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]++; } if (spk_tx_id == WSA_MACRO_TX1 && !test_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { set_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]++; } } else { if (spk_tx_id == WSA_MACRO_TX0 && test_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { clear_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]--; } if (spk_tx_id == WSA_MACRO_TX1 && test_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { clear_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]--; } } snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); @@ -2979,7 +2980,7 @@ static struct platform_driver wsa_macro_driver = { .pm = &wsa_macro_pm_ops, }, .probe = wsa_macro_probe, - .remove_new = wsa_macro_remove, + .remove = wsa_macro_remove, }; module_platform_driver(wsa_macro_driver); diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 978c4d056e81..ebb6f2e84818 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1241,7 +1241,7 @@ static struct platform_driver msm8916_wcd_digital_driver = { .of_match_table = msm8916_wcd_digital_match_table, }, .probe = msm8916_wcd_digital_probe, - .remove_new = msm8916_wcd_digital_remove, + .remove = msm8916_wcd_digital_remove, }; module_platform_driver(msm8916_wcd_digital_driver); diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c new file mode 100644 index 000000000000..988728df15e4 --- /dev/null +++ b/sound/soc/codecs/mt6357.c @@ -0,0 +1,1855 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MT6357 ALSA SoC audio codec driver + * + * Copyright (c) 2024 Baylibre + * Author: Nicolas Belin + */ + +#include +#include +#include +#include +#include + +#include "mt6357.h" + +static void set_playback_gpio(struct mt6357_priv *priv, bool enable) +{ + regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, MT6357_GPIO_MODE2_CLEAR_ALL); + if (enable) { + /* set gpio mosi mode */ + regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, + MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI | + MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 | + MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 | + MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI); + } else { + /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input + * reason: + * pad_aud_dat_mosi*, because the pin is used as boot strap + */ + regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, + MT6357_GPIO8_DIR_MASK | + MT6357_GPIO9_DIR_MASK | + MT6357_GPIO10_DIR_MASK | + MT6357_GPIO11_DIR_MASK, + MT6357_GPIO8_DIR_INPUT | + MT6357_GPIO9_DIR_INPUT | + MT6357_GPIO10_DIR_INPUT | + MT6357_GPIO11_DIR_INPUT); + } +} + +static void set_capture_gpio(struct mt6357_priv *priv, bool enable) +{ + regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, MT6357_GPIO_MODE3_CLEAR_ALL); + if (enable) { + /* set gpio miso mode */ + regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET, + MT6357_GPIO12_MODE_SET_AUD_CLK_MISO | + MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 | + MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 | + MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO); + } else { + /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input + * reason: + * pad_aud_clk_miso, because when playback only the miso_clk + * will also have 26m, so will have power leak + * pad_aud_dat_miso*, because the pin is used as boot strap + */ + regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, + MT6357_GPIO12_DIR_MASK | + MT6357_GPIO13_DIR_MASK | + MT6357_GPIO14_DIR_MASK | + MT6357_GPIO15_DIR_MASK, + MT6357_GPIO12_DIR_INPUT | + MT6357_GPIO13_DIR_INPUT | + MT6357_GPIO14_DIR_INPUT | + MT6357_GPIO15_DIR_INPUT); + } +} + +static void hp_main_output_ramp(struct mt6357_priv *priv, bool up) +{ + int i, stage; + + /* Enable/Reduce HPL/R main output stage step by step */ + for (i = 0; i <= MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX; i++) { + stage = up ? i : MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX - i; + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK, + stage << MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT); + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_STG_CTRL_VAUDP15_MASK, + stage << MT6357_HPROUT_STG_CTRL_VAUDP15_SFT); + usleep_range(600, 700); + } +} + +static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up) +{ + int i, stage; + + /* Reduce HP aux feedback loop gain step by step */ + for (i = 0; i <= MT6357_HP_AUX_LOOP_GAIN_MAX; i++) { + stage = up ? i : MT6357_HP_AUX_LOOP_GAIN_MAX - i; + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HP_AUX_LOOP_GAIN_MASK, + stage << MT6357_HP_AUX_LOOP_GAIN_SFT); + usleep_range(600, 700); + } +} + +static void hp_pull_down(struct mt6357_priv *priv, bool enable) +{ + if (enable) + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, + MT6357_HPP_SHORT_2VCM_VAUDP15_MASK, + MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE); + else + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, + MT6357_HPP_SHORT_2VCM_VAUDP15_MASK, + MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE); +} + +static bool is_valid_hp_pga_idx(int reg_idx) +{ + return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB; +} + +static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, + int rfrom, int rto, unsigned int reg_addr) +{ + int lcount, rcount, sleep = 0; + + if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto)) + pr_debug("%s(), invalid left volume index, from %d, to %d\n", + __func__, lfrom, lto); + + if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto)) + pr_debug("%s(), invalid right volume index, from %d, to %d\n", + __func__, rfrom, rto); + + if (lto > lfrom) + lcount = 1; + else + lcount = -1; + + if (rto > rfrom) + rcount = 1; + else + rcount = -1; + + while ((lto != lfrom) || (rto != rfrom)) { + if (lto != lfrom) { + lfrom += lcount; + if (is_valid_hp_pga_idx(lfrom)) { + regmap_update_bits(priv->regmap, reg_addr, + MT6357_DL_GAIN_REG_LEFT_MASK, + lfrom << MT6357_DL_GAIN_REG_LEFT_SHIFT); + sleep = 1; + } + } + if (rto != rfrom) { + rfrom += rcount; + if (is_valid_hp_pga_idx(rfrom)) { + regmap_update_bits(priv->regmap, reg_addr, + MT6357_DL_GAIN_REG_RIGHT_MASK, + rfrom << MT6357_DL_GAIN_REG_RIGHT_SHIFT); + sleep = 1; + } + } + if (sleep) + usleep_range(200, 300); + } +} + +static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto) +{ + volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1); +} + +static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto) +{ + volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2); +} + +static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to) +{ + volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3); +} + +/* Volume and channel swap controls */ +static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); +static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(hp_degain_tlv, -1200, 1200, 0); + +static const struct snd_kcontrol_new mt6357_controls[] = { + /* dl pga gain */ + SOC_DOUBLE_TLV("Headphone Volume", + MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_SFT, + MT6357_AUD_HPR_GAIN_SFT, MT6357_AUD_HP_GAIN_MAX, + 1, playback_tlv), + SOC_SINGLE_TLV("Headphone Vin Volume", + MT6357_AUDDEC_ANA_CON7, MT6357_HP_IVBUF_DEGAIN_SFT, + MT6357_HP_IVBUF_DEGAIN_MAX, 1, hp_degain_tlv), + SOC_DOUBLE_TLV("Lineout Volume", + MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_SFT, + MT6357_AUD_LOR_GAIN_SFT, MT6357_AUD_LO_GAIN_MAX, + 1, playback_tlv), + SOC_SINGLE_TLV("Handset Volume", + MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_SFT, + MT6357_AUD_HS_GAIN_MAX, 1, playback_tlv), + /* ul pga gain */ + SOC_DOUBLE_R_TLV("Mic Volume", + MT6357_AUDENC_ANA_CON0, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPLGAIN_SFT, MT6357_AUDPREAMPLGAIN_MAX, + 0, capture_tlv), +}; + +/* Uplink controls */ + +enum { + MIC_TYPE_MUX_IDLE, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, + MIC_TYPE_MUX_LPBK, + MIC_TYPE_MUX_SGEN, +}; + +#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \ + (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ + (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) + +static const char * const mic_type_mux_map[] = { + "Idle", + "ACC", + "DMIC", + "DCC", + "DCC_ECM_DIFF", + "DCC_ECM_SINGLE", + "Loopback", + "Sine Generator", +}; + +static SOC_ENUM_SINGLE_DECL(mic_type_mux_map_enum, SND_SOC_NOPM, + 0, mic_type_mux_map); + +static const struct snd_kcontrol_new mic_type_mux_control = + SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum); + +static const char * const pga_mux_map[] = { + "None", "AIN0", "AIN1", "AIN2" +}; + +static SOC_ENUM_SINGLE_DECL(pga_left_mux_map_enum, + MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLINPUTSEL_SFT, + pga_mux_map); + +static const struct snd_kcontrol_new pga_left_mux_control = + SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum); + +static SOC_ENUM_SINGLE_DECL(pga_right_mux_map_enum, + MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRINPUTSEL_SFT, + pga_mux_map); + +static const struct snd_kcontrol_new pga_right_mux_control = + SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum); + +/* Downlink controls */ +static const char * const hslo_mux_map[] = { + "Open", "DACR", "Playback", "Test mode" +}; + +static SOC_ENUM_SINGLE_DECL(lo_mux_map_enum, + MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT, + hslo_mux_map); + +static const struct snd_kcontrol_new lo_mux_control = + SOC_DAPM_ENUM("Line out source", lo_mux_map_enum); + +static SOC_ENUM_SINGLE_DECL(hs_mux_map_enum, + MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT, + hslo_mux_map); + +static const struct snd_kcontrol_new hs_mux_control = + SOC_DAPM_ENUM("Handset source", hs_mux_map_enum); + +static const char * const hplr_mux_map[] = { + "Open", "Line Out", "DAC", "Handset" +}; + +static SOC_ENUM_SINGLE_DECL(hpr_mux_map_enum, + MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT, + hplr_mux_map); + +static const struct snd_kcontrol_new hpr_mux_control = + SOC_DAPM_ENUM("Headphone Right source", hpr_mux_map_enum); + +static SOC_ENUM_SINGLE_DECL(hpl_mux_map_enum, + MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT, + hplr_mux_map); + +static const struct snd_kcontrol_new hpl_mux_control = + SOC_DAPM_ENUM("Headphone Left source", hpl_mux_map_enum); + +static const char * const dac_mux_map[] = { + "Normal Path", "Sine Generator" +}; + +static SOC_ENUM_SINGLE_DECL(dac_mux_map_enum, + MT6357_AFE_TOP_CON0, + MT6357_DL_SINE_ON_SFT, + dac_mux_map); + +static const struct snd_kcontrol_new dac_mux_control = + SOC_DAPM_ENUM("DAC Select", dac_mux_map_enum); + +static int mt6357_set_dmic(struct mt6357_priv *priv, bool enable) +{ + if (enable) { + /* DMIC enable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7, + MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK, + MT6357_AUDDIGMICBIAS_DEFAULT_VALUE | MT6357_AUDDIGMICEN_ENABLE); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); + /* UL dmic setting: dual mode */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H, + MT6357_C_TWO_DIGITAL_MIC_CTL_MASK, + MT6357_C_TWO_DIGITAL_MIC_ENABLE); + /* UL turn on SDM 3 level mode */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SDM_3_LEVEL_CTL_MASK, + MT6357_UL_SDM_3_LEVEL_SELECT); + /* UL turn on */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_ENABLE); + /* Wait to avoid any pop noises */ + msleep(100); + } else { + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_DISABLE); + /* UL turn on SDM 3 level mode */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SDM_3_LEVEL_CTL_MASK, + MT6357_UL_SDM_3_LEVEL_DESELECT); + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); + /* UL dmic setting: dual mode */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H, + MT6357_C_TWO_DIGITAL_MIC_CTL_MASK, + MT6357_C_TWO_DIGITAL_MIC_DISABLE); + /* DMIC disable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7, + MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK, + MT6357_AUDDIGMICBIAS_OFF | MT6357_AUDDIGMICEN_DISABLE); + } + return 0; +} + +static int mt6357_set_amic(struct mt6357_priv *priv, bool enable, unsigned int mic_type) +{ + if (enable) { + if (IS_DCC_BASE(mic_type)) { + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_RUN_VALUE); + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_OUTPUT); + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_ON); + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG1, + MT6357_DCCLK_RESYNC_BYPASS_MASK, + MT6357_DCCLK_RESYNC_BYPASS); + + /* mic bias 0: set the correct DC couple*/ + switch (mic_type) { + case MIC_TYPE_MUX_DCC_ECM_DIFF: + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_DC_MASK, + MT6357_AUD_MICBIAS0_DC_ENABLE_ALL); + break; + case MIC_TYPE_MUX_DCC_ECM_SINGLE: + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_DC_MASK, + MT6357_AUD_MICBIAS0_DC_ENABLE_P1); + break; + default: + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_DC_MASK, + MT6357_AUD_MICBIAS0_DC_DISABLE_ALL); + break; + } + + /* mic bias 1: set the correct DC couple */ + if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE) + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, + MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK, + MT6357_AUD_MICBIAS1_DCSW1P_ENABLE); + + /* Audio L/R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCPRECHARGE_MASK, + MT6357_AUDPREAMPLDCPRECHARGE_ENABLE); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCPRECHARGE_MASK, + MT6357_AUDPREAMPRDCPRECHARGE_ENABLE); + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCCEN_MASK, + MT6357_AUDPREAMPLDCCEN_DC); + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCCEN_MASK, + MT6357_AUDPREAMPRDCCEN_DC); + } else { + /* Audio L preamplifier DCC precharge disable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCPRECHARGE_MASK, + MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); + /* L preamplifier ACC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCCEN_MASK, + MT6357_AUDPREAMPLDCCEN_AC); + /* Audio R preamplifier DCC precharge disable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCPRECHARGE_MASK, + MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); + /* R preamplifier ACC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCCEN_MASK, + MT6357_AUDPREAMPRDCCEN_AC); + } + } else { + /* disable any Mic Bias 0 DC couple */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_DC_MASK, + MT6357_AUD_MICBIAS0_DC_DISABLE_ALL); + /* disable any Mic Bias 1 DC couple */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, + MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK, + MT6357_AUD_MICBIAS1_DCSW1P_DISABLE); + if (IS_DCC_BASE(mic_type)) { + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_OFF); + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_PDN); + regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, + MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_STOP_VALUE); + } + } + + return 0; +} + +static int mt6357_set_loopback(struct mt6357_priv *priv, bool enable) +{ + if (enable) { + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); + /* enable aud_pad lpk TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_LPBK_MASK, + MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE); + /* Set UL Part: enable new lpbk 2 */ + regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0, + MT6357_ADDA_MTKAIF_LPBK_CTL_MASK, + MT6357_ADDA_MTKAIF_LPBK_ENABLE); + /* UL turn on */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_ENABLE); + } else { + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_DISABLE); + /* disable new lpbk 2 */ + regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0, + MT6357_ADDA_MTKAIF_LPBK_CTL_MASK, + MT6357_ADDA_MTKAIF_LPBK_DISABLE); + /* disable aud_pad lpbk TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_LPBK_MASK, + MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE); + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); + } + + return 0; +} + +static int mt6357_set_ul_sine_gen(struct mt6357_priv *priv, bool enable) +{ + if (enable) { + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); + /* UL turn on */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_ENABLE); + } else { + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, + MT6357_UL_SRC_DISABLE); + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); + } + + return 0; +} + +static int mt_aif_out_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_capture_gpio(priv, true); + break; + case SND_SOC_DAPM_POST_PMD: + set_capture_gpio(priv, false); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_supply_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, + MT6357_RSTB_ENCODER_VA28_MASK, MT6357_RSTB_ENCODER_VA28_ENABLE); + /* Enable LCLDO_ENC 2P8V */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_LCLDO_ENC_EN_VA28_MASK, MT6357_LCLDO_ENC_EN_VA28_ENABLE); + /* LCLDO_ENC remote sense */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_VA28REFGEN_EN_VA28_MASK | + MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK, + MT6357_VA28REFGEN_EN_VA28_ENABLE | + MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* LCLDO_ENC remote sense off */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_VA28REFGEN_EN_VA28_MASK | + MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK, + MT6357_VA28REFGEN_EN_VA28_DISABLE | + MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE); + /* disable LCLDO_ENC 2P8V */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_LCLDO_ENC_EN_VA28_MASK, + MT6357_LCLDO_ENC_EN_VA28_DISABLE); + /* disable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, + MT6357_RSTB_ENCODER_VA28_MASK, + MT6357_RSTB_ENCODER_VA28_DISABLE); + break; + default: + break; + } + + return 0; +} + +static int mt_mic_type_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mic_type = dapm_kcontrol_get_value(w->kcontrols[0]); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mic_type) { + case MIC_TYPE_MUX_DMIC: + mt6357_set_dmic(priv, true); + break; + case MIC_TYPE_MUX_LPBK: + mt6357_set_loopback(priv, true); + break; + case MIC_TYPE_MUX_SGEN: + mt6357_set_ul_sine_gen(priv, true); + break; + default: + mt6357_set_amic(priv, true, mic_type); + break; + } + break; + case SND_SOC_DAPM_POST_PMD: + switch (mic_type) { + case MIC_TYPE_MUX_DMIC: + mt6357_set_dmic(priv, false); + break; + case MIC_TYPE_MUX_LPBK: + mt6357_set_loopback(priv, false); + break; + case MIC_TYPE_MUX_SGEN: + mt6357_set_ul_sine_gen(priv, false); + break; + default: + mt6357_set_amic(priv, false, mic_type); + break; + } + break; + default: + break; + } + + return 0; +} + +static int mt_pga_left_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* L preamplifier enable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLON_MASK, + MT6357_AUDPREAMPLON_ENABLE); + /* L ADC input sel : L PGA. Enable audio L ADC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDADCLINPUTSEL_MASK, + MT6357_AUDADCLINPUTSEL_PREAMPLIFIER); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDADCLPWRUP_MASK, + MT6357_AUDADCLPWRUP); + /* Audio L preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCPRECHARGE_MASK, + MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); + break; + case SND_SOC_DAPM_PRE_PMD: + /* Audio L ADC input sel : off, disable audio L ADC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDADCLPWRUP_MASK, + MT6357_AUDADCLPWRDOWN); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDADCLINPUTSEL_MASK, + MT6357_AUDADCLINPUTSEL_IDLE); + /* L preamplifier ACC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCCEN_MASK, + MT6357_AUDPREAMPLDCCEN_AC); + /* L preamplifier disable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLON_MASK, + MT6357_AUDPREAMPLON_DISABLE); + /* disable Audio L preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLDCPRECHARGE_MASK, + MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); + break; + default: + break; + } + + return 0; +} + +static int mt_pga_right_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* R preamplifier enable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_ENABLE); + /* R ADC input sel : R PGA. Enable audio R ADC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDADCRINPUTSEL_MASK, + MT6357_AUDADCRINPUTSEL_PREAMPLIFIER); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRUP); + /* Audio R preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCPRECHARGE_MASK, + MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); + break; + case SND_SOC_DAPM_PRE_PMD: + /* Audio R ADC input sel : off, disable audio R ADC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRDOWN); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDADCRINPUTSEL_MASK, MT6357_AUDADCRINPUTSEL_IDLE); + /* R preamplifier ACC */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_AC); + /* R preamplifier disable */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_DISABLE); + /* disable Audio R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRDCPRECHARGE_MASK, + MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); + break; + default: + break; + } + + return 0; +} + +static int adc_enable_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int lgain, rgain; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &lgain); + regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &rgain); + /* L PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLGAIN_MASK, + UL_GAIN_0DB << MT6357_AUDPREAMPLGAIN_SFT); + /* R PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRGAIN_MASK, + UL_GAIN_0DB << MT6357_AUDPREAMPRGAIN_SFT); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); + /* UL turn on */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE); + /* Wait to avoid any pop noises */ + msleep(100); + /* set the mic gains to the stored values */ + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, + MT6357_AUDPREAMPLGAIN_MASK, lgain); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, + MT6357_AUDPREAMPRGAIN_MASK, rgain); + break; + case SND_SOC_DAPM_POST_PMD: + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, + MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE); + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, + MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); + break; + default: + break; + } + + return 0; +} + +static void configure_downlinks(struct mt6357_priv *priv, bool enable) +{ + if (enable) { + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ELR_0, + MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK, + MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE); + /* Disable headphone short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK, + MT6357_AUD_HPR_SC_VAUDP15_DISABLE | + MT6357_AUD_HPL_SC_VAUDP15_DISABLE); + /* Disable handset short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_SC_VAUDP15_MASK, + MT6357_AUD_HS_SC_VAUDP15_DISABLE); + /* Disable lineout short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_SC_VAUDP15_MASK, + MT6357_AUD_LOL_SC_VAUDP15_DISABLE); + /* Reduce ESD resistance of AU_REFN */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, + MT6357_AUD_REFN_DERES_VAUDP15_MASK, + MT6357_AUD_REFN_DERES_VAUDP15_ENABLE); + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON1, MT6357_DIVCKS_ON); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle DIVCKS_CHG */ + regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON0, MT6357_DIVCKS_CHG); + /* Set NCP soft start mode as default mode: 150us */ + regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON4, + MT6357_DIVCKS_PWD_NCP_ST_150US); + /* Enable NCP */ + regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, + MT6357_DIVCKS_PWD_NCP_ENABLE); + usleep_range(250, 270); + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_VA33REFGEN_EN_VA18_MASK | + MT6357_LCLDO_REMOTE_SENSE_VA18_MASK | + MT6357_LCLDO_EN_VA18_MASK | + MT6357_HCLDO_REMOTE_SENSE_VA18_MASK | + MT6357_HCLDO_EN_VA18_MASK, + MT6357_VA33REFGEN_EN_VA18_ENABLE | + MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE | + MT6357_LCLDO_EN_VA18_ENABLE | + MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE | + MT6357_HCLDO_EN_VA18_ENABLE); + /* Enable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13, + MT6357_NVREG_EN_VAUDP15_MASK, MT6357_NVREG_EN_VAUDP15_ENABLE); + usleep_range(100, 120); + /* Enable IBIST */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10, + MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK, + MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE); + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, + MT6357_RSTB_DECODER_VA28_MASK, + MT6357_RSTB_DECODER_VA28_ENABLE); + /* Enable low-noise mode of DAC */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_DAC_LOW_NOISE_MODE_MASK, + MT6357_DAC_LOW_NOISE_MODE_ENABLE); + usleep_range(100, 120); + } else { + /* Disable low-noise mode of DAC */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_DAC_LOW_NOISE_MODE_MASK, + MT6357_DAC_LOW_NOISE_MODE_DISABLE); + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, + MT6357_RSTB_DECODER_VA28_MASK, + MT6357_RSTB_DECODER_VA28_DISABLE); + /* Enable linout short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_SC_VAUDP15_MASK, + MT6357_AUD_LOL_SC_VAUDP15_ENABLE); + /* Enable handset short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_SC_VAUDP15_MASK, + MT6357_AUD_HS_SC_VAUDP15_ENABLE); + /* Enable headphone short-circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_SC_VAUDP15_MASK | + MT6357_AUD_HPL_SC_VAUDP15_MASK, + MT6357_AUD_HPR_SC_VAUDP15_ENABLE | + MT6357_AUD_HPL_SC_VAUDP15_ENABLE); + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10, + MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK, + MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE); + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13, + MT6357_NVREG_EN_VAUDP15_MASK, + MT6357_NVREG_EN_VAUDP15_DISABLE); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, + MT6357_VA33REFGEN_EN_VA18_MASK | + MT6357_LCLDO_REMOTE_SENSE_VA18_MASK | + MT6357_LCLDO_EN_VA18_MASK | + MT6357_HCLDO_REMOTE_SENSE_VA18_MASK | + MT6357_HCLDO_EN_VA18_MASK, + MT6357_VA33REFGEN_EN_VA18_DISABLE | + MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE | + MT6357_LCLDO_EN_VA18_DISABLE | + MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE | + MT6357_HCLDO_EN_VA18_DISABLE); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, + MT6357_DIVCKS_PWD_NCP_MASK, MT6357_DIVCKS_PWD_NCP_DISABLE); + } +} + +static int mt_audio_in_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_playback_gpio(priv, true); + + /* Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, true); + + /* Disable HP main CMFB Switch */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HPRL_MAIN_CMFB_LOOP_MASK, + MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE); + /* Audio system digital clock power down release */ + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, + MT6357_CCI_AUDIO_FIFO_DISABLE | + MT6357_CCI_ACD_MODE_NORMAL_PATH | + MT6357_CCI_AFIFO_CLK_PWDB_ON | + MT6357_CCI_ACD_FUNC_RSTB_RESET); + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, + MT6357_CCI_AUD_ANACK_INVERT | + (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) | + MT6357_CCI_SCRAMBLER_CG_ENABLE | + MT6357_CCI_RAND_ENABLE | + MT6357_CCI_SPLT_SCRMB_CLK_ON | + MT6357_CCI_SPLT_SCRMB_ON | + MT6357_CCI_ZERO_PADDING_DISABLE | + MT6357_CCI_SCRAMBLER_ENABLE); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, + MT6357_CCI_AUDIO_FIFO_DISABLE | + MT6357_CCI_ACD_MODE_TEST_PATH | + MT6357_CCI_AFIFO_CLK_PWDB_ON | + MT6357_CCI_ACD_FUNC_RSTB_RELEASE); + /* sdm power on */ + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, + MT6357_CCI_AUDIO_FIFO_ENABLE | + MT6357_CCI_ACD_MODE_TEST_PATH | + MT6357_CCI_AFIFO_CLK_PWDB_ON | + MT6357_CCI_ACD_FUNC_RSTB_RELEASE); + + configure_downlinks(priv, true); + break; + case SND_SOC_DAPM_POST_PMD: + configure_downlinks(priv, false); + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, + MT6357_CCI_AUDIO_FIFO_DISABLE | + MT6357_CCI_ACD_MODE_TEST_PATH | + MT6357_CCI_AFIFO_CLK_PWDB_DOWN | + MT6357_CCI_ACD_FUNC_RSTB_RESET); + regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, + MT6357_CCI_AUD_ANACK_INVERT | + (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) | + MT6357_CCI_SCRAMBLER_CG_ENABLE | + MT6357_CCI_RAND_ENABLE | + MT6357_CCI_SPLT_SCRMB_CLK_ON | + MT6357_CCI_SPLT_SCRMB_ON | + MT6357_CCI_ZERO_PADDING_DISABLE | + MT6357_CCI_SCRAMBLER_DISABLE); + + set_playback_gpio(priv, false); + + /* disable Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, false); + break; + default: + break; + } + + return 0; +} + +static int mt_delay_250_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(250, 270); + break; + case SND_SOC_DAPM_PRE_PMD: + usleep_range(250, 270); + break; + default: + break; + } + + return 0; +} + +static int lo_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int lgain, rgain; + + /* Get current gain value */ + regmap_read(priv->regmap, MT6357_ZCD_CON1, &lgain); + rgain = (lgain & MT6357_AUD_LOR_GAIN_MASK) >> MT6357_AUD_LOR_GAIN_SFT; + lgain = lgain & MT6357_AUD_LOL_GAIN_MASK; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Set -40dB before enable HS to avoid POP noise */ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON1, + MT6357_AUD_LOL_GAIN_MASK | + MT6357_AUD_LOR_GAIN_MASK, + MT6357_DL_GAIN_N_40DB_REG); + /* Set LO STB enhance circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK, + MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE); + /* Enable LO driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK, + MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE); + /* Enable LO driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_PWRUP_VAUDP15_MASK, + MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE); + /* Set LOL gain to normal gain step by step */ + lo_volume_ramp(priv, DL_GAIN_N_40DB, lgain, + DL_GAIN_N_40DB, rgain); + break; + case SND_SOC_DAPM_PRE_PMD: + /* decrease LOL gain to minimum gain step by step */ + + lo_volume_ramp(priv, lgain, DL_GAIN_N_40DB, + rgain, DL_GAIN_N_40DB); + /* Disable LO driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_PWRUP_VAUDP15_MASK, + MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE); + /* Disable LO driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK, + MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE); + /* Clear LO STB enhance circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK, + MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE); + /* Save the gain value into the register*/ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON1, + MT6357_AUD_LOL_GAIN_MASK | + MT6357_AUD_LOR_GAIN_MASK, + lgain << MT6357_AUD_LOL_GAIN_SFT | + rgain << MT6357_AUD_LOR_GAIN_SFT); + + break; + default: + break; + } + + return 0; +} + +static int hs_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int gain; /* HS register has only one gain slot */ + + /* Get current gain value */ + regmap_read(priv->regmap, MT6357_ZCD_CON3, &gain); + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Set -40dB before enable HS to avoid POP noise */ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON3, + MT6357_AUD_HS_GAIN_MASK, + DL_GAIN_N_40DB); + + /* Set HS STB enhance circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK, + MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE); + /* Enable HS driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK, + MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE); + /* Enable HS driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_PWRUP_VAUDP15_MASK, + MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE); + /* Set HS gain to normal gain step by step */ + hs_volume_ramp(priv, DL_GAIN_N_40DB, gain); + break; + case SND_SOC_DAPM_PRE_PMD: + /* decrease HS gain to minimum gain step by step */ + hs_volume_ramp(priv, gain, DL_GAIN_N_40DB); + /* Disable HS driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_PWRUP_VAUDP15_MASK, + MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE); + /* Disable HS driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK, + MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE); + /* Clear HS STB enhance circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK, + MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE); + /* Save the gain value into the register*/ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON3, + MT6357_AUD_HS_GAIN_MASK, gain); + break; + default: + break; + } + + return 0; +} + +static int hp_main_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int lgain, rgain; + + /* Get current gain value */ + regmap_read(priv->regmap, MT6357_ZCD_CON2, &lgain); + rgain = (lgain & MT6357_AUD_HPR_GAIN_MASK) >> MT6357_AUD_HPR_GAIN_SFT; + lgain = lgain & MT6357_AUD_HPL_GAIN_MASK; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + priv->hp_channel_number++; + if (priv->hp_channel_number > 1) + break; + /* Set -40dB before enable HS to avoid POP noise */ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON2, + MT6357_AUD_HPL_GAIN_MASK | + MT6357_AUD_HPR_GAIN_MASK, + MT6357_DL_GAIN_N_40DB_REG); + /* Set HPP/N STB enhance circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, + MT6357_HPROUT_STB_ENH_VAUDP15_MASK | + MT6357_HPLOUT_STB_ENH_VAUDP15_MASK, + MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 | + MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250); + /* Enable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE); + /* Enable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | + MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, + MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE | + MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE); + /* Enable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HP_CMFB_RST_MASK | + MT6357_HPL_AUX_CMFB_LOOP_MASK | + MT6357_HPR_AUX_CMFB_LOOP_MASK, + MT6357_HP_CMFB_RST_NORMAL | + MT6357_HPL_AUX_CMFB_LOOP_ENABLE | + MT6357_HPR_AUX_CMFB_LOOP_ENABLE); + /* Enable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_BIAS_VAUDP15_MASK | + MT6357_AUD_HPL_BIAS_VAUDP15_MASK, + MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE | + MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE); + /* Enable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_PWRUP_VAUDP15_MASK | + MT6357_AUD_HPL_PWRUP_VAUDP15_MASK, + MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE | + MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE); + /* Short HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE); + /* Enable HP main CMFB loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HPRL_MAIN_CMFB_LOOP_MASK, + MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE); + /* Disable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HPR_AUX_CMFB_LOOP_MASK | + MT6357_HPL_AUX_CMFB_LOOP_MASK, + MT6357_HPR_AUX_CMFB_LOOP_DISABLE | + MT6357_HPL_AUX_CMFB_LOOP_DISABLE); + /* Enable HP main output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_PWRUP_VAUDP15_ENABLE | + MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + usleep_range(1000, 1200); + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, true); + /* Disable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | + MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, + MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE | + MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE); + /* apply volume setting */ + hp_volume_ramp(priv, DL_GAIN_N_40DB, lgain, + DL_GAIN_N_40DB, rgain); + /* Disable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE); + /* Unshort HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE); + usleep_range(100, 120); + break; + case SND_SOC_DAPM_PRE_PMD: + priv->hp_channel_number--; + if (priv->hp_channel_number > 0) + break; + /* Short HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE); + /* Enable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE); + /* decrease HPL/R gain to normal gain step by step */ + hp_volume_ramp(priv, lgain, DL_GAIN_N_40DB, + rgain, DL_GAIN_N_40DB); + /* Enable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | + MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, + MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE | + MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE); + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_PWRUP_VAUDP15_DISABLE | + MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE); + /* Enable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HP_CMFB_RST_MASK | + MT6357_HPL_AUX_CMFB_LOOP_MASK | + MT6357_HPR_AUX_CMFB_LOOP_MASK, + MT6357_HP_CMFB_RST_RESET | + MT6357_HPL_AUX_CMFB_LOOP_ENABLE | + MT6357_HPR_AUX_CMFB_LOOP_ENABLE); + /* Disable HP main CMFB loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HPRL_MAIN_CMFB_LOOP_MASK, + MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE); + /* Unshort HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, + MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE | + MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE); + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_PWRUP_VAUDP15_MASK | + MT6357_AUD_HPL_PWRUP_VAUDP15_MASK, + MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE | + MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE); + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_BIAS_VAUDP15_MASK | + MT6357_AUD_HPL_BIAS_VAUDP15_MASK, + MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE | + MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE); + /* Disable HP aux CMFB loop, + * Enable HP main CMFB for HP off state + */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, + MT6357_HPRL_MAIN_CMFB_LOOP_MASK | + MT6357_HPR_AUX_CMFB_LOOP_MASK | + MT6357_HPL_AUX_CMFB_LOOP_MASK, + MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE | + MT6357_HPR_AUX_CMFB_LOOP_DISABLE | + MT6357_HPL_AUX_CMFB_LOOP_DISABLE); + /* Disable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | + MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, + MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE | + MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE); + /* Disable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, + MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE | + MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE); + /* Save the gain value into the register*/ + regmap_update_bits(priv->regmap, MT6357_ZCD_CON2, + MT6357_AUD_HPL_GAIN_MASK | + MT6357_AUD_HPR_GAIN_MASK, + lgain << MT6357_AUD_HPL_GAIN_SFT | + rgain << MT6357_AUD_HPR_GAIN_SFT); + break; + default: + break; + } + + return 0; +} + +static int right_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable Audio DAC and control audio bias gen */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_DACR_PWRUP_VA28_MASK | + MT6357_AUD_DACR_PWRUP_VAUDP15_MASK, + MT6357_AUD_DACR_PWRUP_VA28_ENABLE | + MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE); + break; + case SND_SOC_DAPM_POST_PMU: + /* disable Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, false); + break; + case SND_SOC_DAPM_PRE_PMD: + /* Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, true); + /* Disable Audio DAC and control audio bias gen */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_DACR_PWRUP_VA28_MASK | + MT6357_AUD_DACR_PWRUP_VAUDP15_MASK, + MT6357_AUD_DACR_PWRUP_VA28_DISABLE | + MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE); + break; + default: + break; + } + + return 0; +} + +static int left_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable Audio DAC and control audio bias gen */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_DACL_PWRUP_VA28_MASK | + MT6357_AUD_DACL_PWRUP_VAUDP15_MASK, + MT6357_AUD_DACL_PWRUP_VA28_ENABLE | + MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE); + break; + case SND_SOC_DAPM_POST_PMU: + /* disable Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, false); + break; + case SND_SOC_DAPM_PRE_PMD: + /* Pull-down HPL/R to AVSS28_AUD */ + if (priv->pull_down_needed) + hp_pull_down(priv, true); + /* Disable Audio DAC and control audio bias gen */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_DACL_PWRUP_VA28_MASK | + MT6357_AUD_DACL_PWRUP_VAUDP15_MASK, + MT6357_AUD_DACL_PWRUP_VA28_DISABLE | + MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE); + break; + default: + break; + } + + return 0; +} + +/* Supply widgets subsequence */ +enum { + /* common */ + SUPPLY_SEQ_CLK_BUF, + SUPPLY_SEQ_AUD_GLB, + SUPPLY_SEQ_CLKSQ, + SUPPLY_SEQ_VOW_AUD_LPW, + SUPPLY_SEQ_AUD_VOW, + SUPPLY_SEQ_VOW_CLK, + SUPPLY_SEQ_VOW_LDO, + SUPPLY_SEQ_TOP_CK, + SUPPLY_SEQ_TOP_CK_LAST, + SUPPLY_SEQ_AUD_TOP, + SUPPLY_SEQ_AUD_TOP_LAST, + SUPPLY_SEQ_AFE, + /* capture */ + SUPPLY_SEQ_ADC_SUPPLY, +}; + +/* DAPM Widgets */ +static const struct snd_soc_dapm_widget mt6357_dapm_widgets[] = { + /* Analog Clocks */ + SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, + MT6357_DCXO_CW14, + MT6357_XO_AUDIO_EN_M_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, + MT6357_AUDDEC_ANA_CON11, + MT6357_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ, + MT6357_AUDENC_ANA_CON6, + MT6357_CLKSQ_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK, + MT6357_AUD_TOP_CKPDN_CON0, + MT6357_AUDNCP_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK, + MT6357_AUD_TOP_CKPDN_CON0, + MT6357_ZCD13M_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST, + MT6357_AUD_TOP_CKPDN_CON0, + MT6357_AUD_CK_PDN_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, + MT6357_AUD_TOP_CKPDN_CON0, + MT6357_AUDIF_CK_PDN_SFT, 1, NULL, 0), + + /* Digital Clocks */ + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_AFE_CTL_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_DAC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_ADC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_I2S_DL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PWR_CLK_DIS_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_RESERVED_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_LPBK", SUPPLY_SEQ_AUD_TOP, + MT6357_AUDIO_TOP_CON0, + MT6357_PDN_LPBK_CTL_SFT, 1, NULL, 0), + + /* General */ + SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE, + MT6357_AFE_UL_DL_CON0, + MT6357_AFE_ON_SFT, 0, NULL, 0), + + /* Uplinks */ + SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "MT6357 Capture", 0, + SND_SOC_NOPM, 0, 0, + mt_aif_out_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY, + SND_SOC_NOPM, 0, 0, + mt_adc_supply_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, adc_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0, + &pga_left_mux_control, + mt_pga_left_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0, + &pga_right_mux_control, + mt_pga_right_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0, + &mic_type_mux_control, + mt_mic_type_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MICBIAS0", MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_PWD_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS1", MT6357_AUDENC_ANA_CON9, + MT6357_AUD_MICBIAS1_PWD_SFT, 0, NULL, 0), + + /* UL inputs */ + SND_SOC_DAPM_INPUT("AIN0"), + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + SND_SOC_DAPM_INPUT("LPBK"), + SND_SOC_DAPM_INPUT("SGEN UL"), + + /* Downlinks */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "MT6357 Playback", 0, + SND_SOC_NOPM, 0, 0, + mt_audio_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("SGEN DL"), + SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux_control), + + SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, 0, 0, right_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, 0, 0, left_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("DL Digital Supply", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DL Analog Supply", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DL SRC", MT6357_AFE_DL_SRC2_CON0_L, + MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("Line Out Source", SND_SOC_NOPM, 0, 0, &lo_mux_control, + lo_mux_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX_E("Handset Source", SND_SOC_NOPM, 0, 0, &hs_mux_control, + hs_mux_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX_E("Headphone Right Source", SND_SOC_NOPM, 0, 0, &hpr_mux_control, + hp_main_mux_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX_E("Headphone Left Source", SND_SOC_NOPM, 0, 0, &hpl_mux_control, + hp_main_mux_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + /* DL outputs */ + SND_SOC_DAPM_OUTPUT("Headphones"), + SND_SOC_DAPM_OUTPUT("Hansdet"), + SND_SOC_DAPM_OUTPUT("Line out"), + + /* Sine generator */ + SND_SOC_DAPM_SUPPLY("SGEN UL Enable", + MT6357_AFE_TOP_CON0, MT6357_UL_SINE_ON_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SGEN Enable", + MT6357_AFE_SGEN_CFG0, + MT6357_SGEN_DAC_EN_CTL_SFT, 0, mt_audio_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("SGEN MUTE", + MT6357_AFE_SGEN_CFG0, + MT6357_SGEN_MUTE_SW_CTL_SFT, 1, NULL, 0) +}; + +static const struct snd_soc_dapm_route mt6357_dapm_routes[] = { + /* Capture */ + {"AIF1TX", NULL, "Mic Type Mux"}, + {"AIF1TX", NULL, "CLK_BUF"}, + {"AIF1TX", NULL, "AUDGLB"}, + {"AIF1TX", NULL, "CLKSQ Audio"}, + {"AIF1TX", NULL, "AUD_CK"}, + {"AIF1TX", NULL, "AUDIF_CK"}, + + {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"}, + {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"}, + {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"}, + {"AIF1TX", NULL, "AFE_ON"}, + + {"Mic Type Mux", "ACC", "ADC"}, + {"Mic Type Mux", "DCC", "ADC"}, + {"Mic Type Mux", "DCC_ECM_DIFF", "ADC"}, + {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC"}, + {"Mic Type Mux", "DMIC", "AIN0"}, + {"Mic Type Mux", "DMIC", "AIN2"}, + {"Mic Type Mux", "Loopback", "LPBK"}, + {"Mic Type Mux", "Sine Generator", "SGEN UL"}, + + {"SGEN UL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, + {"SGEN UL", NULL, "SGEN UL Enable"}, + {"SGEN UL", NULL, "SGEN MUTE"}, + {"SGEN UL", NULL, "SGEN Enable"}, + + {"ADC", NULL, "PGA L Mux"}, + {"ADC", NULL, "PGA R Mux"}, + {"ADC", NULL, "ADC Supply"}, + + {"PGA L Mux", "AIN0", "AIN0"}, + {"PGA L Mux", "AIN1", "AIN1"}, + {"PGA L Mux", "AIN2", "AIN2"}, + + {"PGA R Mux", "AIN0", "AIN0"}, + {"PGA R Mux", "AIN1", "AIN1"}, + {"PGA R Mux", "AIN2", "AIN2"}, + + {"AIN0", NULL, "MICBIAS0"}, + {"AIN1", NULL, "MICBIAS1"}, + {"AIN2", NULL, "MICBIAS0"}, + {"LPBK", NULL, "AUDIO_TOP_LPBK"}, + + /* Playback */ + {"DAC Mux", "Normal Path", "AIF_RX"}, + {"DAC Mux", "Sine Generator", "SGEN DL"}, + + {"AIF_RX", NULL, "DL SRC"}, + + {"SGEN DL", NULL, "DL SRC"}, + {"SGEN DL", NULL, "SGEN MUTE"}, + {"SGEN DL", NULL, "SGEN Enable"}, + {"SGEN DL", NULL, "DL Digital Supply"}, + {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, + + {"DACL", NULL, "DAC Mux"}, + {"DACR", NULL, "DAC Mux"}, + + {"DL Analog Supply", NULL, "CLK_BUF"}, + {"DL Analog Supply", NULL, "AUDGLB"}, + {"DL Analog Supply", NULL, "CLKSQ Audio"}, + {"DL Analog Supply", NULL, "AUDNCP_CK"}, + {"DL Analog Supply", NULL, "ZCD13M_CK"}, + {"DL Analog Supply", NULL, "AUD_CK"}, + {"DL Analog Supply", NULL, "AUDIF_CK"}, + + {"DL Digital Supply", NULL, "AUDIO_TOP_AFE_CTL"}, + {"DL Digital Supply", NULL, "AUDIO_TOP_DAC_CTL"}, + {"DL Digital Supply", NULL, "AUDIO_TOP_PWR_CLK"}, + {"DL Digital Supply", NULL, "AFE_ON"}, + + {"DACR", NULL, "DL Digital Supply"}, + {"DACR", NULL, "DL Analog Supply"}, + {"DACL", NULL, "DL Digital Supply"}, + {"DACL", NULL, "DL Analog Supply"}, + + {"Line Out Source", "DACR", "DACR"}, + {"Line Out Source", "Playback", "DACL"}, + {"Line Out Source", "Test mode", "DACL"}, + + {"Handset Source", "DACR", "DACR"}, + {"Handset Source", "Playback", "DACL"}, + {"Handset Source", "Test mode", "DACL"}, + + {"Headphone Right Source", "DAC", "DACR"}, + {"Headphone Right Source", "Line Out", "Line Out Source"}, + {"Headphone Right Source", "Handset", "Handset Source"}, + + {"Headphone Left Source", "DAC", "DACL"}, + {"Headphone Left Source", "Line Out", "Line Out Source"}, + {"Headphone Left Source", "Handset", "Handset Source"}, + + {"Line out", NULL, "Line Out Source"}, + {"Hansdet", NULL, "Handset Source"}, + + {"Headphones", NULL, "Headphone Right Source"}, + {"Headphones", NULL, "Headphone Left Source"}, +}; + +static struct snd_soc_dai_driver mtk_6357_dai_codecs[] = { + { + .name = "mt6357-snd-codec-aif1", + .playback = { + .stream_name = "MT6357 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = MT6357_SND_SOC_ADV_MT_FMTS, + }, + .capture = { + .stream_name = "MT6357 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MT6357_SOC_HIGH_USE_RATE, + .formats = MT6357_SND_SOC_ADV_MT_FMTS, + }, + }, +}; + +static int mt6357_codec_probe(struct snd_soc_component *codec) +{ + struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec); + + snd_soc_component_init_regmap(codec, priv->regmap); + + /* Enable audio part */ + regmap_update_bits(priv->regmap, MT6357_DCXO_CW14, + MT6357_XO_AUDIO_EN_M_MASK, MT6357_XO_AUDIO_EN_M_ENABLE); + /* Disable HeadphoneL/HeadphoneR short circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, + MT6357_AUD_HPR_SC_VAUDP15_MASK | + MT6357_AUD_HPL_SC_VAUDP15_MASK, + MT6357_AUD_HPR_SC_VAUDP15_DISABLE | + MT6357_AUD_HPL_SC_VAUDP15_DISABLE); + /* Disable voice short circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, + MT6357_AUD_HS_SC_VAUDP15_MASK, + MT6357_AUD_HS_SC_VAUDP15_DISABLE); + /* disable LO buffer left short circuit protection */ + regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, + MT6357_AUD_LOL_SC_VAUDP15_MASK, + MT6357_AUD_LOL_SC_VAUDP15_DISABLE); + /* set gpio */ + set_playback_gpio(priv, false); + set_capture_gpio(priv, false); + /* Disable audio part */ + regmap_update_bits(priv->regmap, MT6357_DCXO_CW14, + MT6357_XO_AUDIO_EN_M_MASK, + MT6357_XO_AUDIO_EN_M_DISABLE); + + return 0; +} + +static const struct snd_soc_component_driver mt6357_soc_component_driver = { + .probe = mt6357_codec_probe, + .read = snd_soc_component_read, + .write = snd_soc_component_write, + .controls = mt6357_controls, + .num_controls = ARRAY_SIZE(mt6357_controls), + .dapm_widgets = mt6357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets), + .dapm_routes = mt6357_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes), +}; + +static const u32 micbias_values[] = { + 1700000, 1800000, 1900000, 2000000, + 2100000, 2500000, 2600000, 2700000 +}; + +static u32 mt6357_get_micbias_idx(struct device_node *np, const char *micbias) +{ + int err; + u32 idx, val; + + err = of_property_read_u32(np, micbias, &val); + if (err) + return 0; + + for (idx = 0; idx < ARRAY_SIZE(micbias_values); idx++) { + if (val == micbias_values[idx]) + return idx; + } + return 0; +} + +static int mt6357_parse_dt(struct mt6357_priv *priv) +{ + u32 micbias_voltage_index = 0; + struct device_node *np = priv->dev->parent->of_node; + + if (!np) + return -EINVAL; + + priv->pull_down_needed = false; + if (of_property_read_bool(np, "mediatek,hp-pull-down")) + priv->pull_down_needed = true; + + micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias0-microvolt"); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, + MT6357_AUD_MICBIAS0_VREF_MASK, + micbias_voltage_index << MT6357_AUD_MICBIAS0_VREF_SFT); + + micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias1-microvolt"); + regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, + MT6357_AUD_MICBIAS1_VREF_MASK, + micbias_voltage_index << MT6357_AUD_MICBIAS1_VREF_SFT); + + return 0; +} + +static int mt6357_platform_driver_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + struct mt6357_priv *priv; + int ret; + + ret = devm_regulator_get_enable(&pdev->dev, "vaud28"); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to enable vaud28 regulator\n"); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, priv); + priv->dev = &pdev->dev; + + priv->regmap = mt6397->regmap; + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + ret = mt6357_parse_dt(priv); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to parse dts\n"); + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + return devm_snd_soc_register_component(&pdev->dev, + &mt6357_soc_component_driver, + mtk_6357_dai_codecs, + ARRAY_SIZE(mtk_6357_dai_codecs)); +} + +static const struct platform_device_id mt6357_platform_ids[] = { + {"mt6357-sound", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); + +static struct platform_driver mt6357_platform_driver = { + .driver = { + .name = "mt6357-sound", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = mt6357_platform_driver_probe, + .id_table = mt6357_platform_ids, +}; + +module_platform_driver(mt6357_platform_driver) + +MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver"); +MODULE_AUTHOR("Nicolas Belin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/mt6357.h b/sound/soc/codecs/mt6357.h new file mode 100644 index 000000000000..7f6fccada6a2 --- /dev/null +++ b/sound/soc/codecs/mt6357.h @@ -0,0 +1,660 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt6357.h -- mt6357 ALSA SoC audio codec driver + * + * Copyright (c) 2024 Baylibre + * Author: Nicolas Belin + */ + +#ifndef __MT6357_H__ +#define __MT6357_H__ + +#include + +/* Reg bit defines */ +/* MT6357_GPIO_DIR0 */ +#define MT6357_GPIO8_DIR_MASK BIT(8) +#define MT6357_GPIO8_DIR_INPUT 0 +#define MT6357_GPIO8_DIR_OUTPUT BIT(8) +#define MT6357_GPIO9_DIR_MASK BIT(9) +#define MT6357_GPIO9_DIR_INPUT 0 +#define MT6357_GPIO9_DIR_OUTPUT BIT(9) +#define MT6357_GPIO10_DIR_MASK BIT(10) +#define MT6357_GPIO10_DIR_INPUT 0 +#define MT6357_GPIO10_DIR_OUTPUT BIT(10) +#define MT6357_GPIO11_DIR_MASK BIT(11) +#define MT6357_GPIO11_DIR_INPUT 0 +#define MT6357_GPIO11_DIR_OUTPUT BIT(11) +#define MT6357_GPIO12_DIR_MASK BIT(12) +#define MT6357_GPIO12_DIR_INPUT 0 +#define MT6357_GPIO12_DIR_OUTPUT BIT(12) +#define MT6357_GPIO13_DIR_MASK BIT(13) +#define MT6357_GPIO13_DIR_INPUT 0 +#define MT6357_GPIO13_DIR_OUTPUT BIT(13) +#define MT6357_GPIO14_DIR_MASK BIT(14) +#define MT6357_GPIO14_DIR_INPUT 0 +#define MT6357_GPIO14_DIR_OUTPUT BIT(14) +#define MT6357_GPIO15_DIR_MASK BIT(15) +#define MT6357_GPIO15_DIR_INPUT 0 +#define MT6357_GPIO15_DIR_OUTPUT BIT(15) + +/* MT6357_GPIO_MODE2 */ +#define MT6357_GPIO8_MODE_MASK GENMASK(2, 0) +#define MT6357_GPIO8_MODE_AUD_CLK_MOSI BIT(0) +#define MT6357_GPIO8_MODE_GPIO 0 +#define MT6357_GPIO9_MODE_MASK GENMASK(5, 3) +#define MT6357_GPIO9_MODE_AUD_DAT_MOSI0 BIT(3) +#define MT6357_GPIO9_MODE_GPIO 0 +#define MT6357_GPIO10_MODE_MASK GENMASK(8, 6) +#define MT6357_GPIO10_MODE_AUD_DAT_MOSI1 BIT(6) +#define MT6357_GPIO10_MODE_GPIO 0 +#define MT6357_GPIO11_MODE_MASK GENMASK(11, 9) +#define MT6357_GPIO11_MODE_AUD_SYNC_MOSI BIT(9) +#define MT6357_GPIO11_MODE_GPIO 0 + +/* MT6357_GPIO_MODE2_SET */ +#define MT6357_GPIO8_MODE_SET_MASK GENMASK(2, 0) +#define MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI BIT(0) +#define MT6357_GPIO9_MODE_SET_MASK GENMASK(5, 3) +#define MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 BIT(3) +#define MT6357_GPIO10_MODE_SET_MASK GENMASK(8, 6) +#define MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 BIT(6) +#define MT6357_GPIO11_MODE_SET_MASK GENMASK(11, 9) +#define MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI BIT(9) + +/* MT6357_GPIO_MODE2_CLR */ +#define MT6357_GPIO_MODE2_CLEAR_ALL GENMASK(15, 0) + +/* MT6357_GPIO_MODE3 */ +#define MT6357_GPIO12_MODE_MASK GENMASK(2, 0) +#define MT6357_GPIO12_MODE_AUD_CLK_MISO BIT(0) +#define MT6357_GPIO12_MODE_GPIO 0 +#define MT6357_GPIO13_MODE_MASK GENMASK(5, 3) +#define MT6357_GPIO13_MODE_AUD_DAT_MISO0 BIT(3) +#define MT6357_GPIO13_MODE_GPIO 0 +#define MT6357_GPIO14_MODE_MASK GENMASK(8, 6) +#define MT6357_GPIO14_MODE_AUD_DAT_MISO1 BIT(6) +#define MT6357_GPIO14_MODE_GPIO 0 +#define MT6357_GPIO15_MODE_MASK GENMASK(11, 9) +#define MT6357_GPIO15_MODE_AUD_SYNC_MISO BIT(9) +#define MT6357_GPIO15_MODE_GPIO 0 + +/* MT6357_GPIO_MODE3_SET */ +#define MT6357_GPIO12_MODE_SET_MASK GENMASK(2, 0) +#define MT6357_GPIO12_MODE_SET_AUD_CLK_MISO BIT(0) +#define MT6357_GPIO13_MODE_SET_MASK GENMASK(5, 3) +#define MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 BIT(3) +#define MT6357_GPIO14_MODE_SET_MASK GENMASK(8, 6) +#define MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 BIT(6) +#define MT6357_GPIO15_MODE_SET_MASK GENMASK(11, 9) +#define MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO BIT(9) + +/* MT6357_GPIO_MODE3_CLR */ +#define MT6357_GPIO_MODE3_CLEAR_ALL GENMASK(15, 0) + +/* MT6357_DCXO_CW14 */ +#define MT6357_XO_AUDIO_EN_M_SFT 13 +#define MT6357_XO_AUDIO_EN_M_MASK BIT(13) +#define MT6357_XO_AUDIO_EN_M_ENABLE BIT(13) +#define MT6357_XO_AUDIO_EN_M_DISABLE 0 + +/* MT6357_AUD_TOP_CKPDN_CON0 */ +#define MT6357_AUDNCP_CK_PDN_SFT 6 +#define MT6357_ZCD13M_CK_PDN_SFT 5 +#define MT6357_AUDIF_CK_PDN_SFT 2 +#define MT6357_AUD_CK_PDN_SFT 1 + +/* MT6357_AUDNCP_CLKDIV_CON0 */ +#define MT6357_DIVCKS_CHG BIT(0) + +/* MT6357_AUDNCP_CLKDIV_CON1 */ +#define MT6357_DIVCKS_ON BIT(0) + +/* MT6357_AUDNCP_CLKDIV_CON3 */ +#define MT6357_DIVCKS_PWD_NCP_MASK BIT(0) +#define MT6357_DIVCKS_PWD_NCP_DISABLE BIT(0) +#define MT6357_DIVCKS_PWD_NCP_ENABLE 0 + +/* MT6357_AUDNCP_CLKDIV_CON4 */ +#define MT6357_DIVCKS_PWD_NCP_ST_SEL_MASK GENMASK(1, 0) +#define MT6357_DIVCKS_PWD_NCP_ST_50US 0 +#define MT6357_DIVCKS_PWD_NCP_ST_100US 1 +#define MT6357_DIVCKS_PWD_NCP_ST_150US 2 +#define MT6357_DIVCKS_PWD_NCP_ST_200US 3 + +/* MT6357_AFE_UL_DL_CON0 */ +#define MT6357_AFE_UL_LR_SWAP_SFT 15 +#define MT6357_AFE_ON_SFT 0 + +/* MT6357_AFE_DL_SRC2_CON0_L */ +#define MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 + +/* MT6357_AFE_UL_SRC_CON0_H */ +#define MT6357_C_TWO_DIGITAL_MIC_CTL_MASK BIT(7) +#define MT6357_C_TWO_DIGITAL_MIC_ENABLE BIT(7) +#define MT6357_C_TWO_DIGITAL_MIC_DISABLE 0 + +/* MT6357_AFE_UL_SRC_CON0_L */ +#define MT6357_UL_SDM_3_LEVEL_CTL_MASK BIT(1) +#define MT6357_UL_SDM_3_LEVEL_SELECT BIT(1) +#define MT6357_UL_SDM_3_LEVEL_DESELECT 0 +#define MT6357_UL_SRC_ON_TMP_CTL_MASK BIT(0) +#define MT6357_UL_SRC_ENABLE BIT(0) +#define MT6357_UL_SRC_DISABLE 0 + +/* MT6357_AFE_TOP_CON0 */ +#define MT6357_UL_SINE_ON_SFT 1 +#define MT6357_UL_SINE_ON_MASK BIT(1) +#define MT6357_DL_SINE_ON_SFT 0 +#define MT6357_DL_SINE_ON_MASK BIT(0) + +/* MT6357_AUDIO_TOP_CON0 */ +#define MT6357_PDN_LPBK_CTL_SFT 15 +#define MT6357_PDN_AFE_CTL_SFT 7 +#define MT6357_PDN_DAC_CTL_SFT 6 +#define MT6357_PDN_ADC_CTL_SFT 5 +#define MT6357_PDN_I2S_DL_CTL_SFT 3 +#define MT6357_PWR_CLK_DIS_CTL_SFT 2 +#define MT6357_PDN_AFE_TESTMODEL_CTL_SFT 1 +#define MT6357_PDN_RESERVED_SFT 0 + +/* MT6357_AFUNC_AUD_CON0 */ +#define MT6357_CCI_AUD_ANACK_INVERT BIT(15) +#define MT6357_CCI_AUD_ANACK_NORMAL 0 +#define MT6357_CCI_AUDIO_FIFO_WPTR_SFT 12 +#define MT6357_CCI_SCRAMBLER_CG_ENABLE BIT(11) +#define MT6357_CCI_SCRAMBLER_CG_DISABLE 0 +#define MT6357_CCI_LCK_INV_OUT_OF_PHASE BIT(10) +#define MT6357_CCI_LCK_INV_IN_PHASE 0 +#define MT6357_CCI_RAND_ENABLE BIT(9) +#define MT6357_CCI_RAND_DISABLE 0 +#define MT6357_CCI_SPLT_SCRMB_CLK_ON BIT(8) +#define MT6357_CCI_SPLT_SCRMB_CLK_OFF 0 +#define MT6357_CCI_SPLT_SCRMB_ON BIT(7) +#define MT6357_CCI_SPLT_SCRMB_OFF 0 +#define MT6357_CCI_AUD_IDAC_TEST_EN_FROM_TEST_IN BIT(6) +#define MT6357_CCI_AUD_IDAC_TEST_EN_NORMAL_PATH 0 +#define MT6357_CCI_ZERO_PADDING_DISABLE BIT(5) +#define MT6357_CCI_ZERO_PADDING_ENABLE 0 +#define MT6357_CCI_AUD_SPLIT_TEST_EN_FROM_TEST_IN BIT(4) +#define MT6357_CCI_AUD_SPLIT_TEST_EN_NORMAL_PATH 0 +#define MT6357_CCI_AUD_SDM_MUTE_L_REG_CTL BIT(3) +#define MT6357_CCI_AUD_SDM_MUTE_L_NO_CTL 0 +#define MT6357_CCI_AUD_SDM_MUTE_R_REG_CTL BIT(2) +#define MT6357_CCI_AUD_SDM_MUTE_R_NO_CTL 0 +#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER3 BIT(1) +#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER1 0 +#define MT6357_CCI_SCRAMBLER_ENABLE BIT(0) +#define MT6357_CCI_SCRAMBLER_DISABLE 0 + +/* MT6357_AFUNC_AUD_CON2 */ +#define MT6357_CCI_AUDIO_FIFO_ENABLE BIT(3) +#define MT6357_CCI_AUDIO_FIFO_DISABLE 0 +#define MT6357_CCI_ACD_MODE_NORMAL_PATH BIT(2) +#define MT6357_CCI_ACD_MODE_TEST_PATH 0 +#define MT6357_CCI_AFIFO_CLK_PWDB_ON BIT(1) +#define MT6357_CCI_AFIFO_CLK_PWDB_DOWN 0 +#define MT6357_CCI_ACD_FUNC_RSTB_RELEASE BIT(0) +#define MT6357_CCI_ACD_FUNC_RSTB_RESET 0 + +/* MT6357_AFE_ADDA_MTKAIF_CFG0 */ +#define MT6357_ADDA_MTKAIF_LPBK_CTL_MASK BIT(1) +#define MT6357_ADDA_MTKAIF_LPBK_ENABLE BIT(1) +#define MT6357_ADDA_MTKAIF_LPBK_DISABLE 0 + +/* MT6357_AFE_SGEN_CFG0 */ +#define MT6357_SGEN_DAC_EN_CTL_SFT 7 +#define MT6357_SGEN_DAC_ENABLE BIT(7) +#define MT6357_SGEN_MUTE_SW_CTL_SFT 6 +#define MT6357_SGEN_MUTE_SW_DISABLE 0 + +/* MT6357_AFE_DCCLK_CFG0 */ +#define MT6357_DCCLK_DIV_MASK GENMASK(15, 5) +#define MT6357_DCCLK_DIV_SFT 5 +#define MT6357_DCCLK_DIV_RUN_VALUE (32 << MT6357_DCCLK_DIV_SFT) +#define MT6357_DCCLK_DIV_STOP_VALUE (259 << MT6357_DCCLK_DIV_SFT) +#define MT6357_DCCLK_PDN_MASK BIT(1) +#define MT6357_DCCLK_PDN BIT(1) +#define MT6357_DCCLK_OUTPUT 0 +#define MT6357_DCCLK_GEN_ON_MASK BIT(0) +#define MT6357_DCCLK_GEN_ON BIT(0) +#define MT6357_DCCLK_GEN_OFF 0 + +/* MT6357_AFE_DCCLK_CFG1 */ +#define MT6357_DCCLK_RESYNC_BYPASS_MASK BIT(8) +#define MT6357_DCCLK_RESYNC_BYPASS BIT(8) + +/* MT6357_AFE_AUD_PAD_TOP */ +#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK GENMASK(15, 8) +#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE (BIT(13) | BIT(12) | BIT(8)) +#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE (BIT(13) | BIT(12)) +#define MT6357_AUD_PAD_TX_FIFO_LPBK_MASK GENMASK(7, 0) +#define MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE (BIT(5) | BIT(4) | BIT(0)) +#define MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE 0 + +/* MT6357_AUDENC_ANA_CON0 */ +#define MT6357_AUDADCLINPUTSEL_MASK GENMASK(14, 13) +#define MT6357_AUDADCLINPUTSEL_PREAMPLIFIER BIT(14) +#define MT6357_AUDADCLINPUTSEL_IDLE 0 +#define MT6357_AUDADCLPWRUP_SFT 12 +#define MT6357_AUDADCLPWRUP_MASK BIT(12) +#define MT6357_AUDADCLPWRUP BIT(12) +#define MT6357_AUDADCLPWRDOWN 0 +#define MT6357_AUDPREAMPLGAIN_SFT 8 +#define MT6357_AUDPREAMPLGAIN_MASK GENMASK(10, 8) +#define MT6357_AUDPREAMPLGAIN_MAX 4 +#define MT6357_AUDPREAMPLINPUTSEL_SFT 6 +#define MT6357_AUDPREAMPLINPUTSEL_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUDPREAMPLDCPRECHARGE_MASK BIT(2) +#define MT6357_AUDPREAMPLDCPRECHARGE_ENABLE BIT(2) +#define MT6357_AUDPREAMPLDCPRECHARGE_DISABLE 0 +#define MT6357_AUDPREAMPLDCCEN_MASK BIT(1) +#define MT6357_AUDPREAMPLDCCEN_DC BIT(1) +#define MT6357_AUDPREAMPLDCCEN_AC 0 +#define MT6357_AUDPREAMPLON_MASK BIT(0) +#define MT6357_AUDPREAMPLON_ENABLE BIT(0) +#define MT6357_AUDPREAMPLON_DISABLE 0 + +/* MT6357_AUDENC_ANA_CON1 */ +#define MT6357_AUDADCRINPUTSEL_MASK GENMASK(14, 13) +#define MT6357_AUDADCRINPUTSEL_PREAMPLIFIER BIT(14) +#define MT6357_AUDADCRINPUTSEL_IDLE 0 +#define MT6357_AUDADCRPWRUP_SFT 12 +#define MT6357_AUDADCRPWRUP_MASK BIT(12) +#define MT6357_AUDADCRPWRUP BIT(12) +#define MT6357_AUDADCRPWRDOWN 0 +#define MT6357_AUDPREAMPRGAIN_SFT 8 +#define MT6357_AUDPREAMPRGAIN_MASK GENMASK(10, 8) +#define MT6357_AUDPREAMPRGAIN_MAX 4 +#define MT6357_AUDPREAMPRINPUTSEL_SFT 6 +#define MT6357_AUDPREAMPRINPUTSEL_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUDPREAMPRDCPRECHARGE_MASK BIT(2) +#define MT6357_AUDPREAMPRDCPRECHARGE_ENABLE BIT(2) +#define MT6357_AUDPREAMPRDCPRECHARGE_DISABLE 0 +#define MT6357_AUDPREAMPRDCCEN_MASK BIT(1) +#define MT6357_AUDPREAMPRDCCEN_DC BIT(1) +#define MT6357_AUDPREAMPRDCCEN_AC 0 +#define MT6357_AUDPREAMPRON_MASK BIT(0) +#define MT6357_AUDPREAMPRON_ENABLE BIT(0) +#define MT6357_AUDPREAMPRON_DISABLE 0 + +/* MT6357_AUDENC_ANA_CON6 */ +#define MT6357_CLKSQ_EN_SFT 0 + +/* MT6357_AUDENC_ANA_CON7 */ +#define MT6357_AUDDIGMICBIAS_MASK GENMASK(2, 1) +#define MT6357_AUDDIGMICBIAS_DEFAULT_VALUE BIT(2) +#define MT6357_AUDDIGMICBIAS_OFF 0 +#define MT6357_AUDDIGMICEN_MASK BIT(0) +#define MT6357_AUDDIGMICEN_ENABLE BIT(0) +#define MT6357_AUDDIGMICEN_DISABLE 0 + +/* MT6357_AUDENC_ANA_CON8 */ +#define MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK BIT(14) +#define MT6357_AUD_MICBIAS0_DCSW2N_ENABLE BIT(14) +#define MT6357_AUD_MICBIAS0_DCSW2N_DISABLE 0 +#define MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK BIT(13) +#define MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE BIT(13) +#define MT6357_AUD_MICBIAS0_DCSW2P2_DISABLE 0 +#define MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK BIT(12) +#define MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE BIT(12) +#define MT6357_AUD_MICBIAS0_DCSW2P1_DISABLE 0 +#define MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK BIT(10) +#define MT6357_AUD_MICBIAS0_DCSW0N_ENABLE BIT(10) +#define MT6357_AUD_MICBIAS0_DCSWN_DISABLE 0 +#define MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK BIT(9) +#define MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE BIT(9) +#define MT6357_AUD_MICBIAS0_DCSW0P2_DISABLE 0 +#define MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK BIT(8) +#define MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE BIT(8) +#define MT6357_AUD_MICBIAS0_DCSW0P1_DISABLE 0 +#define MT6357_AUD_MICBIAS0_VREF_MASK GENMASK(6, 4) +#define MT6357_AUD_MICBIAS0_VREF_SFT 4 +#define MT6357_AUD_MICBIAS0_PWD_SFT 0 + +#define MT6357_AUD_MICBIAS0_DC_MASK (MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK | \ + MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK | \ + MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK | \ + MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK | \ + MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK | \ + MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK) + +#define MT6357_AUD_MICBIAS0_DC_ENABLE_ALL (MT6357_AUD_MICBIAS0_DCSW2N_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW0N_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE) + +#define MT6357_AUD_MICBIAS0_DC_ENABLE_P1 (MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \ + MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE) + +#define MT6357_AUD_MICBIAS0_DC_DISABLE_ALL 0 + +/* MT6357_AUDENC_ANA_CON9 */ +#define MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK BIT(8) +#define MT6357_AUD_MICBIAS1_DCSW1P_ENABLE BIT(8) +#define MT6357_AUD_MICBIAS1_DCSW1P_DISABLE 0 +#define MT6357_AUD_MICBIAS1_VREF_MASK GENMASK(6, 4) +#define MT6357_AUD_MICBIAS1_VREF_SFT 4 +#define MT6357_AUD_MICBIAS1_PWD_SFT 0 + +/* MT6357_AUDDEC_ANA_CON0 */ +#define MT6357_AUD_HPR_SC_VAUDP15_MASK BIT(13) +#define MT6357_AUD_HPR_SC_VAUDP15_DISABLE BIT(13) +#define MT6357_AUD_HPR_SC_VAUDP15_ENABLE 0 +#define MT6357_AUD_HPL_SC_VAUDP15_MASK BIT(12) +#define MT6357_AUD_HPL_SC_VAUDP15_DISABLE BIT(12) +#define MT6357_AUD_HPL_SC_VAUDP15_ENABLE 0 +#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT 10 +#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT 8 +#define MT6357_AUD_HPR_BIAS_VAUDP15_MASK BIT(7) +#define MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE BIT(7) +#define MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE 0 +#define MT6357_AUD_HPL_BIAS_VAUDP15_MASK BIT(6) +#define MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE BIT(6) +#define MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE 0 +#define MT6357_AUD_HPR_PWRUP_VAUDP15_MASK BIT(5) +#define MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE BIT(5) +#define MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_AUD_HPL_PWRUP_VAUDP15_MASK BIT(4) +#define MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE BIT(4) +#define MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_AUD_DACL_PWRUP_VA28_MASK BIT(3) +#define MT6357_AUD_DACL_PWRUP_VA28_ENABLE BIT(3) +#define MT6357_AUD_DACL_PWRUP_VA28_DISABLE 0 +#define MT6357_AUD_DACR_PWRUP_VA28_MASK BIT(2) +#define MT6357_AUD_DACR_PWRUP_VA28_ENABLE BIT(2) +#define MT6357_AUD_DACR_PWRUP_VA28_DISABLE 0 +#define MT6357_AUD_DACR_PWRUP_VAUDP15_MASK BIT(1) +#define MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE BIT(1) +#define MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_AUD_DACL_PWRUP_VAUDP15_MASK BIT(0) +#define MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE BIT(0) +#define MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON1 */ +#define MT6357_HPROUT_STG_CTRL_VAUDP15_MASK GENMASK(14, 12) +#define MT6357_HPROUT_STG_CTRL_VAUDP15_SFT 12 +#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK GENMASK(10, 8) +#define MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT 8 +#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX 7 +#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK BIT(7) +#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(7) +#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE 0 +#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK BIT(6) +#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(6) +#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE 0 +#define MT6357_HPR_AUX_FBRSW_VAUDP15_MASK BIT(5) +#define MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE BIT(5) +#define MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE 0 +#define MT6357_HPL_AUX_FBRSW_VAUDP15_MASK BIT(4) +#define MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE BIT(4) +#define MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE 0 +#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK BIT(3) +#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE BIT(3) +#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK BIT(2) +#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE BIT(2) +#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_HPROUT_PWRUP_VAUDP15_MASK BIT(1) +#define MT6357_HPROUT_PWRUP_VAUDP15_ENABLE BIT(1) +#define MT6357_HPROUT_PWRUP_VAUDP15_DISABLE 0 +#define MT6357_HPLOUT_PWRUP_VAUDP15_MASK BIT(0) +#define MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE BIT(0) +#define MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON2 */ +#define MT6357_HPP_SHORT_2VCM_VAUDP15_MASK BIT(10) +#define MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE BIT(10) +#define MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE 0 +#define MT6357_AUD_REFN_DERES_VAUDP15_MASK BIT(9) +#define MT6357_AUD_REFN_DERES_VAUDP15_ENABLE BIT(9) +#define MT6357_AUD_REFN_DERES_VAUDP15_DISABLE 0 +#define MT6357_HPROUT_STB_ENH_VAUDP15_MASK GENMASK(6, 4) +#define MT6357_HPROUT_STB_ENH_VAUDP15_OPEN 0 +#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(4) +#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_POPEN BIT(5) +#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 (BIT(4) | BIT(5)) +#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(4) | BIT(6)) +#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P470 (BIT(4) | BIT(5) | BIT(6)) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_MASK GENMASK(2, 0) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_OPEN 0 +#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(0) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_POPEN BIT(1) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250 (BIT(0) | BIT(1)) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(0) | BIT(2)) +#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P470 (BIT(0) | BIT(1) | BIT(2)) + +/* MT6357_AUDDEC_ANA_CON3 */ +#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK BIT(7) +#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE BIT(7) +#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE 0 +#define MT6357_AUD_HS_SC_VAUDP15_MASK BIT(4) +#define MT6357_AUD_HS_SC_VAUDP15_DISABLE BIT(4) +#define MT6357_AUD_HS_SC_VAUDP15_ENABLE 0 +#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT 2 +#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK BIT(1) +#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE BIT(1) +#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_DISABLE 0 +#define MT6357_AUD_HS_PWRUP_VAUDP15_MASK BIT(0) +#define MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE BIT(0) +#define MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON4 */ +#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK BIT(8) +#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE BIT(8) +#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE 0 +#define MT6357_AUD_LOL_SC_VAUDP15_MASK BIT(4) +#define MT6357_AUD_LOL_SC_VAUDP15_DISABLE BIT(4) +#define MT6357_AUD_LOL_SC_VAUDP15_ENABLE 0 +#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0) +#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT 2 +#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK BIT(1) +#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE BIT(1) +#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE 0 +#define MT6357_AUD_LOL_PWRUP_VAUDP15_MASK BIT(0) +#define MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE BIT(0) +#define MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON6 */ +#define MT6357_HP_AUX_LOOP_GAIN_MASK GENMASK(15, 12) +#define MT6357_HP_AUX_LOOP_GAIN_SFT 12 +#define MT6357_HP_AUX_LOOP_GAIN_MAX 0x0f +#define MT6357_HPR_AUX_CMFB_LOOP_MASK BIT(11) +#define MT6357_HPR_AUX_CMFB_LOOP_ENABLE BIT(11) +#define MT6357_HPR_AUX_CMFB_LOOP_DISABLE 0 +#define MT6357_HPL_AUX_CMFB_LOOP_MASK BIT(10) +#define MT6357_HPL_AUX_CMFB_LOOP_ENABLE BIT(10) +#define MT6357_HPL_AUX_CMFB_LOOP_DISABLE 0 +#define MT6357_HPRL_MAIN_CMFB_LOOP_MASK BIT(9) +#define MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE BIT(9) +#define MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE 0 +#define MT6357_HP_CMFB_RST_MASK BIT(7) +#define MT6357_HP_CMFB_RST_NORMAL BIT(7) +#define MT6357_HP_CMFB_RST_RESET 0 +#define MT6357_DAC_LOW_NOISE_MODE_MASK BIT(0) +#define MT6357_DAC_LOW_NOISE_MODE_ENABLE BIT(0) +#define MT6357_DAC_LOW_NOISE_MODE_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON7 */ +#define MT6357_HP_IVBUF_DEGAIN_SFT 2 +#define MT6357_HP_IVBUF_DEGAIN_MAX 1 + +/* MT6357_AUDDEC_ANA_CON10 */ +#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK BIT(8) +#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE BIT(8) +#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE 0 + +/* MT6357_AUDDEC_ANA_CON11 */ +#define MT6357_RSTB_ENCODER_VA28_MASK BIT(5) +#define MT6357_RSTB_ENCODER_VA28_ENABLE BIT(5) +#define MT6357_RSTB_ENCODER_VA28_DISABLE 0 +#define MT6357_AUDGLB_PWRDN_VA28_SFT 4 +#define MT6357_RSTB_DECODER_VA28_MASK BIT(0) +#define MT6357_RSTB_DECODER_VA28_ENABLE BIT(0) +#define MT6357_RSTB_DECODER_VA28_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON12 */ +#define MT6357_VA28REFGEN_EN_VA28_MASK BIT(13) +#define MT6357_VA28REFGEN_EN_VA28_ENABLE BIT(13) +#define MT6357_VA28REFGEN_EN_VA28_DISABLE 0 +#define MT6357_VA33REFGEN_EN_VA18_MASK BIT(12) +#define MT6357_VA33REFGEN_EN_VA18_ENABLE BIT(12) +#define MT6357_VA33REFGEN_EN_VA18_DISABLE 0 +#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK BIT(10) +#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE BIT(10) +#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE 0 +#define MT6357_LCLDO_ENC_EN_VA28_MASK BIT(8) +#define MT6357_LCLDO_ENC_EN_VA28_ENABLE BIT(8) +#define MT6357_LCLDO_ENC_EN_VA28_DISABLE 0 +#define MT6357_LCLDO_REMOTE_SENSE_VA18_MASK BIT(6) +#define MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE BIT(6) +#define MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE 0 +#define MT6357_LCLDO_EN_VA18_MASK BIT(4) +#define MT6357_LCLDO_EN_VA18_ENABLE BIT(4) +#define MT6357_LCLDO_EN_VA18_DISABLE 0 +#define MT6357_HCLDO_REMOTE_SENSE_VA18_MASK BIT(2) +#define MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE BIT(2) +#define MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE 0 +#define MT6357_HCLDO_EN_VA18_MASK BIT(0) +#define MT6357_HCLDO_EN_VA18_ENABLE BIT(0) +#define MT6357_HCLDO_EN_VA18_DISABLE 0 + +/* MT6357_AUDDEC_ANA_CON13 */ +#define MT6357_NVREG_EN_VAUDP15_MASK BIT(0) +#define MT6357_NVREG_EN_VAUDP15_ENABLE BIT(0) +#define MT6357_NVREG_EN_VAUDP15_DISABLE 0 + +/* MT6357_AUDDEC_ELR_0 */ +#define MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK BIT(12) +#define MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE BIT(12) +#define MT6357_AUD_HP_TRIM_EN_VAUDP15_DISABLE 0 + +/* MT6357_ZCD_CON1 */ +#define MT6357_AUD_LOL_GAIN_MASK GENMASK(4, 0) +#define MT6357_AUD_LOL_GAIN_SFT 0 +#define MT6357_AUD_LOR_GAIN_MASK GENMASK(11, 7) +#define MT6357_AUD_LOR_GAIN_SFT 7 +#define MT6357_AUD_LO_GAIN_MAX 0x12 + +/* MT6357_ZCD_CON2 */ +#define MT6357_AUD_HPL_GAIN_MASK GENMASK(4, 0) +#define MT6357_AUD_HPL_GAIN_SFT 0 +#define MT6357_AUD_HPR_GAIN_MASK GENMASK(11, 7) +#define MT6357_AUD_HPR_GAIN_SFT 7 +#define MT6357_AUD_HP_GAIN_MAX 0x12 + +/* MT6357_ZCD_CON3 */ +#define MT6357_AUD_HS_GAIN_MASK GENMASK(4, 0) +#define MT6357_AUD_HS_GAIN_SFT 0 +#define MT6357_AUD_HS_GAIN_MAX 0x12 + +/* Registers list */ +/* gpio direction */ +#define MT6357_GPIO_DIR0 0x0088 +/* mosi */ +#define MT6357_GPIO_MODE2 0x00B6 +#define MT6357_GPIO_MODE2_SET 0x00B8 +#define MT6357_GPIO_MODE2_CLR 0x00BA +/* miso */ +#define MT6357_GPIO_MODE3 0x00BC +#define MT6357_GPIO_MODE3_SET 0x00BE +#define MT6357_GPIO_MODE3_CLR 0x00C0 + +#define MT6357_DCXO_CW14 0x07AC + +#define MT6357_AUD_TOP_CKPDN_CON0 0x208C +#define MT6357_AUDNCP_CLKDIV_CON0 0x20B4 +#define MT6357_AUDNCP_CLKDIV_CON1 0x20B6 +#define MT6357_AUDNCP_CLKDIV_CON2 0x20B8 +#define MT6357_AUDNCP_CLKDIV_CON3 0x20BA +#define MT6357_AUDNCP_CLKDIV_CON4 0x20BC +#define MT6357_AFE_UL_DL_CON0 0x2108 +#define MT6357_AFE_DL_SRC2_CON0_L 0x210A +#define MT6357_AFE_UL_SRC_CON0_H 0x210C +#define MT6357_AFE_UL_SRC_CON0_L 0x210E +#define MT6357_AFE_TOP_CON0 0x2110 +#define MT6357_AUDIO_TOP_CON0 0x2112 +#define MT6357_AFUNC_AUD_CON0 0x2116 +#define MT6357_AFUNC_AUD_CON2 0x211A +#define MT6357_AFE_ADDA_MTKAIF_CFG0 0x2134 +#define MT6357_AFE_SGEN_CFG0 0x2140 +#define MT6357_AFE_DCCLK_CFG0 0x2146 +#define MT6357_AFE_DCCLK_CFG1 0x2148 +#define MT6357_AFE_AUD_PAD_TOP 0x214C +#define MT6357_AUDENC_ANA_CON0 0x2188 +#define MT6357_AUDENC_ANA_CON1 0x218A +#define MT6357_AUDENC_ANA_CON6 0x2194 +#define MT6357_AUDENC_ANA_CON7 0x2196 +#define MT6357_AUDENC_ANA_CON8 0x2198 +#define MT6357_AUDENC_ANA_CON9 0x219A +#define MT6357_AUDDEC_ANA_CON0 0x2208 +#define MT6357_AUDDEC_ANA_CON1 0x220A +#define MT6357_AUDDEC_ANA_CON2 0x220C +#define MT6357_AUDDEC_ANA_CON3 0x220E +#define MT6357_AUDDEC_ANA_CON4 0x2210 +#define MT6357_AUDDEC_ANA_CON6 0x2214 +#define MT6357_AUDDEC_ANA_CON7 0x2216 +#define MT6357_AUDDEC_ANA_CON10 0x221C +#define MT6357_AUDDEC_ANA_CON11 0x221E +#define MT6357_AUDDEC_ANA_CON12 0x2220 +#define MT6357_AUDDEC_ANA_CON13 0x2222 +#define MT6357_AUDDEC_ELR_0 0x2226 +#define MT6357_ZCD_CON1 0x228A +#define MT6357_ZCD_CON2 0x228C +#define MT6357_ZCD_CON3 0x228E + +enum { + DL_GAIN_8DB = 0, + DL_GAIN_0DB = 8, + DL_GAIN_N_1DB = 9, + DL_GAIN_N_10DB = 18, + DL_GAIN_N_12DB = 20, + DL_GAIN_N_40DB = 0x1f, +}; + +enum { + UL_GAIN_0DB = 0, + UL_GAIN_6DB, + UL_GAIN_12DB, + UL_GAIN_18DB, + UL_GAIN_24DB, +}; + +#define MT6357_DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) +#define MT6357_DL_GAIN_REG_LEFT_MASK 0x001f +#define MT6357_DL_GAIN_REG_LEFT_SHIFT 0 +#define MT6357_DL_GAIN_REG_RIGHT_MASK 0x0f80 +#define MT6357_DL_GAIN_REG_RIGHT_SHIFT 7 +#define MT6357_DL_GAIN_REG_MASK 0x0f9f + +#define MT6357_SND_SOC_ADV_MT_FMTS (\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S16_BE |\ + SNDRV_PCM_FMTBIT_U16_LE |\ + SNDRV_PCM_FMTBIT_U16_BE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_BE |\ + SNDRV_PCM_FMTBIT_U24_LE |\ + SNDRV_PCM_FMTBIT_U24_BE |\ + SNDRV_PCM_FMTBIT_S32_LE |\ + SNDRV_PCM_FMTBIT_S32_BE |\ + SNDRV_PCM_FMTBIT_U32_LE |\ + SNDRV_PCM_FMTBIT_U32_BE) + +#define MT6357_SOC_HIGH_USE_RATE (\ + SNDRV_PCM_RATE_CONTINUOUS |\ + SNDRV_PCM_RATE_8000_192000) + +/* codec private structure */ +struct mt6357_priv { + struct device *dev; + struct regmap *regmap; + bool pull_down_needed; + int hp_channel_number; +}; +#endif diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c index 76ee7e3f4d9b..b67cfad4fc32 100644 --- a/sound/soc/codecs/peb2466.c +++ b/sound/soc/codecs/peb2466.c @@ -1975,12 +1975,9 @@ static int peb2466_spi_probe(struct spi_device *spi) if (IS_ERR(peb2466->reset_gpio)) return PTR_ERR(peb2466->reset_gpio); - peb2466->mclk = devm_clk_get(&peb2466->spi->dev, "mclk"); + peb2466->mclk = devm_clk_get_enabled(&peb2466->spi->dev, "mclk"); if (IS_ERR(peb2466->mclk)) return PTR_ERR(peb2466->mclk); - ret = clk_prepare_enable(peb2466->mclk); - if (ret) - return ret; if (peb2466->reset_gpio) { gpiod_set_value_cansleep(peb2466->reset_gpio, 1); @@ -2031,17 +2028,9 @@ static int peb2466_spi_probe(struct spi_device *spi) return 0; failed: - clk_disable_unprepare(peb2466->mclk); return ret; } -static void peb2466_spi_remove(struct spi_device *spi) -{ - struct peb2466 *peb2466 = spi_get_drvdata(spi); - - clk_disable_unprepare(peb2466->mclk); -} - static const struct of_device_id peb2466_of_match[] = { { .compatible = "infineon,peb2466", }, { } @@ -2061,7 +2050,6 @@ static struct spi_driver peb2466_spi_driver = { }, .id_table = peb2466_id_table, .probe = peb2466_spi_probe, - .remove = peb2466_spi_remove, }; module_spi_driver(peb2466_spi_driver); diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 5fea600bc3a4..3c5b66357661 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -529,7 +529,7 @@ static struct platform_driver rk817_codec_driver = { .name = "rk817-codec", }, .probe = rk817_platform_probe, - .remove_new = rk817_platform_remove, + .remove = rk817_platform_remove, }; module_platform_driver(rk817_codec_driver); diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c index 83b29b441be9..e12b1e96a53a 100644 --- a/sound/soc/codecs/rt1318.c +++ b/sound/soc/codecs/rt1318.c @@ -30,7 +30,7 @@ #include "rt1318.h" -static struct reg_sequence init_list[] = { +static const struct reg_sequence init_list[] = { { 0x0000C000, 0x01}, { 0x0000F20D, 0x00}, { 0x0000F212, 0x3E}, @@ -254,7 +254,6 @@ static struct reg_sequence init_list[] = { { 0x0000C320, 0x20}, { 0x0000C203, 0x9C}, }; -#define rt1318_INIT_REG_LEN ARRAY_SIZE(init_list) static const struct reg_default rt1318_reg[] = { { 0xc000, 0x00 }, diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 2916fa77b791..f4e1ea29c265 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -91,6 +91,2027 @@ static const struct reg_sequence rt1320_blind_write[] = { { 0xd486, 0xc3 }, }; +static const struct reg_sequence rt1320_vc_blind_write[] = { + { 0xc003, 0xe0 }, + { 0xe80a, 0x01 }, + { 0xc5c3, 0xf3 }, + { 0xc057, 0x51 }, + { 0xc054, 0x35 }, + { 0xca05, 0xd6 }, + { 0xca07, 0x07 }, + { 0xca25, 0xd6 }, + { 0xca27, 0x07 }, + { 0xc604, 0x40 }, + { 0xc609, 0x40 }, + { 0xc046, 0xff }, + { 0xc045, 0xff }, + { 0xda81, 0x14 }, + { 0xda8d, 0x14 }, + { 0xc044, 0xff }, + { 0xc043, 0xff }, + { 0xc042, 0xff }, + { 0xc041, 0x7f }, + { 0xc040, 0xff }, + { 0xcc10, 0x01 }, + { 0xc700, 0xf0 }, + { 0xc701, 0x13 }, + { 0xc901, 0x09 }, + { 0xc900, 0xd0 }, + { 0xde03, 0x05 }, + { 0xdd0b, 0x0d }, + { 0xdd0a, 0xff }, + { 0xdd09, 0x0d }, + { 0xdd08, 0xff }, + { 0xc570, 0x08 }, + { 0xc086, 0x02 }, + { 0xc085, 0x7f }, + { 0xc084, 0x00 }, + { 0xc081, 0xfe }, + { 0xf084, 0x0f }, + { 0xf083, 0xff }, + { 0xf082, 0xff }, + { 0xf081, 0xff }, + { 0xf080, 0xff }, + { 0xe802, 0xf8 }, + { 0xe803, 0xbe }, + { 0xc003, 0xc0 }, + { 0xd470, 0xec }, + { 0xd471, 0x3a }, + { 0xd474, 0x11 }, + { 0xd475, 0x32 }, + { 0xd478, 0x64 }, + { 0xd479, 0x20 }, + { 0xd47a, 0x10 }, + { 0xd47c, 0xff }, + { 0xc019, 0x10 }, + { 0xd487, 0x0b }, + { 0xd487, 0x3b }, + { 0xd486, 0xc3 }, + { 0xc598, 0x04 }, + { 0xd500, 0x00 }, + { 0xd500, 0x17 }, + { 0xd600, 0x01 }, + { 0xd601, 0x02 }, + { 0xd602, 0x03 }, + { 0xd603, 0x04 }, + { 0xd64c, 0x03 }, + { 0xd64d, 0x03 }, + { 0xd64e, 0x03 }, + { 0xd64f, 0x03 }, + { 0xd650, 0x03 }, + { 0xd651, 0x03 }, + { 0xd652, 0x03 }, + { 0xd610, 0x01 }, + { 0xd608, 0x03 }, + { 0xd609, 0x00 }, +}; + +static const struct reg_sequence rt1320_vc_patch_code_write[] = { + { 0x10007000, 0x37 }, + { 0x10007001, 0x77 }, + { 0x10007002, 0x00 }, + { 0x10007003, 0x10 }, + { 0x10007004, 0xb7 }, + { 0x10007005, 0xe7 }, + { 0x10007006, 0x00 }, + { 0x10007007, 0x10 }, + { 0x10007008, 0x13 }, + { 0x10007009, 0x07 }, + { 0x1000700a, 0x87 }, + { 0x1000700b, 0x48 }, + { 0x1000700c, 0x23 }, + { 0x1000700d, 0xa6 }, + { 0x1000700e, 0xe7 }, + { 0x1000700f, 0xee }, + { 0x10007010, 0x37 }, + { 0x10007011, 0x77 }, + { 0x10007012, 0x00 }, + { 0x10007013, 0x10 }, + { 0x10007014, 0x13 }, + { 0x10007015, 0x07 }, + { 0x10007016, 0x87 }, + { 0x10007017, 0x56 }, + { 0x10007018, 0x23 }, + { 0x10007019, 0xac }, + { 0x1000701a, 0xe7 }, + { 0x1000701b, 0xde }, + { 0x1000701c, 0x37 }, + { 0x1000701d, 0x77 }, + { 0x1000701e, 0x00 }, + { 0x1000701f, 0x10 }, + { 0x10007020, 0x13 }, + { 0x10007021, 0x07 }, + { 0x10007022, 0xc7 }, + { 0x10007023, 0x5f }, + { 0x10007024, 0x23 }, + { 0x10007025, 0xae }, + { 0x10007026, 0xe7 }, + { 0x10007027, 0xdc }, + { 0x10007028, 0x37 }, + { 0x10007029, 0x87 }, + { 0x1000702a, 0x00 }, + { 0x1000702b, 0x10 }, + { 0x1000702c, 0x13 }, + { 0x1000702d, 0x07 }, + { 0x1000702e, 0xc7 }, + { 0x1000702f, 0x86 }, + { 0x10007030, 0x23 }, + { 0x10007031, 0xae }, + { 0x10007032, 0xe7 }, + { 0x10007033, 0xe6 }, + { 0x10007034, 0x37 }, + { 0x10007035, 0x77 }, + { 0x10007036, 0x00 }, + { 0x10007037, 0x10 }, + { 0x10007038, 0x13 }, + { 0x10007039, 0x07 }, + { 0x1000703a, 0x07 }, + { 0x1000703b, 0x40 }, + { 0x1000703c, 0x23 }, + { 0x1000703d, 0xa6 }, + { 0x1000703e, 0xe7 }, + { 0x1000703f, 0xe8 }, + { 0x10007040, 0x37 }, + { 0x10007041, 0x77 }, + { 0x10007042, 0x00 }, + { 0x10007043, 0x10 }, + { 0x10007044, 0x13 }, + { 0x10007045, 0x07 }, + { 0x10007046, 0xc7 }, + { 0x10007047, 0x63 }, + { 0x10007048, 0x23 }, + { 0x10007049, 0xa2 }, + { 0x1000704a, 0xe7 }, + { 0x1000704b, 0xec }, + { 0x1000704c, 0x37 }, + { 0x1000704d, 0x77 }, + { 0x1000704e, 0x00 }, + { 0x1000704f, 0x10 }, + { 0x10007050, 0x13 }, + { 0x10007051, 0x07 }, + { 0x10007052, 0x47 }, + { 0x10007053, 0x6f }, + { 0x10007054, 0x23 }, + { 0x10007055, 0xa6 }, + { 0x10007056, 0xe7 }, + { 0x10007057, 0xec }, + { 0x10007058, 0x37 }, + { 0x10007059, 0x77 }, + { 0x1000705a, 0x00 }, + { 0x1000705b, 0x10 }, + { 0x1000705c, 0x13 }, + { 0x1000705d, 0x07 }, + { 0x1000705e, 0x07 }, + { 0x1000705f, 0x44 }, + { 0x10007060, 0x23 }, + { 0x10007061, 0xa8 }, + { 0x10007062, 0xe7 }, + { 0x10007063, 0xec }, + { 0x10007064, 0x37 }, + { 0x10007065, 0x87 }, + { 0x10007066, 0x00 }, + { 0x10007067, 0x10 }, + { 0x10007068, 0x13 }, + { 0x10007069, 0x07 }, + { 0x1000706a, 0x87 }, + { 0x1000706b, 0x84 }, + { 0x1000706c, 0x23 }, + { 0x1000706d, 0xa8 }, + { 0x1000706e, 0xe7 }, + { 0x1000706f, 0xee }, + { 0x10007070, 0x37 }, + { 0x10007071, 0x87 }, + { 0x10007072, 0x00 }, + { 0x10007073, 0x10 }, + { 0x10007074, 0x13 }, + { 0x10007075, 0x07 }, + { 0x10007076, 0x47 }, + { 0x10007077, 0x97 }, + { 0x10007078, 0x23 }, + { 0x10007079, 0xaa }, + { 0x1000707a, 0xe7 }, + { 0x1000707b, 0xee }, + { 0x1000707c, 0x67 }, + { 0x1000707d, 0x80 }, + { 0x1000707e, 0x00 }, + { 0x1000707f, 0x00 }, + { 0x10007400, 0xb7 }, + { 0x10007401, 0xd6 }, + { 0x10007402, 0x00 }, + { 0x10007403, 0x00 }, + { 0x10007404, 0x83 }, + { 0x10007405, 0xc7 }, + { 0x10007406, 0x06 }, + { 0x10007407, 0x47 }, + { 0x10007408, 0x93 }, + { 0x10007409, 0xf7 }, + { 0x1000740a, 0x87 }, + { 0x1000740b, 0x00 }, + { 0x1000740c, 0x63 }, + { 0x1000740d, 0x88 }, + { 0x1000740e, 0x07 }, + { 0x1000740f, 0x02 }, + { 0x10007410, 0x03 }, + { 0x10007411, 0xc7 }, + { 0x10007412, 0x31 }, + { 0x10007413, 0x43 }, + { 0x10007414, 0x63 }, + { 0x10007415, 0x14 }, + { 0x10007416, 0x07 }, + { 0x10007417, 0x02 }, + { 0x10007418, 0x13 }, + { 0x10007419, 0x07 }, + { 0x1000741a, 0x10 }, + { 0x1000741b, 0x00 }, + { 0x1000741c, 0xa3 }, + { 0x1000741d, 0x89 }, + { 0x1000741e, 0xe1 }, + { 0x1000741f, 0x42 }, + { 0x10007420, 0x37 }, + { 0x10007421, 0xc7 }, + { 0x10007422, 0x00 }, + { 0x10007423, 0x00 }, + { 0x10007424, 0x03 }, + { 0x10007425, 0x46 }, + { 0x10007426, 0x07 }, + { 0x10007427, 0x06 }, + { 0x10007428, 0x23 }, + { 0x10007429, 0x8a }, + { 0x1000742a, 0xc1 }, + { 0x1000742b, 0x42 }, + { 0x1000742c, 0x83 }, + { 0x1000742d, 0xc7 }, + { 0x1000742e, 0x46 }, + { 0x1000742f, 0x47 }, + { 0x10007430, 0x93 }, + { 0x10007431, 0xf7 }, + { 0x10007432, 0xf7 }, + { 0x10007433, 0x0f }, + { 0x10007434, 0x23 }, + { 0x10007435, 0x00 }, + { 0x10007436, 0xf7 }, + { 0x10007437, 0x06 }, + { 0x10007438, 0x23 }, + { 0x10007439, 0x89 }, + { 0x1000743a, 0x01 }, + { 0x1000743b, 0x42 }, + { 0x1000743c, 0x67 }, + { 0x1000743d, 0x80 }, + { 0x1000743e, 0x00 }, + { 0x1000743f, 0x00 }, + { 0x10007440, 0x37 }, + { 0x10007441, 0xc7 }, + { 0x10007442, 0x00 }, + { 0x10007443, 0x00 }, + { 0x10007444, 0x83 }, + { 0x10007445, 0x27 }, + { 0x10007446, 0xc7 }, + { 0x10007447, 0x5f }, + { 0x10007448, 0x13 }, + { 0x10007449, 0x05 }, + { 0x1000744a, 0x00 }, + { 0x1000744b, 0x00 }, + { 0x1000744c, 0x23 }, + { 0x1000744d, 0xa2 }, + { 0x1000744e, 0xf1 }, + { 0x1000744f, 0x42 }, + { 0x10007450, 0xb7 }, + { 0x10007451, 0x06 }, + { 0x10007452, 0x00 }, + { 0x10007453, 0x10 }, + { 0x10007454, 0xb3 }, + { 0x10007455, 0xf7 }, + { 0x10007456, 0xd7 }, + { 0x10007457, 0x00 }, + { 0x10007458, 0x63 }, + { 0x10007459, 0x86 }, + { 0x1000745a, 0x07 }, + { 0x1000745b, 0x02 }, + { 0x1000745c, 0x83 }, + { 0x1000745d, 0x47 }, + { 0x1000745e, 0x07 }, + { 0x1000745f, 0x56 }, + { 0x10007460, 0x93 }, + { 0x10007461, 0xf7 }, + { 0x10007462, 0x87 }, + { 0x10007463, 0x01 }, + { 0x10007464, 0x63 }, + { 0x10007465, 0x80 }, + { 0x10007466, 0x07 }, + { 0x10007467, 0x02 }, + { 0x10007468, 0x83 }, + { 0x10007469, 0x47 }, + { 0x1000746a, 0x17 }, + { 0x1000746b, 0x08 }, + { 0x1000746c, 0x93 }, + { 0x1000746d, 0xf7 }, + { 0x1000746e, 0x47 }, + { 0x1000746f, 0x00 }, + { 0x10007470, 0x63 }, + { 0x10007471, 0x8a }, + { 0x10007472, 0x07 }, + { 0x10007473, 0x00 }, + { 0x10007474, 0xb7 }, + { 0x10007475, 0xc7 }, + { 0x10007476, 0xc2 }, + { 0x10007477, 0x3f }, + { 0x10007478, 0x03 }, + { 0x10007479, 0xa5 }, + { 0x1000747a, 0x47 }, + { 0x1000747b, 0xfc }, + { 0x1000747c, 0x13 }, + { 0x1000747d, 0x55 }, + { 0x1000747e, 0x25 }, + { 0x1000747f, 0x00 }, + { 0x10007480, 0x13 }, + { 0x10007481, 0x75 }, + { 0x10007482, 0x15 }, + { 0x10007483, 0x00 }, + { 0x10007484, 0x67 }, + { 0x10007485, 0x80 }, + { 0x10007486, 0x00 }, + { 0x10007487, 0x00 }, + { 0x10007488, 0x03 }, + { 0x10007489, 0xa7 }, + { 0x1000748a, 0x81 }, + { 0x1000748b, 0x57 }, + { 0x1000748c, 0x13 }, + { 0x1000748d, 0x01 }, + { 0x1000748e, 0x01 }, + { 0x1000748f, 0xff }, + { 0x10007490, 0x23 }, + { 0x10007491, 0x26 }, + { 0x10007492, 0x11 }, + { 0x10007493, 0x00 }, + { 0x10007494, 0x23 }, + { 0x10007495, 0x24 }, + { 0x10007496, 0x81 }, + { 0x10007497, 0x00 }, + { 0x10007498, 0x23 }, + { 0x10007499, 0x22 }, + { 0x1000749a, 0x91 }, + { 0x1000749b, 0x00 }, + { 0x1000749c, 0x93 }, + { 0x1000749d, 0x07 }, + { 0x1000749e, 0xa0 }, + { 0x1000749f, 0x05 }, + { 0x100074a0, 0x63 }, + { 0x100074a1, 0x14 }, + { 0x100074a2, 0xf7 }, + { 0x100074a3, 0x04 }, + { 0x100074a4, 0x37 }, + { 0x100074a5, 0x07 }, + { 0x100074a6, 0x00 }, + { 0x100074a7, 0x11 }, + { 0x100074a8, 0x83 }, + { 0x100074a9, 0x47 }, + { 0x100074aa, 0x07 }, + { 0x100074ab, 0x01 }, + { 0x100074ac, 0x13 }, + { 0x100074ad, 0x06 }, + { 0x100074ae, 0x30 }, + { 0x100074af, 0x00 }, + { 0x100074b0, 0x93 }, + { 0x100074b1, 0xf7 }, + { 0x100074b2, 0xf7 }, + { 0x100074b3, 0x0f }, + { 0x100074b4, 0x63 }, + { 0x100074b5, 0x9a }, + { 0x100074b6, 0xc7 }, + { 0x100074b7, 0x02 }, + { 0x100074b8, 0x03 }, + { 0x100074b9, 0x47 }, + { 0x100074ba, 0x87 }, + { 0x100074bb, 0x01 }, + { 0x100074bc, 0x13 }, + { 0x100074bd, 0x77 }, + { 0x100074be, 0xf7 }, + { 0x100074bf, 0x0f }, + { 0x100074c0, 0x63 }, + { 0x100074c1, 0x14 }, + { 0x100074c2, 0xf7 }, + { 0x100074c3, 0x02 }, + { 0x100074c4, 0x37 }, + { 0x100074c5, 0xd7 }, + { 0x100074c6, 0x00 }, + { 0x100074c7, 0x00 }, + { 0x100074c8, 0x83 }, + { 0x100074c9, 0x47 }, + { 0x100074ca, 0x37 }, + { 0x100074cb, 0x54 }, + { 0x100074cc, 0x93 }, + { 0x100074cd, 0xf7 }, + { 0x100074ce, 0xf7 }, + { 0x100074cf, 0x0f }, + { 0x100074d0, 0x93 }, + { 0x100074d1, 0xe7 }, + { 0x100074d2, 0x07 }, + { 0x100074d3, 0x02 }, + { 0x100074d4, 0xa3 }, + { 0x100074d5, 0x01 }, + { 0x100074d6, 0xf7 }, + { 0x100074d7, 0x54 }, + { 0x100074d8, 0x83 }, + { 0x100074d9, 0x47 }, + { 0x100074da, 0x37 }, + { 0x100074db, 0x54 }, + { 0x100074dc, 0x93 }, + { 0x100074dd, 0xf7 }, + { 0x100074de, 0xf7 }, + { 0x100074df, 0x0d }, + { 0x100074e0, 0xa3 }, + { 0x100074e1, 0x01 }, + { 0x100074e2, 0xf7 }, + { 0x100074e3, 0x54 }, + { 0x100074e4, 0x23 }, + { 0x100074e5, 0xac }, + { 0x100074e6, 0x01 }, + { 0x100074e7, 0x56 }, + { 0x100074e8, 0x37 }, + { 0x100074e9, 0xd4 }, + { 0x100074ea, 0x00 }, + { 0x100074eb, 0x00 }, + { 0x100074ec, 0x83 }, + { 0x100074ed, 0x47 }, + { 0x100074ee, 0xd4 }, + { 0x100074ef, 0x47 }, + { 0x100074f0, 0x93 }, + { 0x100074f1, 0xf7 }, + { 0x100074f2, 0x17 }, + { 0x100074f3, 0x00 }, + { 0x100074f4, 0x63 }, + { 0x100074f5, 0x80 }, + { 0x100074f6, 0x07 }, + { 0x100074f7, 0x06 }, + { 0x100074f8, 0x37 }, + { 0x100074f9, 0xd7 }, + { 0x100074fa, 0x00 }, + { 0x100074fb, 0x10 }, + { 0x100074fc, 0x83 }, + { 0x100074fd, 0x47 }, + { 0x100074fe, 0x77 }, + { 0x100074ff, 0xd9 }, + { 0x10007500, 0x93 }, + { 0x10007501, 0x87 }, + { 0x10007502, 0x17 }, + { 0x10007503, 0x00 }, + { 0x10007504, 0x93 }, + { 0x10007505, 0xf7 }, + { 0x10007506, 0xf7 }, + { 0x10007507, 0x0f }, + { 0x10007508, 0xa3 }, + { 0x10007509, 0x0b }, + { 0x1000750a, 0xf7 }, + { 0x1000750b, 0xd8 }, + { 0x1000750c, 0x03 }, + { 0x1000750d, 0x47 }, + { 0x1000750e, 0x77 }, + { 0x1000750f, 0xd9 }, + { 0x10007510, 0x83 }, + { 0x10007511, 0x47 }, + { 0x10007512, 0xc4 }, + { 0x10007513, 0x47 }, + { 0x10007514, 0x13 }, + { 0x10007515, 0x77 }, + { 0x10007516, 0xf7 }, + { 0x10007517, 0x0f }, + { 0x10007518, 0x93 }, + { 0x10007519, 0xf7 }, + { 0x1000751a, 0xf7 }, + { 0x1000751b, 0x0f }, + { 0x1000751c, 0x63 }, + { 0x1000751d, 0x6c }, + { 0x1000751e, 0xf7 }, + { 0x1000751f, 0x02 }, + { 0x10007520, 0xb7 }, + { 0x10007521, 0xf4 }, + { 0x10007522, 0x00 }, + { 0x10007523, 0x00 }, + { 0x10007524, 0x93 }, + { 0x10007525, 0x05 }, + { 0x10007526, 0x00 }, + { 0x10007527, 0x01 }, + { 0x10007528, 0x13 }, + { 0x10007529, 0x85 }, + { 0x1000752a, 0x34 }, + { 0x1000752b, 0x52 }, + { 0x1000752c, 0xef }, + { 0x1000752d, 0xa0 }, + { 0x1000752e, 0x8f }, + { 0x1000752f, 0xc6 }, + { 0x10007530, 0x93 }, + { 0x10007531, 0x05 }, + { 0x10007532, 0x00 }, + { 0x10007533, 0x00 }, + { 0x10007534, 0x13 }, + { 0x10007535, 0x85 }, + { 0x10007536, 0x54 }, + { 0x10007537, 0x10 }, + { 0x10007538, 0xef }, + { 0x10007539, 0xa0 }, + { 0x1000753a, 0xcf }, + { 0x1000753b, 0xc5 }, + { 0x1000753c, 0x93 }, + { 0x1000753d, 0x05 }, + { 0x1000753e, 0x00 }, + { 0x1000753f, 0x00 }, + { 0x10007540, 0x13 }, + { 0x10007541, 0x85 }, + { 0x10007542, 0x74 }, + { 0x10007543, 0x10 }, + { 0x10007544, 0xef }, + { 0x10007545, 0xa0 }, + { 0x10007546, 0x0f }, + { 0x10007547, 0xc5 }, + { 0x10007548, 0x83 }, + { 0x10007549, 0x47 }, + { 0x1000754a, 0xd4 }, + { 0x1000754b, 0x47 }, + { 0x1000754c, 0x93 }, + { 0x1000754d, 0xf7 }, + { 0x1000754e, 0xe7 }, + { 0x1000754f, 0x0f }, + { 0x10007550, 0xa3 }, + { 0x10007551, 0x0e }, + { 0x10007552, 0xf4 }, + { 0x10007553, 0x46 }, + { 0x10007554, 0x83 }, + { 0x10007555, 0x20 }, + { 0x10007556, 0xc1 }, + { 0x10007557, 0x00 }, + { 0x10007558, 0x03 }, + { 0x10007559, 0x24 }, + { 0x1000755a, 0x81 }, + { 0x1000755b, 0x00 }, + { 0x1000755c, 0x83 }, + { 0x1000755d, 0x24 }, + { 0x1000755e, 0x41 }, + { 0x1000755f, 0x00 }, + { 0x10007560, 0x13 }, + { 0x10007561, 0x01 }, + { 0x10007562, 0x01 }, + { 0x10007563, 0x01 }, + { 0x10007564, 0x67 }, + { 0x10007565, 0x80 }, + { 0x10007566, 0x00 }, + { 0x10007567, 0x00 }, + { 0x10007568, 0x13 }, + { 0x10007569, 0x01 }, + { 0x1000756a, 0x01 }, + { 0x1000756b, 0xff }, + { 0x1000756c, 0x23 }, + { 0x1000756d, 0x24 }, + { 0x1000756e, 0x81 }, + { 0x1000756f, 0x00 }, + { 0x10007570, 0x23 }, + { 0x10007571, 0x26 }, + { 0x10007572, 0x11 }, + { 0x10007573, 0x00 }, + { 0x10007574, 0x23 }, + { 0x10007575, 0x22 }, + { 0x10007576, 0x91 }, + { 0x10007577, 0x00 }, + { 0x10007578, 0x37 }, + { 0x10007579, 0xd4 }, + { 0x1000757a, 0x00 }, + { 0x1000757b, 0x00 }, + { 0x1000757c, 0x83 }, + { 0x1000757d, 0x47 }, + { 0x1000757e, 0x04 }, + { 0x1000757f, 0x54 }, + { 0x10007580, 0x93 }, + { 0x10007581, 0x97 }, + { 0x10007582, 0x87 }, + { 0x10007583, 0x01 }, + { 0x10007584, 0x93 }, + { 0x10007585, 0xd7 }, + { 0x10007586, 0x87 }, + { 0x10007587, 0x41 }, + { 0x10007588, 0x63 }, + { 0x10007589, 0xd0 }, + { 0x1000758a, 0x07 }, + { 0x1000758b, 0x06 }, + { 0x1000758c, 0xb7 }, + { 0x1000758d, 0xf4 }, + { 0x1000758e, 0x00 }, + { 0x1000758f, 0x00 }, + { 0x10007590, 0x93 }, + { 0x10007591, 0x05 }, + { 0x10007592, 0x60 }, + { 0x10007593, 0x01 }, + { 0x10007594, 0x13 }, + { 0x10007595, 0x85 }, + { 0x10007596, 0x34 }, + { 0x10007597, 0x52 }, + { 0x10007598, 0xef }, + { 0x10007599, 0xa0 }, + { 0x1000759a, 0xcf }, + { 0x1000759b, 0xbf }, + { 0x1000759c, 0x93 }, + { 0x1000759d, 0x05 }, + { 0x1000759e, 0x00 }, + { 0x1000759f, 0x04 }, + { 0x100075a0, 0x13 }, + { 0x100075a1, 0x85 }, + { 0x100075a2, 0x54 }, + { 0x100075a3, 0x10 }, + { 0x100075a4, 0xef }, + { 0x100075a5, 0xa0 }, + { 0x100075a6, 0x0f }, + { 0x100075a7, 0xbf }, + { 0x100075a8, 0x93 }, + { 0x100075a9, 0x05 }, + { 0x100075aa, 0x00 }, + { 0x100075ab, 0x04 }, + { 0x100075ac, 0x13 }, + { 0x100075ad, 0x85 }, + { 0x100075ae, 0x74 }, + { 0x100075af, 0x10 }, + { 0x100075b0, 0xef }, + { 0x100075b1, 0xa0 }, + { 0x100075b2, 0x4f }, + { 0x100075b3, 0xbe }, + { 0x100075b4, 0x83 }, + { 0x100075b5, 0x47 }, + { 0x100075b6, 0xd4 }, + { 0x100075b7, 0x47 }, + { 0x100075b8, 0x37 }, + { 0x100075b9, 0xd7 }, + { 0x100075ba, 0x00 }, + { 0x100075bb, 0x10 }, + { 0x100075bc, 0x93 }, + { 0x100075bd, 0xf7 }, + { 0x100075be, 0xf7 }, + { 0x100075bf, 0x0f }, + { 0x100075c0, 0x93 }, + { 0x100075c1, 0xe7 }, + { 0x100075c2, 0x17 }, + { 0x100075c3, 0x00 }, + { 0x100075c4, 0xa3 }, + { 0x100075c5, 0x0e }, + { 0x100075c6, 0xf4 }, + { 0x100075c7, 0x46 }, + { 0x100075c8, 0xa3 }, + { 0x100075c9, 0x0b }, + { 0x100075ca, 0x07 }, + { 0x100075cb, 0xd8 }, + { 0x100075cc, 0x83 }, + { 0x100075cd, 0x47 }, + { 0x100075ce, 0x87 }, + { 0x100075cf, 0xd9 }, + { 0x100075d0, 0x93 }, + { 0x100075d1, 0x87 }, + { 0x100075d2, 0x17 }, + { 0x100075d3, 0x00 }, + { 0x100075d4, 0x93 }, + { 0x100075d5, 0xf7 }, + { 0x100075d6, 0xf7 }, + { 0x100075d7, 0x0f }, + { 0x100075d8, 0x23 }, + { 0x100075d9, 0x0c }, + { 0x100075da, 0xf7 }, + { 0x100075db, 0xd8 }, + { 0x100075dc, 0x83 }, + { 0x100075dd, 0x47 }, + { 0x100075de, 0x04 }, + { 0x100075df, 0x54 }, + { 0x100075e0, 0x93 }, + { 0x100075e1, 0xf7 }, + { 0x100075e2, 0xf7 }, + { 0x100075e3, 0x07 }, + { 0x100075e4, 0x23 }, + { 0x100075e5, 0x00 }, + { 0x100075e6, 0xf4 }, + { 0x100075e7, 0x54 }, + { 0x100075e8, 0x83 }, + { 0x100075e9, 0x20 }, + { 0x100075ea, 0xc1 }, + { 0x100075eb, 0x00 }, + { 0x100075ec, 0x03 }, + { 0x100075ed, 0x24 }, + { 0x100075ee, 0x81 }, + { 0x100075ef, 0x00 }, + { 0x100075f0, 0x83 }, + { 0x100075f1, 0x24 }, + { 0x100075f2, 0x41 }, + { 0x100075f3, 0x00 }, + { 0x100075f4, 0x13 }, + { 0x100075f5, 0x01 }, + { 0x100075f6, 0x01 }, + { 0x100075f7, 0x01 }, + { 0x100075f8, 0x67 }, + { 0x100075f9, 0x80 }, + { 0x100075fa, 0x00 }, + { 0x100075fb, 0x00 }, + { 0x100075fc, 0x13 }, + { 0x100075fd, 0x01 }, + { 0x100075fe, 0x01 }, + { 0x100075ff, 0xff }, + { 0x10007600, 0x23 }, + { 0x10007601, 0x24 }, + { 0x10007602, 0x81 }, + { 0x10007603, 0x00 }, + { 0x10007604, 0x37 }, + { 0x10007605, 0xd4 }, + { 0x10007606, 0x00 }, + { 0x10007607, 0x00 }, + { 0x10007608, 0x83 }, + { 0x10007609, 0x27 }, + { 0x1000760a, 0x04 }, + { 0x1000760b, 0x53 }, + { 0x1000760c, 0x23 }, + { 0x1000760d, 0x22 }, + { 0x1000760e, 0x91 }, + { 0x1000760f, 0x00 }, + { 0x10007610, 0xb7 }, + { 0x10007611, 0x04 }, + { 0x10007612, 0x00 }, + { 0x10007613, 0x40 }, + { 0x10007614, 0x23 }, + { 0x10007615, 0x26 }, + { 0x10007616, 0x11 }, + { 0x10007617, 0x00 }, + { 0x10007618, 0xb3 }, + { 0x10007619, 0xf7 }, + { 0x1000761a, 0x97 }, + { 0x1000761b, 0x00 }, + { 0x1000761c, 0x63 }, + { 0x1000761d, 0x86 }, + { 0x1000761e, 0x07 }, + { 0x1000761f, 0x00 }, + { 0x10007620, 0xef }, + { 0x10007621, 0xd0 }, + { 0x10007622, 0x5f }, + { 0x10007623, 0xc2 }, + { 0x10007624, 0x23 }, + { 0x10007625, 0x28 }, + { 0x10007626, 0x94 }, + { 0x10007627, 0x52 }, + { 0x10007628, 0x83 }, + { 0x10007629, 0x20 }, + { 0x1000762a, 0xc1 }, + { 0x1000762b, 0x00 }, + { 0x1000762c, 0x03 }, + { 0x1000762d, 0x24 }, + { 0x1000762e, 0x81 }, + { 0x1000762f, 0x00 }, + { 0x10007630, 0x83 }, + { 0x10007631, 0x24 }, + { 0x10007632, 0x41 }, + { 0x10007633, 0x00 }, + { 0x10007634, 0x13 }, + { 0x10007635, 0x01 }, + { 0x10007636, 0x01 }, + { 0x10007637, 0x01 }, + { 0x10007638, 0x67 }, + { 0x10007639, 0x80 }, + { 0x1000763a, 0x00 }, + { 0x1000763b, 0x00 }, + { 0x1000763c, 0x37 }, + { 0x1000763d, 0xc7 }, + { 0x1000763e, 0x00 }, + { 0x1000763f, 0x00 }, + { 0x10007640, 0x83 }, + { 0x10007641, 0x27 }, + { 0x10007642, 0xc7 }, + { 0x10007643, 0x5f }, + { 0x10007644, 0x23 }, + { 0x10007645, 0xa2 }, + { 0x10007646, 0xf1 }, + { 0x10007647, 0x42 }, + { 0x10007648, 0xb7 }, + { 0x10007649, 0x06 }, + { 0x1000764a, 0x00 }, + { 0x1000764b, 0x10 }, + { 0x1000764c, 0xb3 }, + { 0x1000764d, 0xf7 }, + { 0x1000764e, 0xd7 }, + { 0x1000764f, 0x00 }, + { 0x10007650, 0x63 }, + { 0x10007651, 0x80 }, + { 0x10007652, 0x07 }, + { 0x10007653, 0x0a }, + { 0x10007654, 0x83 }, + { 0x10007655, 0x47 }, + { 0x10007656, 0x07 }, + { 0x10007657, 0x56 }, + { 0x10007658, 0x93 }, + { 0x10007659, 0xf7 }, + { 0x1000765a, 0x87 }, + { 0x1000765b, 0x01 }, + { 0x1000765c, 0x63 }, + { 0x1000765d, 0x8a }, + { 0x1000765e, 0x07 }, + { 0x1000765f, 0x08 }, + { 0x10007660, 0x83 }, + { 0x10007661, 0x47 }, + { 0x10007662, 0x17 }, + { 0x10007663, 0x08 }, + { 0x10007664, 0x93 }, + { 0x10007665, 0xf7 }, + { 0x10007666, 0x47 }, + { 0x10007667, 0x00 }, + { 0x10007668, 0x63 }, + { 0x10007669, 0x84 }, + { 0x1000766a, 0x07 }, + { 0x1000766b, 0x08 }, + { 0x1000766c, 0x13 }, + { 0x1000766d, 0x01 }, + { 0x1000766e, 0x01 }, + { 0x1000766f, 0xff }, + { 0x10007670, 0x23 }, + { 0x10007671, 0x26 }, + { 0x10007672, 0x11 }, + { 0x10007673, 0x00 }, + { 0x10007674, 0xb7 }, + { 0x10007675, 0xc7 }, + { 0x10007676, 0xc2 }, + { 0x10007677, 0x3f }, + { 0x10007678, 0x03 }, + { 0x10007679, 0xa7 }, + { 0x1000767a, 0x07 }, + { 0x1000767b, 0xfc }, + { 0x1000767c, 0x63 }, + { 0x1000767d, 0x10 }, + { 0x1000767e, 0x05 }, + { 0x1000767f, 0x06 }, + { 0x10007680, 0x13 }, + { 0x10007681, 0x67 }, + { 0x10007682, 0x07 }, + { 0x10007683, 0x20 }, + { 0x10007684, 0x23 }, + { 0x10007685, 0xa0 }, + { 0x10007686, 0xe7 }, + { 0x10007687, 0xfc }, + { 0x10007688, 0x03 }, + { 0x10007689, 0xa7 }, + { 0x1000768a, 0x07 }, + { 0x1000768b, 0xfc }, + { 0x1000768c, 0x13 }, + { 0x1000768d, 0x67 }, + { 0x1000768e, 0x07 }, + { 0x1000768f, 0x40 }, + { 0x10007690, 0x23 }, + { 0x10007691, 0xa0 }, + { 0x10007692, 0xe7 }, + { 0x10007693, 0xfc }, + { 0x10007694, 0x37 }, + { 0x10007695, 0xc7 }, + { 0x10007696, 0xc2 }, + { 0x10007697, 0x3f }, + { 0x10007698, 0x83 }, + { 0x10007699, 0x27 }, + { 0x1000769a, 0x07 }, + { 0x1000769b, 0xfc }, + { 0x1000769c, 0x13 }, + { 0x1000769d, 0x75 }, + { 0x1000769e, 0x15 }, + { 0x1000769f, 0x00 }, + { 0x100076a0, 0x13 }, + { 0x100076a1, 0x15 }, + { 0x100076a2, 0x85 }, + { 0x100076a3, 0x00 }, + { 0x100076a4, 0x93 }, + { 0x100076a5, 0xf7 }, + { 0x100076a6, 0xf7 }, + { 0x100076a7, 0xef }, + { 0x100076a8, 0x33 }, + { 0x100076a9, 0xe5 }, + { 0x100076aa, 0xa7 }, + { 0x100076ab, 0x00 }, + { 0x100076ac, 0x23 }, + { 0x100076ad, 0x20 }, + { 0x100076ae, 0xa7 }, + { 0x100076af, 0xfc }, + { 0x100076b0, 0x93 }, + { 0x100076b1, 0x05 }, + { 0x100076b2, 0x00 }, + { 0x100076b3, 0x00 }, + { 0x100076b4, 0x13 }, + { 0x100076b5, 0x05 }, + { 0x100076b6, 0xa0 }, + { 0x100076b7, 0x00 }, + { 0x100076b8, 0xef }, + { 0x100076b9, 0xe0 }, + { 0x100076ba, 0xcf }, + { 0x100076bb, 0xb6 }, + { 0x100076bc, 0x37 }, + { 0x100076bd, 0xf7 }, + { 0x100076be, 0x00 }, + { 0x100076bf, 0x00 }, + { 0x100076c0, 0x83 }, + { 0x100076c1, 0x47 }, + { 0x100076c2, 0x57 }, + { 0x100076c3, 0x01 }, + { 0x100076c4, 0x93 }, + { 0x100076c5, 0xf7 }, + { 0x100076c6, 0xf7 }, + { 0x100076c7, 0x0f }, + { 0x100076c8, 0x93 }, + { 0x100076c9, 0xe7 }, + { 0x100076ca, 0x47 }, + { 0x100076cb, 0x00 }, + { 0x100076cc, 0xa3 }, + { 0x100076cd, 0x0a }, + { 0x100076ce, 0xf7 }, + { 0x100076cf, 0x00 }, + { 0x100076d0, 0x83 }, + { 0x100076d1, 0x20 }, + { 0x100076d2, 0xc1 }, + { 0x100076d3, 0x00 }, + { 0x100076d4, 0x13 }, + { 0x100076d5, 0x01 }, + { 0x100076d6, 0x01 }, + { 0x100076d7, 0x01 }, + { 0x100076d8, 0x67 }, + { 0x100076d9, 0x80 }, + { 0x100076da, 0x00 }, + { 0x100076db, 0x00 }, + { 0x100076dc, 0x13 }, + { 0x100076dd, 0x77 }, + { 0x100076de, 0xf7 }, + { 0x100076df, 0xdf }, + { 0x100076e0, 0x23 }, + { 0x100076e1, 0xa0 }, + { 0x100076e2, 0xe7 }, + { 0x100076e3, 0xfc }, + { 0x100076e4, 0x03 }, + { 0x100076e5, 0xa7 }, + { 0x100076e6, 0x07 }, + { 0x100076e7, 0xfc }, + { 0x100076e8, 0x13 }, + { 0x100076e9, 0x77 }, + { 0x100076ea, 0xf7 }, + { 0x100076eb, 0xbf }, + { 0x100076ec, 0x6f }, + { 0x100076ed, 0xf0 }, + { 0x100076ee, 0x5f }, + { 0x100076ef, 0xfa }, + { 0x100076f0, 0x67 }, + { 0x100076f1, 0x80 }, + { 0x100076f2, 0x00 }, + { 0x100076f3, 0x00 }, + { 0x100076f4, 0xb7 }, + { 0x100076f5, 0xc7 }, + { 0x100076f6, 0x00 }, + { 0x100076f7, 0x00 }, + { 0x100076f8, 0x03 }, + { 0x100076f9, 0xc7 }, + { 0x100076fa, 0x87 }, + { 0x100076fb, 0x59 }, + { 0x100076fc, 0x13 }, + { 0x100076fd, 0x77 }, + { 0x100076fe, 0xf7 }, + { 0x100076ff, 0x0f }, + { 0x10007700, 0x13 }, + { 0x10007701, 0x67 }, + { 0x10007702, 0x17 }, + { 0x10007703, 0x00 }, + { 0x10007704, 0x23 }, + { 0x10007705, 0x8c }, + { 0x10007706, 0xe7 }, + { 0x10007707, 0x58 }, + { 0x10007708, 0x03 }, + { 0x10007709, 0xc7 }, + { 0x1000770a, 0x77 }, + { 0x1000770b, 0x04 }, + { 0x1000770c, 0x13 }, + { 0x1000770d, 0x17 }, + { 0x1000770e, 0x87 }, + { 0x1000770f, 0x01 }, + { 0x10007710, 0x13 }, + { 0x10007711, 0x57 }, + { 0x10007712, 0x87 }, + { 0x10007713, 0x41 }, + { 0x10007714, 0x63 }, + { 0x10007715, 0x58 }, + { 0x10007716, 0x07 }, + { 0x10007717, 0x12 }, + { 0x10007718, 0x37 }, + { 0x10007719, 0xd7 }, + { 0x1000771a, 0x00 }, + { 0x1000771b, 0x00 }, + { 0x1000771c, 0x83 }, + { 0x1000771d, 0x26 }, + { 0x1000771e, 0x87 }, + { 0x1000771f, 0x53 }, + { 0x10007720, 0x37 }, + { 0x10007721, 0x06 }, + { 0x10007722, 0x00 }, + { 0x10007723, 0x40 }, + { 0x10007724, 0x93 }, + { 0x10007725, 0x05 }, + { 0x10007726, 0x80 }, + { 0x10007727, 0x01 }, + { 0x10007728, 0xb3 }, + { 0x10007729, 0xe6 }, + { 0x1000772a, 0xc6 }, + { 0x1000772b, 0x00 }, + { 0x1000772c, 0x23 }, + { 0x1000772d, 0x2c }, + { 0x1000772e, 0xd7 }, + { 0x1000772f, 0x52 }, + { 0x10007730, 0x83 }, + { 0x10007731, 0xc6 }, + { 0x10007732, 0x07 }, + { 0x10007733, 0x56 }, + { 0x10007734, 0x93 }, + { 0x10007735, 0xf6 }, + { 0x10007736, 0xf6 }, + { 0x10007737, 0x0f }, + { 0x10007738, 0x63 }, + { 0x10007739, 0x9c }, + { 0x1000773a, 0xb6 }, + { 0x1000773b, 0x0e }, + { 0x1000773c, 0x83 }, + { 0x1000773d, 0x27 }, + { 0x1000773e, 0x87 }, + { 0x1000773f, 0x53 }, + { 0x10007740, 0xb3 }, + { 0x10007741, 0xf7 }, + { 0x10007742, 0xc7 }, + { 0x10007743, 0x00 }, + { 0x10007744, 0x63 }, + { 0x10007745, 0x80 }, + { 0x10007746, 0x07 }, + { 0x10007747, 0x10 }, + { 0x10007748, 0x13 }, + { 0x10007749, 0x01 }, + { 0x1000774a, 0x01 }, + { 0x1000774b, 0xff }, + { 0x1000774c, 0x23 }, + { 0x1000774d, 0x24 }, + { 0x1000774e, 0x81 }, + { 0x1000774f, 0x00 }, + { 0x10007750, 0x83 }, + { 0x10007751, 0xa7 }, + { 0x10007752, 0x41 }, + { 0x10007753, 0x58 }, + { 0x10007754, 0x23 }, + { 0x10007755, 0x26 }, + { 0x10007756, 0x11 }, + { 0x10007757, 0x00 }, + { 0x10007758, 0x63 }, + { 0x10007759, 0x94 }, + { 0x1000775a, 0x07 }, + { 0x1000775b, 0x0c }, + { 0x1000775c, 0x83 }, + { 0x1000775d, 0x27 }, + { 0x1000775e, 0x07 }, + { 0x1000775f, 0x53 }, + { 0x10007760, 0x03 }, + { 0x10007761, 0xc6 }, + { 0x10007762, 0xb1 }, + { 0x10007763, 0x42 }, + { 0x10007764, 0x93 }, + { 0x10007765, 0xd7 }, + { 0x10007766, 0xe7 }, + { 0x10007767, 0x01 }, + { 0x10007768, 0x93 }, + { 0x10007769, 0xf7 }, + { 0x1000776a, 0x17 }, + { 0x1000776b, 0x00 }, + { 0x1000776c, 0x93 }, + { 0x1000776d, 0x06 }, + { 0x1000776e, 0x10 }, + { 0x1000776f, 0x00 }, + { 0x10007770, 0x63 }, + { 0x10007771, 0x14 }, + { 0x10007772, 0x06 }, + { 0x10007773, 0x00 }, + { 0x10007774, 0xb3 }, + { 0x10007775, 0x86 }, + { 0x10007776, 0xf6 }, + { 0x10007777, 0x40 }, + { 0x10007778, 0xa3 }, + { 0x10007779, 0x85 }, + { 0x1000777a, 0xd1 }, + { 0x1000777b, 0x42 }, + { 0x1000777c, 0x03 }, + { 0x1000777d, 0xc6 }, + { 0x1000777e, 0xa1 }, + { 0x1000777f, 0x42 }, + { 0x10007780, 0x93 }, + { 0x10007781, 0x06 }, + { 0x10007782, 0x10 }, + { 0x10007783, 0x00 }, + { 0x10007784, 0x63 }, + { 0x10007785, 0x14 }, + { 0x10007786, 0x06 }, + { 0x10007787, 0x00 }, + { 0x10007788, 0xb3 }, + { 0x10007789, 0x86 }, + { 0x1000778a, 0xf6 }, + { 0x1000778b, 0x40 }, + { 0x1000778c, 0x23 }, + { 0x1000778d, 0x85 }, + { 0x1000778e, 0xd1 }, + { 0x1000778f, 0x42 }, + { 0x10007790, 0x03 }, + { 0x10007791, 0xc6 }, + { 0x10007792, 0x91 }, + { 0x10007793, 0x42 }, + { 0x10007794, 0x93 }, + { 0x10007795, 0x06 }, + { 0x10007796, 0x10 }, + { 0x10007797, 0x00 }, + { 0x10007798, 0x63 }, + { 0x10007799, 0x14 }, + { 0x1000779a, 0x06 }, + { 0x1000779b, 0x00 }, + { 0x1000779c, 0xb3 }, + { 0x1000779d, 0x86 }, + { 0x1000779e, 0xf6 }, + { 0x1000779f, 0x40 }, + { 0x100077a0, 0xa3 }, + { 0x100077a1, 0x84 }, + { 0x100077a2, 0xd1 }, + { 0x100077a3, 0x42 }, + { 0x100077a4, 0x03 }, + { 0x100077a5, 0xc6 }, + { 0x100077a6, 0x81 }, + { 0x100077a7, 0x42 }, + { 0x100077a8, 0x93 }, + { 0x100077a9, 0x06 }, + { 0x100077aa, 0x10 }, + { 0x100077ab, 0x00 }, + { 0x100077ac, 0x63 }, + { 0x100077ad, 0x14 }, + { 0x100077ae, 0x06 }, + { 0x100077af, 0x00 }, + { 0x100077b0, 0xb3 }, + { 0x100077b1, 0x86 }, + { 0x100077b2, 0xf6 }, + { 0x100077b3, 0x40 }, + { 0x100077b4, 0x23 }, + { 0x100077b5, 0x84 }, + { 0x100077b6, 0xd1 }, + { 0x100077b7, 0x42 }, + { 0x100077b8, 0xb7 }, + { 0x100077b9, 0xd7 }, + { 0x100077ba, 0x00 }, + { 0x100077bb, 0x00 }, + { 0x100077bc, 0x83 }, + { 0x100077bd, 0xa7 }, + { 0x100077be, 0x07 }, + { 0x100077bf, 0x53 }, + { 0x100077c0, 0x37 }, + { 0x100077c1, 0x07 }, + { 0x100077c2, 0x00 }, + { 0x100077c3, 0x40 }, + { 0x100077c4, 0xb3 }, + { 0x100077c5, 0xf7 }, + { 0x100077c6, 0xe7 }, + { 0x100077c7, 0x00 }, + { 0x100077c8, 0x63 }, + { 0x100077c9, 0x8c }, + { 0x100077ca, 0x07 }, + { 0x100077cb, 0x04 }, + { 0x100077cc, 0xb7 }, + { 0x100077cd, 0x47 }, + { 0x100077ce, 0x0f }, + { 0x100077cf, 0x00 }, + { 0x100077d0, 0x93 }, + { 0x100077d1, 0x87 }, + { 0x100077d2, 0x17 }, + { 0x100077d3, 0x24 }, + { 0x100077d4, 0xb7 }, + { 0x100077d5, 0xf6 }, + { 0x100077d6, 0x00 }, + { 0x100077d7, 0x00 }, + { 0x100077d8, 0x03 }, + { 0x100077d9, 0xc7 }, + { 0x100077da, 0xf6 }, + { 0x100077db, 0x83 }, + { 0x100077dc, 0x13 }, + { 0x100077dd, 0x77 }, + { 0x100077de, 0x07 }, + { 0x100077df, 0x04 }, + { 0x100077e0, 0x63 }, + { 0x100077e1, 0x16 }, + { 0x100077e2, 0x07 }, + { 0x100077e3, 0x00 }, + { 0x100077e4, 0x93 }, + { 0x100077e5, 0x87 }, + { 0x100077e6, 0xf7 }, + { 0x100077e7, 0xff }, + { 0x100077e8, 0xe3 }, + { 0x100077e9, 0x98 }, + { 0x100077ea, 0x07 }, + { 0x100077eb, 0xfe }, + { 0x100077ec, 0x13 }, + { 0x100077ed, 0x05 }, + { 0x100077ee, 0x80 }, + { 0x100077ef, 0x3e }, + { 0x100077f0, 0x93 }, + { 0x100077f1, 0x05 }, + { 0x100077f2, 0x00 }, + { 0x100077f3, 0x00 }, + { 0x100077f4, 0xef }, + { 0x100077f5, 0xe0 }, + { 0x100077f6, 0x0f }, + { 0x100077f7, 0xa3 }, + { 0x100077f8, 0x37 }, + { 0x100077f9, 0xf7 }, + { 0x100077fa, 0x00 }, + { 0x100077fb, 0x00 }, + { 0x100077fc, 0x83 }, + { 0x100077fd, 0x47 }, + { 0x100077fe, 0xb7 }, + { 0x100077ff, 0x80 }, + { 0x10007800, 0x93 }, + { 0x10007801, 0xe7 }, + { 0x10007802, 0x07 }, + { 0x10007803, 0xf8 }, + { 0x10007804, 0x93 }, + { 0x10007805, 0xf7 }, + { 0x10007806, 0xf7 }, + { 0x10007807, 0x0f }, + { 0x10007808, 0xa3 }, + { 0x10007809, 0x05 }, + { 0x1000780a, 0xf7 }, + { 0x1000780b, 0x80 }, + { 0x1000780c, 0xb7 }, + { 0x1000780d, 0xd7 }, + { 0x1000780e, 0x00 }, + { 0x1000780f, 0x00 }, + { 0x10007810, 0x37 }, + { 0x10007811, 0x07 }, + { 0x10007812, 0x00 }, + { 0x10007813, 0x40 }, + { 0x10007814, 0x23 }, + { 0x10007815, 0xa8 }, + { 0x10007816, 0xe7 }, + { 0x10007817, 0x52 }, + { 0x10007818, 0x93 }, + { 0x10007819, 0x07 }, + { 0x1000781a, 0x10 }, + { 0x1000781b, 0x00 }, + { 0x1000781c, 0x23 }, + { 0x1000781d, 0xa2 }, + { 0x1000781e, 0xf1 }, + { 0x1000781f, 0x58 }, + { 0x10007820, 0x83 }, + { 0x10007821, 0x20 }, + { 0x10007822, 0xc1 }, + { 0x10007823, 0x00 }, + { 0x10007824, 0x03 }, + { 0x10007825, 0x24 }, + { 0x10007826, 0x81 }, + { 0x10007827, 0x00 }, + { 0x10007828, 0x13 }, + { 0x10007829, 0x01 }, + { 0x1000782a, 0x01 }, + { 0x1000782b, 0x01 }, + { 0x1000782c, 0x67 }, + { 0x1000782d, 0x80 }, + { 0x1000782e, 0x00 }, + { 0x1000782f, 0x00 }, + { 0x10007830, 0x83 }, + { 0x10007831, 0xc7 }, + { 0x10007832, 0x07 }, + { 0x10007833, 0x56 }, + { 0x10007834, 0x93 }, + { 0x10007835, 0xf7 }, + { 0x10007836, 0xf7 }, + { 0x10007837, 0x0f }, + { 0x10007838, 0x63 }, + { 0x10007839, 0x96 }, + { 0x1000783a, 0x07 }, + { 0x1000783b, 0x00 }, + { 0x1000783c, 0x23 }, + { 0x1000783d, 0xa2 }, + { 0x1000783e, 0x01 }, + { 0x1000783f, 0x58 }, + { 0x10007840, 0x67 }, + { 0x10007841, 0x80 }, + { 0x10007842, 0x00 }, + { 0x10007843, 0x00 }, + { 0x10007844, 0x67 }, + { 0x10007845, 0x80 }, + { 0x10007846, 0x00 }, + { 0x10007847, 0x00 }, + { 0x10007848, 0xb7 }, + { 0x10007849, 0xc7 }, + { 0x1000784a, 0x00 }, + { 0x1000784b, 0x00 }, + { 0x1000784c, 0x83 }, + { 0x1000784d, 0xc7 }, + { 0x1000784e, 0x07 }, + { 0x1000784f, 0x56 }, + { 0x10007850, 0x13 }, + { 0x10007851, 0x07 }, + { 0x10007852, 0x80 }, + { 0x10007853, 0x01 }, + { 0x10007854, 0x93 }, + { 0x10007855, 0xf7 }, + { 0x10007856, 0xf7 }, + { 0x10007857, 0x0f }, + { 0x10007858, 0x63 }, + { 0x10007859, 0x98 }, + { 0x1000785a, 0xe7 }, + { 0x1000785b, 0x00 }, + { 0x1000785c, 0x13 }, + { 0x1000785d, 0x05 }, + { 0x1000785e, 0x00 }, + { 0x1000785f, 0x7d }, + { 0x10007860, 0x93 }, + { 0x10007861, 0x05 }, + { 0x10007862, 0x00 }, + { 0x10007863, 0x00 }, + { 0x10007864, 0x6f }, + { 0x10007865, 0xe0 }, + { 0x10007866, 0x0f }, + { 0x10007867, 0x9c }, + { 0x10007868, 0x67 }, + { 0x10007869, 0x80 }, + { 0x1000786a, 0x00 }, + { 0x1000786b, 0x00 }, + { 0x1000786c, 0x13 }, + { 0x1000786d, 0x01 }, + { 0x1000786e, 0x01 }, + { 0x1000786f, 0xff }, + { 0x10007870, 0x23 }, + { 0x10007871, 0x26 }, + { 0x10007872, 0x11 }, + { 0x10007873, 0x00 }, + { 0x10007874, 0x23 }, + { 0x10007875, 0x24 }, + { 0x10007876, 0x81 }, + { 0x10007877, 0x00 }, + { 0x10007878, 0xef }, + { 0x10007879, 0xd0 }, + { 0x1000787a, 0x4f }, + { 0x1000787b, 0x91 }, + { 0x1000787c, 0x83 }, + { 0x1000787d, 0xc7 }, + { 0x1000787e, 0x81 }, + { 0x1000787f, 0x41 }, + { 0x10007880, 0x63 }, + { 0x10007881, 0x84 }, + { 0x10007882, 0x07 }, + { 0x10007883, 0x08 }, + { 0x10007884, 0xb7 }, + { 0x10007885, 0xd7 }, + { 0x10007886, 0x00 }, + { 0x10007887, 0x00 }, + { 0x10007888, 0x83 }, + { 0x10007889, 0xc7 }, + { 0x1000788a, 0x07 }, + { 0x1000788b, 0x47 }, + { 0x1000788c, 0x93 }, + { 0x1000788d, 0xf7 }, + { 0x1000788e, 0x07 }, + { 0x1000788f, 0x02 }, + { 0x10007890, 0x63 }, + { 0x10007891, 0x8a }, + { 0x10007892, 0x07 }, + { 0x10007893, 0x04 }, + { 0x10007894, 0x83 }, + { 0x10007895, 0xc7 }, + { 0x10007896, 0x11 }, + { 0x10007897, 0x44 }, + { 0x10007898, 0x93 }, + { 0x10007899, 0xf7 }, + { 0x1000789a, 0xd7 }, + { 0x1000789b, 0x0f }, + { 0x1000789c, 0x63 }, + { 0x1000789d, 0x90 }, + { 0x1000789e, 0x07 }, + { 0x1000789f, 0x02 }, + { 0x100078a0, 0x03 }, + { 0x100078a1, 0xc7 }, + { 0x100078a2, 0xd1 }, + { 0x100078a3, 0x58 }, + { 0x100078a4, 0xb7 }, + { 0x100078a5, 0x07 }, + { 0x100078a6, 0x00 }, + { 0x100078a7, 0x11 }, + { 0x100078a8, 0x23 }, + { 0x100078a9, 0x88 }, + { 0x100078aa, 0xe7 }, + { 0x100078ab, 0x00 }, + { 0x100078ac, 0x23 }, + { 0x100078ad, 0x88 }, + { 0x100078ae, 0xe7 }, + { 0x100078af, 0x20 }, + { 0x100078b0, 0x03 }, + { 0x100078b1, 0xc7 }, + { 0x100078b2, 0xc1 }, + { 0x100078b3, 0x58 }, + { 0x100078b4, 0x23 }, + { 0x100078b5, 0x8c }, + { 0x100078b6, 0xe7 }, + { 0x100078b7, 0x00 }, + { 0x100078b8, 0x6f }, + { 0x100078b9, 0x00 }, + { 0x100078ba, 0x80 }, + { 0x100078bb, 0x04 }, + { 0x100078bc, 0xb7 }, + { 0x100078bd, 0x07 }, + { 0x100078be, 0x00 }, + { 0x100078bf, 0x11 }, + { 0x100078c0, 0x23 }, + { 0x100078c1, 0x88 }, + { 0x100078c2, 0x07 }, + { 0x100078c3, 0x00 }, + { 0x100078c4, 0x23 }, + { 0x100078c5, 0x88 }, + { 0x100078c6, 0x07 }, + { 0x100078c7, 0x20 }, + { 0x100078c8, 0x23 }, + { 0x100078c9, 0x8c }, + { 0x100078ca, 0x07 }, + { 0x100078cb, 0x00 }, + { 0x100078cc, 0x23 }, + { 0x100078cd, 0x8c }, + { 0x100078ce, 0x07 }, + { 0x100078cf, 0x20 }, + { 0x100078d0, 0xef }, + { 0x100078d1, 0xb0 }, + { 0x100078d2, 0xcf }, + { 0x100078d3, 0xc4 }, + { 0x100078d4, 0x03 }, + { 0x100078d5, 0x24 }, + { 0x100078d6, 0x81 }, + { 0x100078d7, 0x00 }, + { 0x100078d8, 0x83 }, + { 0x100078d9, 0x20 }, + { 0x100078da, 0xc1 }, + { 0x100078db, 0x00 }, + { 0x100078dc, 0x13 }, + { 0x100078dd, 0x01 }, + { 0x100078de, 0x01 }, + { 0x100078df, 0x01 }, + { 0x100078e0, 0x6f }, + { 0x100078e1, 0xb0 }, + { 0x100078e2, 0xcf }, + { 0x100078e3, 0xcd }, + { 0x100078e4, 0x03 }, + { 0x100078e5, 0xc7 }, + { 0x100078e6, 0xd1 }, + { 0x100078e7, 0x58 }, + { 0x100078e8, 0xb7 }, + { 0x100078e9, 0x07 }, + { 0x100078ea, 0x00 }, + { 0x100078eb, 0x11 }, + { 0x100078ec, 0x23 }, + { 0x100078ed, 0x88 }, + { 0x100078ee, 0xe7 }, + { 0x100078ef, 0x00 }, + { 0x100078f0, 0x83 }, + { 0x100078f1, 0xc6 }, + { 0x100078f2, 0xc1 }, + { 0x100078f3, 0x58 }, + { 0x100078f4, 0x23 }, + { 0x100078f5, 0x88 }, + { 0x100078f6, 0xd7 }, + { 0x100078f7, 0x20 }, + { 0x100078f8, 0x23 }, + { 0x100078f9, 0x8c }, + { 0x100078fa, 0xd7 }, + { 0x100078fb, 0x00 }, + { 0x100078fc, 0x03 }, + { 0x100078fd, 0xc7 }, + { 0x100078fe, 0xc1 }, + { 0x100078ff, 0x58 }, + { 0x10007900, 0x23 }, + { 0x10007901, 0x8c }, + { 0x10007902, 0xe7 }, + { 0x10007903, 0x20 }, + { 0x10007904, 0x6f }, + { 0x10007905, 0xf0 }, + { 0x10007906, 0xdf }, + { 0x10007907, 0xfc }, + { 0x10007908, 0xb7 }, + { 0x10007909, 0x06 }, + { 0x1000790a, 0x00 }, + { 0x1000790b, 0x11 }, + { 0x1000790c, 0x03 }, + { 0x1000790d, 0xc7 }, + { 0x1000790e, 0x06 }, + { 0x1000790f, 0x21 }, + { 0x10007910, 0x03 }, + { 0x10007911, 0xc6 }, + { 0x10007912, 0xd1 }, + { 0x10007913, 0x58 }, + { 0x10007914, 0x13 }, + { 0x10007915, 0x84 }, + { 0x10007916, 0x07 }, + { 0x10007917, 0x00 }, + { 0x10007918, 0x13 }, + { 0x10007919, 0x77 }, + { 0x1000791a, 0xf7 }, + { 0x1000791b, 0x0f }, + { 0x1000791c, 0x63 }, + { 0x1000791d, 0x1a }, + { 0x1000791e, 0xe6 }, + { 0x1000791f, 0x00 }, + { 0x10007920, 0x83 }, + { 0x10007921, 0xc7 }, + { 0x10007922, 0x86 }, + { 0x10007923, 0x21 }, + { 0x10007924, 0x03 }, + { 0x10007925, 0xc7 }, + { 0x10007926, 0xc1 }, + { 0x10007927, 0x58 }, + { 0x10007928, 0x93 }, + { 0x10007929, 0xf7 }, + { 0x1000792a, 0xf7 }, + { 0x1000792b, 0x0f }, + { 0x1000792c, 0xe3 }, + { 0x1000792d, 0x02 }, + { 0x1000792e, 0xf7 }, + { 0x1000792f, 0xfa }, + { 0x10007930, 0xb7 }, + { 0x10007931, 0xc7 }, + { 0x10007932, 0x00 }, + { 0x10007933, 0x00 }, + { 0x10007934, 0x83 }, + { 0x10007935, 0xc7 }, + { 0x10007936, 0x07 }, + { 0x10007937, 0x56 }, + { 0x10007938, 0x13 }, + { 0x10007939, 0x07 }, + { 0x1000793a, 0xf0 }, + { 0x1000793b, 0x00 }, + { 0x1000793c, 0x93 }, + { 0x1000793d, 0xf7 }, + { 0x1000793e, 0xf7 }, + { 0x1000793f, 0x0f }, + { 0x10007940, 0xe3 }, + { 0x10007941, 0x78 }, + { 0x10007942, 0xf7 }, + { 0x10007943, 0xf8 }, + { 0x10007944, 0xb7 }, + { 0x10007945, 0xd7 }, + { 0x10007946, 0x00 }, + { 0x10007947, 0x00 }, + { 0x10007948, 0x83 }, + { 0x10007949, 0xc5 }, + { 0x1000794a, 0xa7 }, + { 0x1000794b, 0x47 }, + { 0x1000794c, 0x93 }, + { 0x1000794d, 0xf7 }, + { 0x1000794e, 0xf5 }, + { 0x1000794f, 0x0f }, + { 0x10007950, 0x93 }, + { 0x10007951, 0x95 }, + { 0x10007952, 0x57 }, + { 0x10007953, 0x00 }, + { 0x10007954, 0xb3 }, + { 0x10007955, 0x85 }, + { 0x10007956, 0xf5 }, + { 0x10007957, 0x40 }, + { 0x10007958, 0x93 }, + { 0x10007959, 0x95 }, + { 0x1000795a, 0x25 }, + { 0x1000795b, 0x00 }, + { 0x1000795c, 0xb3 }, + { 0x1000795d, 0x85 }, + { 0x1000795e, 0xf5 }, + { 0x1000795f, 0x00 }, + { 0x10007960, 0x13 }, + { 0x10007961, 0x95 }, + { 0x10007962, 0x35 }, + { 0x10007963, 0x00 }, + { 0x10007964, 0x93 }, + { 0x10007965, 0xd5 }, + { 0x10007966, 0xf5 }, + { 0x10007967, 0x41 }, + { 0x10007968, 0xef }, + { 0x10007969, 0xe0 }, + { 0x1000796a, 0xcf }, + { 0x1000796b, 0x8b }, + { 0x1000796c, 0x03 }, + { 0x1000796d, 0xc7 }, + { 0x1000796e, 0xd1 }, + { 0x1000796f, 0x58 }, + { 0x10007970, 0x6f }, + { 0x10007971, 0xf0 }, + { 0x10007972, 0x5f }, + { 0x10007973, 0xf3 }, + { 0x10007974, 0x13 }, + { 0x10007975, 0x01 }, + { 0x10007976, 0x01 }, + { 0x10007977, 0xfe }, + { 0x10007978, 0x23 }, + { 0x10007979, 0x2c }, + { 0x1000797a, 0x81 }, + { 0x1000797b, 0x00 }, + { 0x1000797c, 0x83 }, + { 0x1000797d, 0xc7 }, + { 0x1000797e, 0x21 }, + { 0x1000797f, 0x41 }, + { 0x10007980, 0x23 }, + { 0x10007981, 0x2e }, + { 0x10007982, 0x11 }, + { 0x10007983, 0x00 }, + { 0x10007984, 0x23 }, + { 0x10007985, 0x2a }, + { 0x10007986, 0x91 }, + { 0x10007987, 0x00 }, + { 0x10007988, 0x23 }, + { 0x10007989, 0x28 }, + { 0x1000798a, 0x21 }, + { 0x1000798b, 0x01 }, + { 0x1000798c, 0x23 }, + { 0x1000798d, 0x26 }, + { 0x1000798e, 0x31 }, + { 0x1000798f, 0x01 }, + { 0x10007990, 0x13 }, + { 0x10007991, 0x07 }, + { 0x10007992, 0x10 }, + { 0x10007993, 0x00 }, + { 0x10007994, 0x63 }, + { 0x10007995, 0x92 }, + { 0x10007996, 0xe7 }, + { 0x10007997, 0x02 }, + { 0x10007998, 0xa3 }, + { 0x10007999, 0x81 }, + { 0x1000799a, 0xf1 }, + { 0x1000799b, 0x40 }, + { 0x1000799c, 0x83 }, + { 0x1000799d, 0x20 }, + { 0x1000799e, 0xc1 }, + { 0x1000799f, 0x01 }, + { 0x100079a0, 0x03 }, + { 0x100079a1, 0x24 }, + { 0x100079a2, 0x81 }, + { 0x100079a3, 0x01 }, + { 0x100079a4, 0x83 }, + { 0x100079a5, 0x24 }, + { 0x100079a6, 0x41 }, + { 0x100079a7, 0x01 }, + { 0x100079a8, 0x03 }, + { 0x100079a9, 0x29 }, + { 0x100079aa, 0x01 }, + { 0x100079ab, 0x01 }, + { 0x100079ac, 0x83 }, + { 0x100079ad, 0x29 }, + { 0x100079ae, 0xc1 }, + { 0x100079af, 0x00 }, + { 0x100079b0, 0x13 }, + { 0x100079b1, 0x01 }, + { 0x100079b2, 0x01 }, + { 0x100079b3, 0x02 }, + { 0x100079b4, 0x67 }, + { 0x100079b5, 0x80 }, + { 0x100079b6, 0x00 }, + { 0x100079b7, 0x00 }, + { 0x100079b8, 0xe3 }, + { 0x100079b9, 0x92 }, + { 0x100079ba, 0x07 }, + { 0x100079bb, 0xfe }, + { 0x100079bc, 0x37 }, + { 0x100079bd, 0xc9 }, + { 0x100079be, 0x00 }, + { 0x100079bf, 0x00 }, + { 0x100079c0, 0x83 }, + { 0x100079c1, 0x47 }, + { 0x100079c2, 0x09 }, + { 0x100079c3, 0x56 }, + { 0x100079c4, 0x13 }, + { 0x100079c5, 0x07 }, + { 0x100079c6, 0x80 }, + { 0x100079c7, 0x01 }, + { 0x100079c8, 0x93 }, + { 0x100079c9, 0xf7 }, + { 0x100079ca, 0xf7 }, + { 0x100079cb, 0x0f }, + { 0x100079cc, 0xe3 }, + { 0x100079cd, 0x78 }, + { 0x100079ce, 0xf7 }, + { 0x100079cf, 0xfc }, + { 0x100079d0, 0x83 }, + { 0x100079d1, 0xc7 }, + { 0x100079d2, 0x31 }, + { 0x100079d3, 0x40 }, + { 0x100079d4, 0xe3 }, + { 0x100079d5, 0x84 }, + { 0x100079d6, 0x07 }, + { 0x100079d7, 0xfc }, + { 0x100079d8, 0xb7 }, + { 0x100079d9, 0xd4 }, + { 0x100079da, 0x00 }, + { 0x100079db, 0x00 }, + { 0x100079dc, 0x03 }, + { 0x100079dd, 0xc5 }, + { 0x100079de, 0x94 }, + { 0x100079df, 0x47 }, + { 0x100079e0, 0xb7 }, + { 0x100079e1, 0x15 }, + { 0x100079e2, 0x00 }, + { 0x100079e3, 0x00 }, + { 0x100079e4, 0x93 }, + { 0x100079e5, 0x85 }, + { 0x100079e6, 0x85 }, + { 0x100079e7, 0x38 }, + { 0x100079e8, 0x13 }, + { 0x100079e9, 0x75 }, + { 0x100079ea, 0xf5 }, + { 0x100079eb, 0x0f }, + { 0x100079ec, 0xef }, + { 0x100079ed, 0xe0 }, + { 0x100079ee, 0x5f }, + { 0x100079ef, 0xe0 }, + { 0x100079f0, 0x93 }, + { 0x100079f1, 0x55 }, + { 0x100079f2, 0xf5 }, + { 0x100079f3, 0x41 }, + { 0x100079f4, 0xef }, + { 0x100079f5, 0xe0 }, + { 0x100079f6, 0x0f }, + { 0x100079f7, 0x83 }, + { 0x100079f8, 0xa3 }, + { 0x100079f9, 0x81 }, + { 0x100079fa, 0x01 }, + { 0x100079fb, 0x40 }, + { 0x100079fc, 0x83 }, + { 0x100079fd, 0x27 }, + { 0x100079fe, 0xc9 }, + { 0x100079ff, 0x5f }, + { 0x10007a00, 0x37 }, + { 0x10007a01, 0x07 }, + { 0x10007a02, 0x00 }, + { 0x10007a03, 0x02 }, + { 0x10007a04, 0xb3 }, + { 0x10007a05, 0xf7 }, + { 0x10007a06, 0xe7 }, + { 0x10007a07, 0x00 }, + { 0x10007a08, 0xe3 }, + { 0x10007a09, 0x8a }, + { 0x10007a0a, 0x07 }, + { 0x10007a0b, 0xf8 }, + { 0x10007a0c, 0x03 }, + { 0x10007a0d, 0xc7 }, + { 0x10007a0e, 0x04 }, + { 0x10007a0f, 0x90 }, + { 0x10007a10, 0x93 }, + { 0x10007a11, 0x07 }, + { 0x10007a12, 0x10 }, + { 0x10007a13, 0x00 }, + { 0x10007a14, 0x13 }, + { 0x10007a15, 0x77 }, + { 0x10007a16, 0x17 }, + { 0x10007a17, 0x00 }, + { 0x10007a18, 0x63 }, + { 0x10007a19, 0x1c }, + { 0x10007a1a, 0x07 }, + { 0x10007a1b, 0x00 }, + { 0x10007a1c, 0x83 }, + { 0x10007a1d, 0xc7 }, + { 0x10007a1e, 0x34 }, + { 0x10007a1f, 0x54 }, + { 0x10007a20, 0x93 }, + { 0x10007a21, 0xf7 }, + { 0x10007a22, 0xf7 }, + { 0x10007a23, 0x0f }, + { 0x10007a24, 0x93 }, + { 0x10007a25, 0xd7 }, + { 0x10007a26, 0x17 }, + { 0x10007a27, 0x00 }, + { 0x10007a28, 0x93 }, + { 0x10007a29, 0xc7 }, + { 0x10007a2a, 0x17 }, + { 0x10007a2b, 0x00 }, + { 0x10007a2c, 0x93 }, + { 0x10007a2d, 0xf7 }, + { 0x10007a2e, 0x17 }, + { 0x10007a2f, 0x00 }, + { 0x10007a30, 0xa3 }, + { 0x10007a31, 0x85 }, + { 0x10007a32, 0xf1 }, + { 0x10007a33, 0x42 }, + { 0x10007a34, 0x37 }, + { 0x10007a35, 0xd6 }, + { 0x10007a36, 0x00 }, + { 0x10007a37, 0x00 }, + { 0x10007a38, 0x03 }, + { 0x10007a39, 0x47 }, + { 0x10007a3a, 0x06 }, + { 0x10007a3b, 0x90 }, + { 0x10007a3c, 0x93 }, + { 0x10007a3d, 0x06 }, + { 0x10007a3e, 0x10 }, + { 0x10007a3f, 0x00 }, + { 0x10007a40, 0x13 }, + { 0x10007a41, 0x77 }, + { 0x10007a42, 0x27 }, + { 0x10007a43, 0x00 }, + { 0x10007a44, 0x63 }, + { 0x10007a45, 0x18 }, + { 0x10007a46, 0x07 }, + { 0x10007a47, 0x00 }, + { 0x10007a48, 0x03 }, + { 0x10007a49, 0x47 }, + { 0x10007a4a, 0x36 }, + { 0x10007a4b, 0x54 }, + { 0x10007a4c, 0x13 }, + { 0x10007a4d, 0x77 }, + { 0x10007a4e, 0x17 }, + { 0x10007a4f, 0x00 }, + { 0x10007a50, 0xb3 }, + { 0x10007a51, 0x86 }, + { 0x10007a52, 0xe6 }, + { 0x10007a53, 0x40 }, + { 0x10007a54, 0x23 }, + { 0x10007a55, 0x85 }, + { 0x10007a56, 0xd1 }, + { 0x10007a57, 0x42 }, + { 0x10007a58, 0xb7 }, + { 0x10007a59, 0xd5 }, + { 0x10007a5a, 0x00 }, + { 0x10007a5b, 0x00 }, + { 0x10007a5c, 0x03 }, + { 0x10007a5d, 0xc6 }, + { 0x10007a5e, 0x05 }, + { 0x10007a5f, 0x92 }, + { 0x10007a60, 0x13 }, + { 0x10007a61, 0x07 }, + { 0x10007a62, 0x10 }, + { 0x10007a63, 0x00 }, + { 0x10007a64, 0x13 }, + { 0x10007a65, 0x76 }, + { 0x10007a66, 0x16 }, + { 0x10007a67, 0x00 }, + { 0x10007a68, 0x63 }, + { 0x10007a69, 0x1c }, + { 0x10007a6a, 0x06 }, + { 0x10007a6b, 0x00 }, + { 0x10007a6c, 0x03 }, + { 0x10007a6d, 0xc7 }, + { 0x10007a6e, 0x35 }, + { 0x10007a6f, 0x54 }, + { 0x10007a70, 0x13 }, + { 0x10007a71, 0x77 }, + { 0x10007a72, 0xf7 }, + { 0x10007a73, 0x0f }, + { 0x10007a74, 0x13 }, + { 0x10007a75, 0x57 }, + { 0x10007a76, 0x37 }, + { 0x10007a77, 0x00 }, + { 0x10007a78, 0x13 }, + { 0x10007a79, 0x47 }, + { 0x10007a7a, 0x17 }, + { 0x10007a7b, 0x00 }, + { 0x10007a7c, 0x13 }, + { 0x10007a7d, 0x77 }, + { 0x10007a7e, 0x17 }, + { 0x10007a7f, 0x00 }, + { 0x10007a80, 0xa3 }, + { 0x10007a81, 0x84 }, + { 0x10007a82, 0xe1 }, + { 0x10007a83, 0x42 }, + { 0x10007a84, 0xb7 }, + { 0x10007a85, 0xd5 }, + { 0x10007a86, 0x00 }, + { 0x10007a87, 0x00 }, + { 0x10007a88, 0x03 }, + { 0x10007a89, 0xc6 }, + { 0x10007a8a, 0x05 }, + { 0x10007a8b, 0x92 }, + { 0x10007a8c, 0x13 }, + { 0x10007a8d, 0x07 }, + { 0x10007a8e, 0x10 }, + { 0x10007a8f, 0x00 }, + { 0x10007a90, 0x13 }, + { 0x10007a91, 0x76 }, + { 0x10007a92, 0x26 }, + { 0x10007a93, 0x00 }, + { 0x10007a94, 0x63 }, + { 0x10007a95, 0x1c }, + { 0x10007a96, 0x06 }, + { 0x10007a97, 0x00 }, + { 0x10007a98, 0x03 }, + { 0x10007a99, 0xc7 }, + { 0x10007a9a, 0x35 }, + { 0x10007a9b, 0x54 }, + { 0x10007a9c, 0x13 }, + { 0x10007a9d, 0x77 }, + { 0x10007a9e, 0xf7 }, + { 0x10007a9f, 0x0f }, + { 0x10007aa0, 0x13 }, + { 0x10007aa1, 0x57 }, + { 0x10007aa2, 0x27 }, + { 0x10007aa3, 0x00 }, + { 0x10007aa4, 0x13 }, + { 0x10007aa5, 0x47 }, + { 0x10007aa6, 0x17 }, + { 0x10007aa7, 0x00 }, + { 0x10007aa8, 0x13 }, + { 0x10007aa9, 0x77 }, + { 0x10007aaa, 0x17 }, + { 0x10007aab, 0x00 }, + { 0x10007aac, 0x23 }, + { 0x10007aad, 0x84 }, + { 0x10007aae, 0xe1 }, + { 0x10007aaf, 0x42 }, + { 0x10007ab0, 0x63 }, + { 0x10007ab1, 0x84 }, + { 0x10007ab2, 0x07 }, + { 0x10007ab3, 0x00 }, + { 0x10007ab4, 0xe3 }, + { 0x10007ab5, 0x94 }, + { 0x10007ab6, 0x06 }, + { 0x10007ab7, 0xee }, + { 0x10007ab8, 0xef }, + { 0x10007ab9, 0x90 }, + { 0x10007aba, 0x0f }, + { 0x10007abb, 0x86 }, + { 0x10007abc, 0xef }, + { 0x10007abd, 0xd0 }, + { 0x10007abe, 0x0f }, + { 0x10007abf, 0x97 }, + { 0x10007ac0, 0x37 }, + { 0x10007ac1, 0x15 }, + { 0x10007ac2, 0x00 }, + { 0x10007ac3, 0x00 }, + { 0x10007ac4, 0x13 }, + { 0x10007ac5, 0x05 }, + { 0x10007ac6, 0x85 }, + { 0x10007ac7, 0xbb }, + { 0x10007ac8, 0x93 }, + { 0x10007ac9, 0x05 }, + { 0x10007aca, 0x00 }, + { 0x10007acb, 0x00 }, + { 0x10007acc, 0xef }, + { 0x10007acd, 0xd0 }, + { 0x10007ace, 0x9f }, + { 0x10007acf, 0xf5 }, + { 0x10007ad0, 0xb7 }, + { 0x10007ad1, 0xd7 }, + { 0x10007ad2, 0x00 }, + { 0x10007ad3, 0x00 }, + { 0x10007ad4, 0x83 }, + { 0x10007ad5, 0xc7 }, + { 0x10007ad6, 0x07 }, + { 0x10007ad7, 0x47 }, + { 0x10007ad8, 0x93 }, + { 0x10007ad9, 0xf7 }, + { 0x10007ada, 0x47 }, + { 0x10007adb, 0x00 }, + { 0x10007adc, 0xe3 }, + { 0x10007add, 0x80 }, + { 0x10007ade, 0x07 }, + { 0x10007adf, 0xec }, + { 0x10007ae0, 0xef }, + { 0x10007ae1, 0x80 }, + { 0x10007ae2, 0xdf }, + { 0x10007ae3, 0xf4 }, + { 0x10007ae4, 0x23 }, + { 0x10007ae5, 0x89 }, + { 0x10007ae6, 0xa1 }, + { 0x10007ae7, 0x40 }, + { 0x10007ae8, 0x6f }, + { 0x10007ae9, 0xf0 }, + { 0x10007aea, 0x5f }, + { 0x10007aeb, 0xeb }, + { 0x10007aec, 0x00 }, + { 0x10007aed, 0x00 }, + { 0x10007aee, 0x00 }, + { 0x10007aef, 0x00 }, + { 0x3fc2bf83, 0x00 }, + { 0x3fc2bf82, 0x00 }, + { 0x3fc2bf81, 0x00 }, + { 0x3fc2bf80, 0x00 }, + { 0x3fc2bfc7, 0x00 }, + { 0x3fc2bfc6, 0x00 }, + { 0x3fc2bfc5, 0x00 }, + { 0x3fc2bfc4, 0x00 }, + { 0x3fc2bfc3, 0x00 }, + { 0x3fc2bfc2, 0x00 }, + { 0x3fc2bfc1, 0x00 }, + { 0x3fc2bfc0, 0x03 }, + { 0x0000d486, 0x43 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, + { 0x1000db00, 0x04 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x11 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x82 }, + { 0x1000db06, 0x04 }, + { 0x1000db07, 0xf1 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0x40 }, + { 0x1000db0b, 0x02 }, + { 0x1000db0c, 0xf2 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0xe0 }, + { 0x1000db10, 0x00 }, + { 0x1000db11, 0x10 }, + { 0x1000db12, 0x00 }, + { 0x1000db13, 0x00 }, + { 0x1000db14, 0x45 }, + { 0x0000d540, 0x01 }, + { 0x0000c081, 0xfc }, + { 0x0000f01e, 0x80 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + /* * The 'patch code' is written to the patch code area. * The patch code area is used for SDCA register expansion flexibility. @@ -1418,12 +3439,13 @@ static const struct reg_sequence rt1320_patch_code_write[] = { static const struct reg_default rt1320_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 }, }; static const struct reg_default rt1320_mbq_defaults[] = { @@ -1484,21 +3506,36 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case 0xde00 ... 0xde09: case 0xdf00 ... 0xdf1b: case 0xe000 ... 0xe847: + case 0xf01e: case 0xf717 ... 0xf719: case 0xf720 ... 0xf723: + case 0x1000cd91 ... 0x1000cd96: case 0x1000f008: + case 0x1000f021: case 0x3fe2e000 ... 0x3fe2e003: - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): + case 0x3fc2ab80 ... 0x3fc2abd4: + /* 0x41000189/0x4100018a */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + /* 0x41001388 */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + /* 0x41001988 */ + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + /* 0x41080000 */ + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): + /* 0x41080200 */ + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0): + /* 0x41080900 */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + /* 0x41080980 */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + /* 0x41081080 */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + /* 0x41081480/0x41081488 */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + /* 0x41081980 */ + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): return true; default: return false; @@ -1508,6 +3545,9 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) static bool rt1320_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0xc000: + case 0xc003: + case 0xc081: case 0xc402 ... 0xc406: case 0xc48c ... 0xc48f: case 0xc560: @@ -1545,16 +3585,21 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0xde02: case 0xdf14 ... 0xdf1b: case 0xe83c ... 0xe847: + case 0xf01e: case 0xf717 ... 0xf719: case 0xf720 ... 0xf723: case 0x10000000 ... 0x10007fff: case 0x1000c000 ... 0x1000dfff: case 0x1000f008: - case 0x3fc2bfc4 ... 0x3fc2bfc7: + case 0x1000f021: + case 0x3fc2ab80 ... 0x3fc2abd4: + case 0x3fc2bf80 ... 0x3fc2bf83: + case 0x3fc2bfc0 ... 0x3fc2bfc7: case 0x3fe2e000 ... 0x3fe2e003: case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): return true; default: return false; @@ -1577,7 +3622,7 @@ static const struct regmap_config rt1320_sdw_regmap = { .val_bits = 8, .readable_reg = rt1320_readable_register, .volatile_reg = rt1320_volatile_register, - .max_register = 0x41081488, + .max_register = 0x41081980, .reg_defaults = rt1320_reg_defaults, .num_reg_defaults = ARRAY_SIZE(rt1320_reg_defaults), .cache_type = REGCACHE_MAPLE, @@ -1663,6 +3708,63 @@ static int rt1320_read_prop(struct sdw_slave *slave) return 0; } +static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char ps) +{ + unsigned int delay = 1000, val; + + pm_runtime_mark_last_busy(&rt1320->sdw_slave->dev); + + /* waiting for Actual PDE becomes to PS0/PS3 */ + while (delay) { + regmap_read(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, + RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val); + if (val == ps) + break; + + usleep_range(1000, 1500); + delay--; + } + if (!delay) { + dev_warn(&rt1320->sdw_slave->dev, "%s PDE to %s is NOT ready", __func__, ps?"PS3":"PS0"); + return -ETIMEDOUT; + } + + return 0; +} + +static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) +{ + struct sdw_slave *slave = rt1320->sdw_slave; + unsigned int i, reg, val, delay, retry, tmp; + + regmap_multi_reg_write(rt1320->regmap, rt1320_vc_blind_write, ARRAY_SIZE(rt1320_vc_blind_write)); + + for (i = 0; i < ARRAY_SIZE(rt1320_vc_patch_code_write); i++) { + reg = rt1320_vc_patch_code_write[i].reg; + val = rt1320_vc_patch_code_write[i].def; + delay = rt1320_vc_patch_code_write[i].delay_us; + + if ((reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) && + (val == 0x00)) { + retry = 200; + while (retry) { + regmap_read(rt1320->regmap, RT1320_KR0_INT_READY, &tmp); + dev_dbg(&slave->dev, "%s, RT1320_KR0_INT_READY=0x%x\n", __func__, tmp); + if (tmp == 0x1f) + break; + usleep_range(1000, 1500); + retry--; + } + if (!retry) + dev_warn(&slave->dev, "%s MCU is NOT ready!", __func__); + } + regmap_write(rt1320->regmap, reg, val); + if (delay) + usleep_range(delay, delay + 1000); + } +} + static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); @@ -1696,16 +3798,20 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status); /* initialization write */ - if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt1320->first_hw_init)) { - regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write)); - regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write, - ARRAY_SIZE(rt1320_patch_code_write)); + if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) { + if (rt1320->version_id < RT1320_VC) { + regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write)); + regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write, + ARRAY_SIZE(rt1320_patch_code_write)); + } else if (rt1320->version_id == RT1320_VC) { + rt1320_vc_preset(rt1320); + } regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), FUNCTION_NEEDS_INITIALIZATION); } - if (!rt1320->first_hw_init) { + if (!rt1320->first_hw_init && rt1320->version_id == RT1320_VA) { regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0); regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val); @@ -1776,14 +3882,14 @@ static int rt1320_pde23_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, - RT1320_SDCA_CTL_REQ_POWER_STATE, 0), - ps0); + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + rt1320_pde_transition_delay(rt1320, ps0); break; case SND_SOC_DAPM_PRE_PMD: regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, - RT1320_SDCA_CTL_REQ_POWER_STATE, 0), - ps3); + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + rt1320_pde_transition_delay(rt1320, ps3); break; default: break; @@ -1799,7 +3905,7 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); - unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int gain_l_val, gain_r_val; unsigned int lvalue, rvalue; const unsigned int interval_offset = 0xc0; @@ -1828,12 +3934,7 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, /* Rch */ regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val); - regmap_read(rt1320->mbq_regmap, mc->reg, &read_l); - regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r); - if (read_r == gain_r_val && read_l == gain_l_val) - return 1; - - return -EIO; + return 1; } static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index b23228e74568..1fbc1fcd71cf 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -18,6 +18,7 @@ #define RT1320_DEV_VERSION_ID_1 0xc404 #define RT1320_KR0_STATUS_CNT 0x1000f008 +#define RT1320_KR0_INT_READY 0x1000f021 #define RT1320_HIFI_VER_0 0x3fe2e000 #define RT1320_HIFI_VER_1 0x3fe2e001 #define RT1320_HIFI_VER_2 0x3fe2e002 @@ -43,6 +44,7 @@ /* RT1320 SDCA control */ #define RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 #define RT1320_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1320_SDCA_CTL_ACTUAL_POWER_STATE 0x10 #define RT1320_SDCA_CTL_FU_MUTE 0x01 #define RT1320_SDCA_CTL_FU_VOLUME 0x02 #define RT1320_SDCA_CTL_SAPU_PROTECTION_MODE 0x10 @@ -76,6 +78,7 @@ enum { enum rt1320_version_id { RT1320_VA, RT1320_VB, + RT1320_VC, }; #define RT1320_VER_B_ID 0x07392238 diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index e3aca9c785a0..aa163ec40862 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2903,8 +2903,10 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682) } if (dev->of_node) { - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + if (ret) + return ret; } else { ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, init.name, diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index f50f196d700d..ce2e88e066f3 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2828,7 +2828,9 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component) } if (dev->of_node) { - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + if (ret) + return ret; } else { ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, init.name, dev_name(dev)); diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index c421906a0694..4ab15be69f3a 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -63,10 +63,6 @@ struct sti_spdif_audio { struct sti_sas_dev_data { const struct regmap_config *regmap; const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ - const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ - const int num_dapm_widgets; /* dapms declaration */ - const struct snd_soc_dapm_route *dapm_routes; /* route declaration */ - const int num_dapm_routes; /* route declaration */ }; /* driver data structure */ @@ -324,10 +320,6 @@ static const struct regmap_config stih407_sas_regmap = { static const struct sti_sas_dev_data stih407_data = { .regmap = &stih407_sas_regmap, .dac_ops = &stih407_dac_ops, - .dapm_widgets = stih407_sas_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), - .dapm_routes = stih407_sas_route, - .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), }; static struct snd_soc_dai_driver sti_sas_dai[] = { @@ -386,12 +378,16 @@ static int sti_sas_component_probe(struct snd_soc_component *component) return sti_sas_init_sas_registers(component, drvdata); } -static struct snd_soc_component_driver sti_sas_driver = { +static const struct snd_soc_component_driver sti_sas_driver = { .probe = sti_sas_component_probe, .resume = sti_sas_resume, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, + .dapm_widgets = stih407_sas_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), + .dapm_routes = stih407_sas_route, + .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), }; static const struct of_device_id sti_sas_dev_match[] = { @@ -446,13 +442,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev) sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; - /* Set dapms*/ - sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; - sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; - - sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; - sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; - /* Store context */ dev_set_drvdata(&pdev->dev, drvdata); diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 9e68afc09897..684d52ec6600 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 5eaddf07aadc..d482cd194c08 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 5601fba17c96..9f93b230652a 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c index 6902bfef185b..a1963415c931 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 1fbf4560f5cc..1e0b3aa95749 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // -// TAS2781 Common functions for HDA and ASoC Audio drivers +// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers // // Copyright 2023 - 2024 Texas Instruments, Inc. // @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -64,8 +63,8 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, */ ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", - __func__, ret); + dev_err(tas_priv->dev, "%s, E=%d channel:%d\n", + __func__, ret, chn); goto out; } } @@ -89,6 +88,32 @@ out: return ret; } +int tasdev_chn_switch(struct tasdevice_priv *tas_priv, + unsigned short chn) +{ + struct i2c_client *client = (struct i2c_client *)tas_priv->client; + struct tasdevice *tasdev = &tas_priv->tasdevice[chn]; + struct regmap *map = tas_priv->regmap; + int ret; + + if (client->addr != tasdev->dev_addr) { + client->addr = tasdev->dev_addr; + /* All devices share the same regmap, clear the page + * inside regmap once switching to another device. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + return ret; + } + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(tasdev_chn_switch); + int tasdevice_dev_read(struct tasdevice_priv *tas_priv, unsigned short chn, unsigned int reg, unsigned int *val) { @@ -411,8 +436,6 @@ EXPORT_SYMBOL_GPL(tasdevice_dsp_remove); void tasdevice_remove(struct tasdevice_priv *tas_priv) { - if (gpio_is_valid(tas_priv->irq_info.irq_gpio)) - gpio_free(tas_priv->irq_info.irq_gpio); mutex_destroy(&tas_priv->codec_lock); } EXPORT_SYMBOL_GPL(tasdevice_remove); diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 8f9a3ae7153e..3de0132c345d 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -2152,20 +2151,61 @@ static int tasdevice_load_data(struct tasdevice_priv *tas_priv, static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i) { + struct tasdevice_fw *cal_fmw = priv->tasdevice[i].cali_data_fmw; + struct calidata *cali_data = &priv->cali_data; + struct cali_reg *p = &cali_data->cali_reg_array; + unsigned char *data = cali_data->data; struct tasdevice_calibration *cal; - struct tasdevice_fw *cal_fmw; + int k = i * (cali_data->cali_dat_sz_per_dev + 1); + int rc; - cal_fmw = priv->tasdevice[i].cali_data_fmw; + /* Load the calibrated data from cal bin file */ + if (!priv->is_user_space_calidata && cal_fmw) { + cal = cal_fmw->calibrations; - /* No calibrated data for current devices, playback will go ahead. */ - if (!cal_fmw) + if (cal) + load_calib_data(priv, &cal->dev_data); return; - - cal = cal_fmw->calibrations; - if (!cal) + } + if (!priv->is_user_space_calidata) return; + /* load calibrated data from user space */ + if (data[k] != i) { + dev_err(priv->dev, "%s: no cal-data for dev %d from usr-spc\n", + __func__, i); + return; + } + k++; - load_calib_data(priv, &cal->dev_data); + rc = tasdevice_dev_bulk_write(priv, i, p->r0_reg, &(data[k]), 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d r0_reg bulk_wr err = %d\n", i, rc); + return; + } + k += 4; + rc = tasdevice_dev_bulk_write(priv, i, p->r0_low_reg, &(data[k]), 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d r0_low_reg err = %d\n", i, rc); + return; + } + k += 4; + rc = tasdevice_dev_bulk_write(priv, i, p->invr0_reg, &(data[k]), 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d invr0_reg err = %d\n", i, rc); + return; + } + k += 4; + rc = tasdevice_dev_bulk_write(priv, i, p->pow_reg, &(data[k]), 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d pow_reg bulk_wr err = %d\n", i, rc); + return; + } + k += 4; + rc = tasdevice_dev_bulk_write(priv, i, p->tlimit_reg, &(data[k]), 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d tlimit_reg err = %d\n", i, rc); + return; + } } int tasdevice_select_tuningprm_cfg(void *context, int prm_no, @@ -2260,9 +2300,10 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, tas_priv->tasdevice[i].cur_conf = cfg_no; } } - } else + } else { dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n", __func__, cfg_no); + } status |= cfg_info[rca_conf_no]->active_dev; diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index e79d613745b4..8a8d97dd7f25 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,9 +29,73 @@ #include #include #include +#include #include #include +#define X2563_CL_STT_VAL(xreg, xval) \ +{ .reg = xreg, \ + .val = { xval }, \ + .val_len = 1, } + +#define X2563_CL_STT_4BYTS(xreg, byte0, byte1, byte2, byte3) \ +{ .reg = xreg, \ + .val = { byte0, byte1, byte2, byte3 }, \ + .val_len = 4, } + +static const struct bulk_reg_val tas2563_cali_start_reg[] = { + X2563_CL_STT_VAL(TAS2563_IDLE, 0x00), + X2563_CL_STT_4BYTS(TAS2563_PRM_ENFF_REG, 0x40, 0x00, 0x00, 0x00), + X2563_CL_STT_4BYTS(TAS2563_PRM_DISTCK_REG, 0x40, 0x00, 0x00, 0x00), + X2563_CL_STT_4BYTS(TAS2563_PRM_TE_SCTHR_REG, 0x7f, 0xff, 0xff, 0xff), + X2563_CL_STT_4BYTS(TAS2563_PRM_PLT_FLAG_REG, 0x40, 0x00, 0x00, 0x00), + X2563_CL_STT_4BYTS(TAS2563_PRM_SINEGAIN_REG, 0x0a, 0x3d, 0x70, 0xa4), + X2563_CL_STT_4BYTS(TAS2563_TE_TA1_REG, 0x00, 0x36, 0x91, 0x5e), + X2563_CL_STT_4BYTS(TAS2563_TE_TA1_AT_REG, 0x00, 0x36, 0x91, 0x5e), + X2563_CL_STT_4BYTS(TAS2563_TE_TA2_REG, 0x00, 0x06, 0xd3, 0x72), + X2563_CL_STT_4BYTS(TAS2563_TE_AT_REG, 0x00, 0x36, 0x91, 0x5e), + X2563_CL_STT_4BYTS(TAS2563_TE_DT_REG, 0x00, 0x36, 0x91, 0x5e), +}; + +#define X2781_CL_STT_VAL(xreg, xval, xlocked) \ +{ .reg = xreg, \ + .val = { xval }, \ + .val_len = 1, \ + .is_locked = xlocked, } + +#define X2781_CL_STT_4BYTS_UNLOCKED(xreg, byte0, byte1, byte2, byte3) \ +{ .reg = xreg, \ + .val = { byte0, byte1, byte2, byte3 }, \ + .val_len = 4, \ + .is_locked = false, } + +#define X2781_CL_STT_LEN_UNLOCKED(xreg) \ +{ .reg = xreg, \ + .val_len = 4, \ + .is_locked = false, } + +static const struct bulk_reg_val tas2781_cali_start_reg[] = { + X2781_CL_STT_VAL(TAS2781_PRM_INT_MASK_REG, 0xfe, false), + X2781_CL_STT_VAL(TAS2781_PRM_CLK_CFG_REG, 0xdd, false), + X2781_CL_STT_VAL(TAS2781_PRM_RSVD_REG, 0x20, false), + X2781_CL_STT_VAL(TAS2781_PRM_TEST_57_REG, 0x14, false), + X2781_CL_STT_VAL(TAS2781_PRM_TEST_62_REG, 0x45, true), + X2781_CL_STT_VAL(TAS2781_PRM_PVDD_UVLO_REG, 0x03, false), + X2781_CL_STT_VAL(TAS2781_PRM_CHNL_0_REG, 0xa8, false), + X2781_CL_STT_VAL(TAS2781_PRM_NG_CFG0_REG, 0xb9, false), + X2781_CL_STT_VAL(TAS2781_PRM_IDLE_CH_DET_REG, 0x92, false), + /* + * This register is pilot tone threshold, different with the + * calibration tool version, it will be updated in + * tas2781_calib_start_put(), set to 1mA. + */ + X2781_CL_STT_4BYTS_UNLOCKED(0, 0x00, 0x00, 0x00, 0x56), + X2781_CL_STT_4BYTS_UNLOCKED(TAS2781_PRM_PLT_FLAG_REG, + 0x40, 0x00, 0x00, 0x00), + X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN_REG), + X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN2_REG), +}; + static const struct i2c_device_id tasdevice_id[] = { { "tas2563", TAS2563 }, { "tas2781", TAS2781 }, @@ -141,6 +204,557 @@ static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } +static int tasdev_cali_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + struct calidata *cali_data = &priv->cali_data; + struct cali_reg *p = &cali_data->cali_reg_array; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned char *data = cali_data->data; + unsigned int i = 0; + unsigned int j, k; + int rc; + + guard(mutex)(&priv->codec_lock); + if (!priv->is_user_space_calidata) + return -1; + + if (!p->r0_reg) + return -1; + + dst[i++] = bytes_ext->max; + dst[i++] = 'r'; + + dst[i++] = TASDEVICE_BOOK_ID(p->r0_reg); + dst[i++] = TASDEVICE_PAGE_ID(p->r0_reg); + dst[i++] = TASDEVICE_PAGE_REG(p->r0_reg); + + dst[i++] = TASDEVICE_BOOK_ID(p->r0_low_reg); + dst[i++] = TASDEVICE_PAGE_ID(p->r0_low_reg); + dst[i++] = TASDEVICE_PAGE_REG(p->r0_low_reg); + + dst[i++] = TASDEVICE_BOOK_ID(p->invr0_reg); + dst[i++] = TASDEVICE_PAGE_ID(p->invr0_reg); + dst[i++] = TASDEVICE_PAGE_REG(p->invr0_reg); + + dst[i++] = TASDEVICE_BOOK_ID(p->pow_reg); + dst[i++] = TASDEVICE_PAGE_ID(p->pow_reg); + dst[i++] = TASDEVICE_PAGE_REG(p->pow_reg); + + dst[i++] = TASDEVICE_BOOK_ID(p->tlimit_reg); + dst[i++] = TASDEVICE_PAGE_ID(p->tlimit_reg); + dst[i++] = TASDEVICE_PAGE_REG(p->tlimit_reg); + + for (j = 0, k = 0; j < priv->ndev; j++) { + if (j == data[k]) { + dst[i++] = j; + k++; + } else { + dev_err(priv->dev, "chn %d device %u not match\n", + j, data[k]); + k += 21; + continue; + } + rc = tasdevice_dev_bulk_read(priv, j, p->r0_reg, &dst[i], 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d r0_reg bulk_rd err = %d\n", + j, rc); + i += 20; + k += 20; + continue; + } + rc = memcmp(&dst[i], &data[k], 4); + if (rc != 0) + dev_dbg(priv->dev, "chn %d r0_data is not same\n", j); + k += 4; + i += 4; + rc = tasdevice_dev_bulk_read(priv, j, p->r0_low_reg, + &dst[i], 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d r0_low bulk_rd err = %d\n", + j, rc); + i += 16; + k += 16; + continue; + } + rc = memcmp(&dst[i], &data[k], 4); + if (rc != 0) + dev_dbg(priv->dev, "chn %d r0_low is not same\n", j); + i += 4; + k += 4; + rc = tasdevice_dev_bulk_read(priv, j, p->invr0_reg, + &dst[i], 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d invr0 bulk_rd err = %d\n", + j, rc); + i += 12; + k += 12; + continue; + } + rc = memcmp(&dst[i], &data[k], 4); + if (rc != 0) + dev_dbg(priv->dev, "chn %d invr0 is not same\n", j); + i += 4; + k += 4; + rc = tasdevice_dev_bulk_read(priv, j, p->pow_reg, &dst[i], 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d pow_reg bulk_rd err = %d\n", + j, rc); + i += 8; + k += 8; + continue; + } + rc = memcmp(&dst[i], &data[k], 4); + if (rc != 0) + dev_dbg(priv->dev, "chn %d pow_reg is not same\n", j); + i += 4; + k += 4; + rc = tasdevice_dev_bulk_read(priv, j, p->tlimit_reg, + &dst[i], 4); + if (rc < 0) { + dev_err(priv->dev, "chn %d tlimit bulk_rd err = %d\n", + j, rc); + } + rc = memcmp(&dst[i], &data[k], 4); + if (rc != 0) + dev_dbg(priv->dev, "chn %d tlimit is not same\n", j); + i += 4; + k += 4; + } + return 0; +} + +static int calib_data_get(struct tasdevice_priv *tas_priv, int reg, + unsigned char *dst) +{ + struct i2c_client *clt = (struct i2c_client *)tas_priv->client; + struct tasdevice *tasdev = tas_priv->tasdevice; + int rc = -1; + int i; + + for (i = 0; i < tas_priv->ndev; i++) { + if (clt->addr == tasdev[i].dev_addr) { + /* First byte is the device index. */ + dst[0] = i; + rc = tasdevice_dev_bulk_read(tas_priv, i, reg, &dst[1], + 4); + break; + } + } + + return rc; +} + +static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, + int *reg, unsigned char *dat) +{ + struct tasdevice *tasdev = tas_priv->tasdevice; + struct bulk_reg_val *p = tasdev[i].cali_data_backup; + const int sum = ARRAY_SIZE(tas2781_cali_start_reg); + int j; + + if (p == NULL) + return; + + /* Store the current setting from the chip */ + for (j = 0; j < sum; j++) { + if (p[j].val_len == 1) { + if (p[j].is_locked) + tasdevice_dev_write(tas_priv, i, + TAS2781_TEST_UNLOCK_REG, + TAS2781_TEST_PAGE_UNLOCK); + tasdevice_dev_read(tas_priv, i, p[j].reg, + (int *)&p[j].val[0]); + } else { + switch (p[j].reg) { + case 0: { + if (!reg[0]) + continue; + p[j].reg = reg[0]; + } + break; + case TAS2781_PRM_PLT_FLAG_REG: + p[j].reg = reg[1]; + break; + case TAS2781_PRM_SINEGAIN_REG: + p[j].reg = reg[2]; + break; + case TAS2781_PRM_SINEGAIN2_REG: + p[j].reg = reg[3]; + break; + } + tasdevice_dev_bulk_read(tas_priv, i, p[j].reg, + p[j].val, 4); + } + } + + /* Update the setting for calibration */ + for (j = 0; j < sum - 2; j++) { + if (p[j].val_len == 1) { + if (p[j].is_locked) + tasdevice_dev_write(tas_priv, i, + TAS2781_TEST_UNLOCK_REG, + TAS2781_TEST_PAGE_UNLOCK); + tasdevice_dev_write(tas_priv, i, p[j].reg, + tas2781_cali_start_reg[j].val[0]); + } else { + if (!p[j].reg) + continue; + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, + (unsigned char *) + tas2781_cali_start_reg[j].val, 4); + } + } + + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, &dat[1], 4); + tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg, &dat[5], 4); +} + +static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dat = ucontrol->value.bytes.data; + int i, reg[4]; + int j = 0; + + guard(mutex)(&priv->codec_lock); + if (priv->chip_id != TAS2781 || bytes_ext->max != dat[0] || + dat[1] != 'r') { + dev_err(priv->dev, "%s: package fmt or chipid incorrect\n", + __func__); + return 0; + } + j += 2; + /* refresh pilot tone and SineGain register */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + reg[i] = TASDEVICE_REG(dat[j], dat[j + 1], dat[j + 2]); + j += 3; + } + + for (i = 0; i < priv->ndev; i++) { + int k = i * 9 + j; + + if (dat[k] != i) { + dev_err(priv->dev, "%s:no cal-setting for dev %d\n", + __func__, i); + continue; + } + sngl_calib_start(priv, i, reg, dat + k); + } + return 1; +} + +static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv) +{ + const int sum = ARRAY_SIZE(tas2781_cali_start_reg); + int i, j; + + for (i = 0; i < tas_priv->ndev; i++) { + struct tasdevice *tasdev = tas_priv->tasdevice; + struct bulk_reg_val *p = tasdev[i].cali_data_backup; + + if (p == NULL) + continue; + + for (j = 0; j < sum; j++) { + if (p[j].val_len == 1) { + if (p[j].is_locked) + tasdevice_dev_write(tas_priv, i, + TAS2781_TEST_UNLOCK_REG, + TAS2781_TEST_PAGE_UNLOCK); + tasdevice_dev_write(tas_priv, i, p[j].reg, + p[j].val[0]); + } else { + if (!p[j].reg) + continue; + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, + p[j].val, 4); + } + } + } +} + +static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct bulk_reg_val *q = (struct bulk_reg_val *)tas2563_cali_start_reg; + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + const int sum = ARRAY_SIZE(tas2563_cali_start_reg); + int rc = 1; + int i, j; + + guard(mutex)(&tas_priv->codec_lock); + if (tas_priv->chip_id != TAS2563) { + rc = -1; + goto out; + } + + for (i = 0; i < tas_priv->ndev; i++) { + struct tasdevice *tasdev = tas_priv->tasdevice; + struct bulk_reg_val *p = tasdev[i].cali_data_backup; + + if (p == NULL) + continue; + for (j = 0; j < sum; j++) { + if (p[j].val_len == 1) + tasdevice_dev_read(tas_priv, + i, p[j].reg, + (unsigned int *)&p[j].val[0]); + else + tasdevice_dev_bulk_read(tas_priv, + i, p[j].reg, p[j].val, 4); + } + + for (j = 0; j < sum; j++) { + if (p[j].val_len == 1) + tasdevice_dev_write(tas_priv, i, p[j].reg, + q[j].val[0]); + else + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, + q[j].val, 4); + } + } +out: + return rc; +} + +static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv) +{ + const int sum = ARRAY_SIZE(tas2563_cali_start_reg); + int i, j; + + for (i = 0; i < tas_priv->ndev; i++) { + struct tasdevice *tasdev = tas_priv->tasdevice; + struct bulk_reg_val *p = tasdev[i].cali_data_backup; + + if (p == NULL) + continue; + + for (j = 0; j < sum; j++) { + if (p[j].val_len == 1) + tasdevice_dev_write(tas_priv, i, p[j].reg, + p[j].val[0]); + else + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, + p[j].val, 4); + } + } +} + +static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + + guard(mutex)(&priv->codec_lock); + if (priv->chip_id == TAS2563) + tas2563_calib_stop_put(priv); + else + tas2781_calib_stop_put(priv); + + return 1; +} + +static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + struct calidata *cali_data = &priv->cali_data; + struct cali_reg *p = &cali_data->cali_reg_array; + unsigned char *src = ucontrol->value.bytes.data; + unsigned char *dst = cali_data->data; + int rc = 1, i = 0; + int j; + + guard(mutex)(&priv->codec_lock); + if (src[0] != bytes_ext->max || src[1] != 'r') { + dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__); + return 0; + } + for (j = 0; j < priv->ndev; j++) { + if (src[17 + j * 21] != j) { + dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__); + return 0; + } + } + i += 2; + priv->is_user_space_calidata = true; + + p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + + memcpy(dst, &src[i], cali_data->total_sz); + return rc; +} + +static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct i2c_client *clt = (struct i2c_client *)tas_priv->client; + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + struct tasdevice *tasdev = tas_priv->tasdevice; + unsigned char *dst = ucontrol->value.bytes.data; + int i, val, rc = -1; + + dst[0] = bytes_ext->max; + guard(mutex)(&tas_priv->codec_lock); + for (i = 0; i < tas_priv->ndev; i++) { + if (clt->addr == tasdev[i].dev_addr) { + /* First byte is the device index. */ + dst[1] = i; + rc = tasdevice_dev_read(tas_priv, i, + TAS2781_RUNTIME_LATCH_RE_REG, &val); + if (rc < 0) + dev_err(tas_priv->dev, "%s, get value error\n", + __func__); + else + dst[2] = val; + + break; + } + } + + return rc; +} + +static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned int reg; + int rc = -1; + + if (tas_priv->chip_id == TAS2781) + reg = TAS2781_RUNTIME_RE_REG_TF; + else + reg = TAS2563_RUNTIME_RE_REG_TF; + + guard(mutex)(&tas_priv->codec_lock); + dst[0] = bytes_ext->max; + rc = calib_data_get(tas_priv, reg, &dst[1]); + + return rc; +} + +static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned int reg; + int rc = -1; + + if (tas_priv->chip_id == TAS2781) + reg = TAS2781_RUNTIME_RE_REG; + else + reg = TAS2563_RUNTIME_RE_REG; + guard(mutex)(&tas_priv->codec_lock); + dst[0] = bytes_ext->max; + rc = calib_data_get(tas_priv, reg, &dst[1]); + + return rc; +} + +static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct calidata *cali_data = &tas_priv->cali_data; + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned int reg; + int rc = -1; + + guard(mutex)(&tas_priv->codec_lock); + + if (tas_priv->chip_id == TAS2563) + reg = TAS2563_PRM_R0_REG; + else if (cali_data->cali_reg_array.r0_reg) + reg = cali_data->cali_reg_array.r0_reg; + else + return -1; + dst[0] = bytes_ext->max; + rc = calib_data_get(tas_priv, reg, &dst[1]); + + return rc; +} + +static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned int reg = TASDEVICE_XM_A1_REG; + int rc = -1; + + guard(mutex)(&tas_priv->codec_lock); + dst[0] = bytes_ext->max; + rc = calib_data_get(tas_priv, reg, &dst[1]); + + return rc; +} + +static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + unsigned char *dst = ucontrol->value.bytes.data; + unsigned int reg = TASDEVICE_XM_A2_REG; + int rc = -1; + + guard(mutex)(&tas_priv->codec_lock); + dst[0] = bytes_ext->max; + rc = calib_data_get(tas_priv, reg, &dst[1]); + + return rc; +} + +static int tasdev_nop_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + static int tas2563_digital_gain_get( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -157,7 +771,7 @@ static int tas2563_digital_gain_get( mutex_lock(&tas_dev->codec_lock); /* Read the primary device */ - ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); goto out; @@ -203,7 +817,7 @@ static int tas2563_digital_gain_put( vol = clamp(vol, 0, max); mutex_lock(&tas_dev->codec_lock); /* Read the primary device */ - ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); + ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); rc = -1; @@ -241,6 +855,16 @@ static const struct snd_kcontrol_new tasdevice_snd_controls[] = { tasdev_force_fwload_get, tasdev_force_fwload_put), }; +static const struct snd_kcontrol_new tasdevice_cali_controls[] = { + SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0, + tasdev_nop_get, tasdev_calib_stop_put), + SND_SOC_BYTES_EXT("Amp TF Data", 6, tasdev_tf_data_get, NULL), + SND_SOC_BYTES_EXT("Amp RE Data", 6, tasdev_re_data_get, NULL), + SND_SOC_BYTES_EXT("Amp R0 Data", 6, tasdev_r0_data_get, NULL), + SND_SOC_BYTES_EXT("Amp XMA1 Data", 6, tasdev_XMA1_data_get, NULL), + SND_SOC_BYTES_EXT("Amp XMA2 Data", 6, tasdev_XMA2_data_get, NULL), +}; + static const struct snd_kcontrol_new tas2781_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, @@ -250,6 +874,10 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_digital_putvol, dvc_tlv), }; +static const struct snd_kcontrol_new tas2781_cali_controls[] = { + SND_SOC_BYTES_EXT("Amp Latch Data", 3, tas2781_latch_reg_get, NULL), +}; + static const struct snd_kcontrol_new tas2563_snd_controls[] = { SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0, 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0, @@ -257,6 +885,11 @@ static const struct snd_kcontrol_new tas2563_snd_controls[] = { tas2563_dvc_tlv), }; +static const struct snd_kcontrol_new tas2563_cali_controls[] = { + SOC_SINGLE_EXT("Calibration Start", SND_SOC_NOPM, 0, 1, 0, + tasdev_nop_get, tas2563_calib_start_put), +}; + static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -274,6 +907,31 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, return ret; } +static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_priv->ndev - 1; + + return 0; +} + +static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = TAS2563; + uinfo->value.integer.max = TAS2781; + + return 0; +} + static int tasdevice_info_programs(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -330,6 +988,17 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, return 0; } +static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tas_priv->chip_id; + + return 0; +} + static int tasdevice_create_control(struct tasdevice_priv *tas_priv) { struct snd_kcontrol_new *prof_ctrls; @@ -346,13 +1015,11 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv) } /* Create a mixer item for selecting the active profile */ - name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - GFP_KERNEL); + name = devm_kstrdup(tas_priv->dev, "Speaker Profile Id", GFP_KERNEL); if (!name) { ret = -ENOMEM; goto out; } - scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "Speaker Profile Id"); prof_ctrls[mix_index].name = name; prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; prof_ctrls[mix_index].info = tasdevice_info_profile; @@ -423,12 +1090,47 @@ static int tasdevice_configuration_put( return ret; } -static int tasdevice_dsp_create_ctrls( - struct tasdevice_priv *tas_priv) +static int tasdevice_active_num_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + struct i2c_client *clt = (struct i2c_client *)tas_priv->client; + struct tasdevice *tasdev = tas_priv->tasdevice; + int i; + + for (i = 0; i < tas_priv->ndev; i++) { + if (clt->addr == tasdev[i].dev_addr) { + ucontrol->value.integer.value[0] = i; + return 0; + } + } + + return -1; +} + +static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); + int dev_id = ucontrol->value.integer.value[0]; + int max = tas_priv->ndev - 1, rc; + + dev_id = clamp(dev_id, 0, max); + + guard(mutex)(&tas_priv->codec_lock); + rc = tasdev_chn_switch(tas_priv, dev_id); + + return rc; +} + +static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) { struct snd_kcontrol_new *dsp_ctrls; - char *prog_name, *conf_name; - int nr_controls = 2; + char *active_dev_num, *chip_id; + char *conf_name, *prog_name; + int nr_controls = 4; int mix_index = 0; int ret; @@ -442,18 +1144,13 @@ static int tasdevice_dsp_create_ctrls( goto out; } - /* Create a mixer item for selecting the active profile */ - prog_name = devm_kzalloc(tas_priv->dev, - SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL); - conf_name = devm_kzalloc(tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + /* Create mixer items for selecting the active Program and Config */ + prog_name = devm_kstrdup(tas_priv->dev, "Speaker Program Id", GFP_KERNEL); - if (!prog_name || !conf_name) { + if (!prog_name) { ret = -ENOMEM; goto out; } - - scnprintf(prog_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "Speaker Program Id"); dsp_ctrls[mix_index].name = prog_name; dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; dsp_ctrls[mix_index].info = tasdevice_info_programs; @@ -461,8 +1158,12 @@ static int tasdevice_dsp_create_ctrls( dsp_ctrls[mix_index].put = tasdevice_program_put; mix_index++; - scnprintf(conf_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, - "Speaker Config Id"); + conf_name = devm_kstrdup(tas_priv->dev, "Speaker Config Id", + GFP_KERNEL); + if (!conf_name) { + ret = -ENOMEM; + goto out; + } dsp_ctrls[mix_index].name = conf_name; dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; dsp_ctrls[mix_index].info = tasdevice_info_configurations; @@ -470,6 +1171,30 @@ static int tasdevice_dsp_create_ctrls( dsp_ctrls[mix_index].put = tasdevice_configuration_put; mix_index++; + active_dev_num = devm_kstrdup(tas_priv->dev, "Activate Tasdevice Num", + GFP_KERNEL); + if (!active_dev_num) { + ret = -ENOMEM; + goto out; + } + dsp_ctrls[mix_index].name = active_dev_num; + dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + dsp_ctrls[mix_index].info = tasdevice_info_active_num; + dsp_ctrls[mix_index].get = tasdevice_active_num_get; + dsp_ctrls[mix_index].put = tasdevice_active_num_put; + mix_index++; + + chip_id = devm_kstrdup(tas_priv->dev, "Tasdevice Chip Id", GFP_KERNEL); + if (!chip_id) { + ret = -ENOMEM; + goto out; + } + dsp_ctrls[mix_index].name = chip_id; + dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + dsp_ctrls[mix_index].info = tasdevice_info_chip_id; + dsp_ctrls[mix_index].get = tasdevice_get_chip_id; + mix_index++; + ret = snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls, nr_controls < mix_index ? nr_controls : mix_index); @@ -477,6 +1202,149 @@ out: return ret; } +static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) +{ + struct calidata *cali_data = &priv->cali_data; + struct tasdevice *tasdev = priv->tasdevice; + struct soc_bytes_ext *ext_cali_data; + struct snd_kcontrol_new *cali_ctrls; + unsigned int nctrls; + char *cali_name; + int rc, i; + + rc = snd_soc_add_component_controls(priv->codec, + tasdevice_cali_controls, ARRAY_SIZE(tasdevice_cali_controls)); + if (rc < 0) { + dev_err(priv->dev, "%s: Add cali controls err rc = %d", + __func__, rc); + return rc; + } + + if (priv->chip_id == TAS2781) { + cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls; + nctrls = ARRAY_SIZE(tas2781_cali_controls); + for (i = 0; i < priv->ndev; i++) { + tasdev[i].cali_data_backup = + kmemdup(tas2781_cali_start_reg, + sizeof(tas2781_cali_start_reg), GFP_KERNEL); + if (!tasdev[i].cali_data_backup) + return -ENOMEM; + } + } else { + cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls; + nctrls = ARRAY_SIZE(tas2563_cali_controls); + for (i = 0; i < priv->ndev; i++) { + tasdev[i].cali_data_backup = + kmemdup(tas2563_cali_start_reg, + sizeof(tas2563_cali_start_reg), GFP_KERNEL); + if (!tasdev[i].cali_data_backup) + return -ENOMEM; + } + } + + rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, nctrls); + if (rc < 0) { + dev_err(priv->dev, "%s: Add chip cali ctrls err rc = %d", + __func__, rc); + return rc; + } + + /* index for cali_ctrls */ + i = 0; + if (priv->chip_id == TAS2781) + nctrls = 2; + else + nctrls = 1; + + /* + * Alloc kcontrol via devm_kzalloc(), which don't manually + * free the kcontrol。 + */ + cali_ctrls = devm_kcalloc(priv->dev, nctrls, + sizeof(cali_ctrls[0]), GFP_KERNEL); + if (!cali_ctrls) + return -ENOMEM; + + ext_cali_data = devm_kzalloc(priv->dev, sizeof(*ext_cali_data), + GFP_KERNEL); + if (!ext_cali_data) + return -ENOMEM; + + cali_name = devm_kstrdup(priv->dev, "Speaker Calibrated Data", + GFP_KERNEL); + if (!cali_name) + return -ENOMEM; + /* the number of calibrated data per tas2563/tas2781 */ + cali_data->cali_dat_sz_per_dev = 20; + /* + * Data structure for tas2563/tas2781 calibrated data: + * Pkg len (1 byte) + * Reg id (1 byte, constant 'r') + * book, page, register array for calibrated data (15 bytes) + * for (i = 0; i < Device-Sum; i++) { + * Device #i index_info (1 byte) + * Calibrated data for Device #i (20 bytes) + * } + */ + ext_cali_data->max = priv->ndev * + (cali_data->cali_dat_sz_per_dev + 1) + 1 + 15 + 1; + priv->cali_data.total_sz = priv->ndev * + (cali_data->cali_dat_sz_per_dev + 1); + priv->cali_data.data = devm_kzalloc(priv->dev, + ext_cali_data->max, GFP_KERNEL); + cali_ctrls[i].name = cali_name; + cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cali_ctrls[i].info = snd_soc_bytes_info_ext; + cali_ctrls[i].get = tasdev_cali_data_get; + cali_ctrls[i].put = tasdev_cali_data_put; + cali_ctrls[i].private_value = (unsigned long)ext_cali_data; + i++; + + cali_data->data = devm_kzalloc(priv->dev, cali_data->total_sz, + GFP_KERNEL); + if (!cali_data->data) + return -ENOMEM; + + if (priv->chip_id == TAS2781) { + struct soc_bytes_ext *ext_cali_start; + char *cali_start_name; + + ext_cali_start = devm_kzalloc(priv->dev, + sizeof(*ext_cali_start), GFP_KERNEL); + if (!ext_cali_start) + return -ENOMEM; + + cali_start_name = devm_kstrdup(priv->dev, + "Calibration Start", GFP_KERNEL); + if (!cali_start_name) + return -ENOMEM; + /* + * package structure for tas2781 ftc start: + * Pkg len (1 byte) + * Reg id (1 byte, constant 'r') + * book, page, register for pilot threshold, pilot tone + * and sine gain (12 bytes) + * for (i = 0; i < Device-Sum; i++) { + * Device #i index_info (1 byte) + * Sine gain for Device #i (8 bytes) + * } + */ + ext_cali_start->max = 14 + priv->ndev * 9; + cali_ctrls[i].name = cali_start_name; + cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cali_ctrls[i].info = snd_soc_bytes_info_ext; + cali_ctrls[i].put = tas2781_calib_start_put; + cali_ctrls[i].get = tasdev_nop_get; + cali_ctrls[i].private_value = (unsigned long)ext_cali_start; + i++; + } + + rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, + nctrls < i ? nctrls : i); + + return rc; +} + static void tasdevice_fw_ready(const struct firmware *fmw, void *context) { @@ -523,6 +1391,12 @@ static void tasdevice_fw_ready(const struct firmware *fmw, goto out; } + ret = tasdevice_create_cali_ctrls(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "cali controls error\n"); + goto out; + } + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; /* If calibrated data occurs error, dsp will still works with default @@ -583,13 +1457,13 @@ static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = { SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event), SND_SOC_DAPM_OUTPUT("OUT"), - SND_SOC_DAPM_INPUT("DMIC") + SND_SOC_DAPM_INPUT("DMIC"), }; static const struct snd_soc_dapm_route tasdevice_audio_map[] = { {"SPK", NULL, "ASI"}, {"OUT", NULL, "SPK"}, - {"ASI OUT", NULL, "DMIC"} + {"ASI OUT", NULL, "DMIC"}, }; static int tasdevice_startup(struct snd_pcm_substream *substream, @@ -672,7 +1546,7 @@ static const struct snd_soc_dai_ops tasdevice_dai_ops = { static struct snd_soc_dai_driver tasdevice_dai_driver[] = { { - .name = "tas2781_codec", + .name = "tasdev_codec", .id = 0, .playback = { .stream_name = "Playback", @@ -724,6 +1598,11 @@ static int tasdevice_codec_probe(struct snd_soc_component *codec) static void tasdevice_deinit(void *context) { struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; + struct tasdevice *tasdev = tas_priv->tasdevice; + int i; + + for (i = 0; i < tas_priv->ndev; i++) + kfree(tasdev[i].cali_data_backup); tasdevice_config_info_remove(tas_priv); tasdevice_dsp_remove(tas_priv); @@ -731,8 +1610,7 @@ static void tasdevice_deinit(void *context) tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; } -static void tasdevice_codec_remove( - struct snd_soc_component *codec) +static void tasdevice_codec_remove(struct snd_soc_component *codec) { struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); @@ -757,7 +1635,7 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) { struct i2c_client *client = (struct i2c_client *)tas_priv->client; unsigned int dev_addrs[TASDEVICE_MAX_CHANNELS]; - int rc, i, ndev = 0; + int i, ndev = 0; if (tas_priv->isacpi) { ndev = device_property_read_u32_array(&client->dev, @@ -772,7 +1650,7 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) "ti,audio-slots", dev_addrs, ndev); } - tas_priv->irq_info.irq_gpio = + tas_priv->irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0); } else if (IS_ENABLED(CONFIG_OF)) { struct device_node *np = tas_priv->dev->of_node; @@ -784,7 +1662,7 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) dev_addrs[ndev++] = addr; } - tas_priv->irq_info.irq_gpio = of_irq_get(np, 0); + tas_priv->irq = of_irq_get(np, 0); } else { ndev = 1; dev_addrs[0] = client->addr; @@ -794,29 +1672,12 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) tas_priv->tasdevice[i].dev_addr = dev_addrs[i]; tas_priv->reset = devm_gpiod_get_optional(&client->dev, - "reset-gpios", GPIOD_OUT_HIGH); + "reset", GPIOD_OUT_HIGH); if (IS_ERR(tas_priv->reset)) dev_err(tas_priv->dev, "%s Can't get reset GPIO\n", __func__); strcpy(tas_priv->dev_name, tasdevice_id[tas_priv->chip_id].name); - - if (gpio_is_valid(tas_priv->irq_info.irq_gpio)) { - rc = gpio_request(tas_priv->irq_info.irq_gpio, - "AUDEV-IRQ"); - if (!rc) { - gpio_direction_input( - tas_priv->irq_info.irq_gpio); - - tas_priv->irq_info.irq = - gpio_to_irq(tas_priv->irq_info.irq_gpio); - } else - dev_err(tas_priv->dev, "%s: GPIO %d request error\n", - __func__, tas_priv->irq_info.irq_gpio); - } else - dev_err(tas_priv->dev, - "Looking up irq-gpio property failed %d\n", - tas_priv->irq_info.irq_gpio); } static int tasdevice_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 4bc1fdd232bb..b97c0e885713 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -463,9 +463,9 @@ static void tas5086_reset(struct tas5086_private *priv) { if (priv->reset) { /* Reset codec - minimum assertion time is 400ns */ - gpiod_direction_output(priv->reset, 1); + gpiod_set_value_cansleep(priv->reset, 1); udelay(1); - gpiod_set_value(priv->reset, 0); + gpiod_set_value_cansleep(priv->reset, 0); /* Codec needs ~15ms to wake up */ msleep(15); @@ -866,9 +866,10 @@ static void tas5086_remove(struct snd_soc_component *component) { struct tas5086_private *priv = snd_soc_component_get_drvdata(component); - if (priv->reset) + if (priv->reset) { /* Set codec to the reset state */ - gpiod_set_value(priv->reset, 1); + gpiod_set_value_cansleep(priv->reset, 1); + } regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); }; diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 2f94cfda0e33..187d68e8688c 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -12,6 +12,7 @@ * and mono/stereo Class-D speaker driver. */ +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -893,7 +895,7 @@ static int aic31xx_setup_pll(struct snd_soc_component *component, dev_err(component->dev, "%s: Sample rate (%u) and format not supported\n", __func__, params_rate(params)); - /* See bellow for details how fix this. */ + /* See below for details on how to fix this. */ return -EINVAL; } if (bclk_score != 0) { @@ -1638,6 +1640,98 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); +static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx, + const u8 *data, size_t size) +{ + int ret, reg; + u16 val16; + + /* + * Coefficients firmware binary structure. Multi-byte values are big-endian. + * + * @0, 16bits: Magic (0xB30C) + * @2, 16bits: Version (0x0100 for version 1.0) + * @4, 8bits: DAC Processing Block Selection + * @5, 62 16-bit values: Page 8 buffer A DAC programmable filter coefficients + * @129, 12 16-bit values: Page 9 Buffer A DAC programmable filter coefficients + * + * Filter coefficients are interpreted as two's complement values + * ranging from -32 768 to 32 767. For more details on filter coefficients, + * please refer to the TLV320DAC3100 datasheet, tables 6-120 and 6-123. + */ + + if (size != 153) { + dev_err(aic31xx->dev, "firmware size is %zu, expected 153 bytes\n", size); + return -EINVAL; + } + + /* Check magic */ + val16 = get_unaligned_be16(data); + if (val16 != 0xb30c) { + dev_err(aic31xx->dev, "fw magic is 0x%04x expected 0xb30c\n", val16); + return -EINVAL; + } + data += 2; + + /* Check version */ + val16 = get_unaligned_be16(data); + if (val16 != 0x0100) { + dev_err(aic31xx->dev, "invalid firmware version 0x%04x! expected 1", val16); + return -EINVAL; + } + data += 2; + + ret = regmap_write(aic31xx->regmap, AIC31XX_DACPRB, *data); + if (ret) { + dev_err(aic31xx->dev, "failed to write PRB index: err %d\n", ret); + return ret; + } + data += 1; + + /* Page 8 Buffer A coefficients */ + for (reg = 2; reg < 126; reg++) { + ret = regmap_write(aic31xx->regmap, AIC31XX_REG(8, reg), *data); + if (ret) { + dev_err(aic31xx->dev, + "failed to write page 8 filter coefficient %d: err %d\n", reg, ret); + return ret; + } + data++; + } + + /* Page 9 Buffer A coefficients */ + for (reg = 2; reg < 26; reg++) { + ret = regmap_write(aic31xx->regmap, AIC31XX_REG(9, reg), *data); + if (ret) { + dev_err(aic31xx->dev, + "failed to write page 9 filter coefficient %d: err %d\n", reg, ret); + return ret; + } + data++; + } + + dev_info(aic31xx->dev, "done loading DAC filter coefficients\n"); + + return ret; +} + +static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx, + const char *fw_name) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, fw_name, aic31xx->dev); + if (ret) + return ret; + + ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size); + + release_firmware(fw); + + return ret; +} + static int aic31xx_i2c_probe(struct i2c_client *i2c) { struct aic31xx_priv *aic31xx; @@ -1727,6 +1821,12 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c) } } + if (aic31xx->codec_type == DAC3100) { + ret = tlv320dac3100_load_coeffs(aic31xx, "tlv320dac3100-coeffs.bin"); + if (ret) + dev_warn(aic31xx->dev, "Did not load any filter coefficients\n"); + } + if (aic31xx->codec_type & DAC31XX_BIT) return devm_snd_soc_register_component(&i2c->dev, &soc_codec_driver_aic31xx, diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 5c0c81da06db..54ea4bc58c27 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1073,6 +1073,13 @@ static int aic32x4_component_probe(struct snd_soc_component *component) return 0; } +static int aic32x4_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) +{ + /* return dai id 0, whatever the endpoint index */ + return 0; +} + static const struct snd_soc_component_driver soc_component_dev_aic32x4 = { .probe = aic32x4_component_probe, .set_bias_level = aic32x4_set_bias_level, @@ -1082,6 +1089,7 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = { .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), .dapm_routes = aic32x4_dapm_routes, .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), + .of_xlate_dai_id = aic32x4_of_xlate_dai_id, .suspend_bias_off = 1, .idle_bias_on = 1, .use_pmdown_time = 1, @@ -1203,6 +1211,7 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = .num_dapm_widgets = ARRAY_SIZE(aic32x4_tas2505_dapm_widgets), .dapm_routes = aic32x4_tas2505_dapm_routes, .num_dapm_routes = ARRAY_SIZE(aic32x4_tas2505_dapm_routes), + .of_xlate_dai_id = aic32x4_of_xlate_dai_id, .suspend_bias_off = 1, .idle_bias_on = 1, .use_pmdown_time = 1, diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 291d0c80a6fc..910852eb9698 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2643,8 +2643,8 @@ static void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x, s16 c1; s32 x1, d1; int32_t denom; - int minCode_param[] = { - 3277, 1639, 820, 410, 205, 103, 52, 26 + static const int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 }; regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x20); diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index af296b77a723..45f32d281908 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2957,7 +2957,7 @@ MODULE_DEVICE_TABLE(of, wcd937x_of_match); static struct platform_driver wcd937x_codec_driver = { .probe = wcd937x_probe, - .remove_new = wcd937x_remove, + .remove = wcd937x_remove, .driver = { .name = "wcd937x_codec", .of_match_table = of_match_ptr(wcd937x_of_match), diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 37bff16e88dd..35f3d48bd7dd 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -484,10 +484,25 @@ #define WCD937X_MAX_MICBIAS 3 #define WCD937X_MAX_BULK_SUPPLY 4 -#define WCD937X_MAX_TX_SWR_PORTS 4 -#define WCD937X_MAX_SWR_PORTS 5 #define WCD937X_MAX_SWR_CH_IDS 15 +enum wcd937x_tx_sdw_ports { + WCD937X_ADC_1_PORT = 1, + WCD937X_ADC_2_3_PORT, + WCD937X_DMIC_0_3_MBHC_PORT, + WCD937X_DMIC_4_6_PORT, + WCD937X_MAX_TX_SWR_PORTS = WCD937X_DMIC_4_6_PORT, +}; + +enum wcd937x_rx_sdw_ports { + WCD937X_HPH_PORT = 1, + WCD937X_CLSH_PORT, + WCD937X_COMP_PORT, + WCD937X_LO_PORT, + WCD937X_DSD_PORT, + WCD937X_MAX_SWR_PORTS = WCD937X_DSD_PORT, +}; + struct wcd937x_sdw_ch_info { int port_num; unsigned int ch_mask; @@ -581,13 +596,6 @@ enum { WCD937X_NUM_IRQS, }; -enum wcd937x_tx_sdw_ports { - WCD937X_ADC_1_PORT = 1, - WCD937X_ADC_2_3_PORT, - WCD937X_DMIC_0_3_MBHC_PORT, - WCD937X_DMIC_4_6_PORT, -}; - enum wcd937x_tx_sdw_channels { WCD937X_ADC1, WCD937X_ADC2, @@ -602,14 +610,6 @@ enum wcd937x_tx_sdw_channels { WCD937X_DMIC6, }; -enum wcd937x_rx_sdw_ports { - WCD937X_HPH_PORT = 1, - WCD937X_CLSH_PORT, - WCD937X_COMP_PORT, - WCD937X_LO_PORT, - WCD937X_DSD_PORT, -}; - enum wcd937x_rx_sdw_channels { WCD937X_HPH_L, WCD937X_HPH_R, diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 12b32d5dc580..f2a4f3262bdb 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -29,7 +29,6 @@ #define WCD938X_MAX_SUPPLY (4) #define WCD938X_MBHC_MAX_BUTTONS (8) #define TX_ADC_MAX (4) -#define WCD938X_TX_MAX_SWR_PORTS (5) #define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -39,8 +38,6 @@ SNDRV_PCM_RATE_176400) #define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE) -/* Convert from vout ctl to micbias voltage in mV */ -#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) #define SWR_CLK_RATE_0P6MHZ (600000) #define SWR_CLK_RATE_1P2MHZ (1200000) #define SWR_CLK_RATE_2P4MHZ (2400000) @@ -48,8 +45,6 @@ #define SWR_CLK_RATE_9P6MHZ (9600000) #define SWR_CLK_RATE_11P2896MHZ (1128960) -#define WCD938X_DRV_NAME "wcd938x_codec" -#define WCD938X_VERSION_1_0 (1) #define EAR_RX_PATH_AUX (1) #define ADC_MODE_VAL_HIFI 0x01 @@ -72,7 +67,6 @@ /* Z value compared in milliOhm */ #define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) #define WCD938X_MBHC_ZDET_CONST (86 * 16384) -#define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM #define WCD_MBHC_HS_V_MAX 1600 #define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ @@ -89,18 +83,6 @@ enum { WCD9385 = 5, }; -enum { - TX_HDR12 = 0, - TX_HDR34, - TX_HDR_MAX, -}; - -enum { - WCD_RX1, - WCD_RX2, - WCD_RX3 -}; - enum { /* INTR_CTRL_INT_MASK_0 */ WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, @@ -3614,7 +3596,7 @@ MODULE_DEVICE_TABLE(of, wcd938x_dt_match); static struct platform_driver wcd938x_codec_driver = { .probe = wcd938x_probe, - .remove_new = wcd938x_remove, + .remove = wcd938x_remove, .driver = { .name = "wcd938x_codec", .of_match_table = of_match_ptr(wcd938x_dt_match), diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index b2ad98026ae2..fb6a0e4ef337 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -585,8 +585,6 @@ #define WCD938X_DIGITAL_DEM_BYPASS_DATA3 (0x34D8) #define WCD938X_MAX_REGISTER (WCD938X_DIGITAL_DEM_BYPASS_DATA3) -#define WCD938X_MAX_SWR_PORTS 5 -#define WCD938X_MAX_TX_SWR_PORTS 4 #define WCD938X_MAX_SWR_CH_IDS 15 struct wcd938x_sdw_ch_info { @@ -606,6 +604,7 @@ enum wcd938x_tx_sdw_ports { /* DMIC0_0, DMIC0_1, DMIC1_0, DMIC1_1 */ WCD938X_DMIC_0_3_MBHC_PORT, WCD938X_DMIC_4_7_PORT, + WCD938X_MAX_TX_SWR_PORTS = WCD938X_DMIC_4_7_PORT, }; enum wcd938x_tx_sdw_channels { @@ -630,6 +629,7 @@ enum wcd938x_rx_sdw_ports { WCD938X_COMP_PORT, WCD938X_LO_PORT, WCD938X_DSD_PORT, + WCD938X_MAX_SWR_PORTS = WCD938X_DSD_PORT, }; enum wcd938x_rx_sdw_channels { diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 68fc591670dc..4a417a92514d 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -3683,7 +3683,7 @@ MODULE_DEVICE_TABLE(of, wcd939x_dt_match); static struct platform_driver wcd939x_codec_driver = { .probe = wcd939x_probe, - .remove_new = wcd939x_remove, + .remove = wcd939x_remove, .driver = { .name = "wcd939x_codec", .of_match_table = of_match_ptr(wcd939x_dt_match), diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h index 1571c2120cfc..3204fb10b58d 100644 --- a/sound/soc/codecs/wcd939x.h +++ b/sound/soc/codecs/wcd939x.h @@ -842,9 +842,6 @@ #define WCD939X_DSD_HPHR_CFG5 (0x35a6) #define WCD939X_MAX_REGISTER (WCD939X_DSD_HPHR_CFG5) -#define WCD939X_MAX_SWR_PORTS (6) -#define WCD939X_MAX_RX_SWR_PORTS (6) -#define WCD939X_MAX_TX_SWR_PORTS (4) #define WCD939X_MAX_SWR_CH_IDS (15) struct wcd939x_sdw_ch_info { @@ -863,6 +860,7 @@ enum wcd939x_tx_sdw_ports { WCD939X_ADC_DMIC_1_2_PORT, WCD939X_DMIC_0_3_MBHC_PORT, WCD939X_DMIC_3_7_PORT, + WCD939X_MAX_TX_SWR_PORTS = WCD939X_DMIC_3_7_PORT, }; enum wcd939x_tx_sdw_channels { @@ -888,6 +886,8 @@ enum wcd939x_rx_sdw_ports { WCD939X_LO_PORT, WCD939X_DSD_PORT, WCD939X_HIFI_PCM_PORT, + WCD939X_MAX_RX_SWR_PORTS = WCD939X_HIFI_PCM_PORT, + WCD939X_MAX_SWR_PORTS = WCD939X_MAX_RX_SWR_PORTS, }; enum wcd939x_rx_sdw_channels { diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 4ecf07c7448c..651f1319204d 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2174,7 +2174,7 @@ static struct platform_driver wm5102_codec_driver = { .name = "wm5102-codec", }, .probe = wm5102_probe, - .remove_new = wm5102_remove, + .remove = wm5102_remove, }; module_platform_driver(wm5102_codec_driver); diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 0f299cd07b2e..502196253d42 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2534,7 +2534,7 @@ static struct platform_driver wm5110_codec_driver = { .name = "wm5110-codec", }, .probe = wm5110_probe, - .remove_new = wm5110_remove, + .remove = wm5110_remove, }; module_platform_driver(wm5110_codec_driver); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a99908582a50..a4abe6e53bfc 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4699,7 +4699,7 @@ static struct platform_driver wm8994_codec_driver = { .pm = &wm8994_pm_ops, }, .probe = wm8994_probe, - .remove_new = wm8994_remove, + .remove = wm8994_remove, }; module_platform_driver(wm8994_codec_driver); diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 87442840f0af..5389c363b14e 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1210,7 +1210,7 @@ static struct platform_driver wm8997_codec_driver = { .name = "wm8997-codec", }, .probe = wm8997_probe, - .remove_new = wm8997_remove, + .remove = wm8997_remove, }; module_platform_driver(wm8997_codec_driver); diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 3c2c4d12c08e..b72b8a64be8f 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1426,7 +1426,7 @@ static struct platform_driver wm8998_codec_driver = { .name = "wm8998-codec", }, .probe = wm8998_probe, - .remove_new = wm8998_remove, + .remove = wm8998_remove, }; module_platform_driver(wm8998_codec_driver); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index fb9e92f08d98..dd2d6661adc7 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -386,33 +386,32 @@ enum wsa_port_ids { /* 4 ports */ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = { - { - /* DAC */ - .num = 1, + [WSA881X_PORT_DAC] = { + .num = WSA881X_PORT_DAC + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* COMP */ - .num = 2, + }, + [WSA881X_PORT_COMP] = { + .num = WSA881X_PORT_COMP + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* BOOST */ - .num = 3, + }, + [WSA881X_PORT_BOOST] = { + .num = WSA881X_PORT_BOOST + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* VISENSE */ - .num = 4, + }, + [WSA881X_PORT_VISENSE] = { + .num = WSA881X_PORT_VISENSE + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, @@ -422,17 +421,20 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = { }; static const struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = { - { - .num = 1, + [WSA881X_PORT_DAC] = { + .num = WSA881X_PORT_DAC + 1, .ch_mask = 0x1, - }, { - .num = 2, + }, + [WSA881X_PORT_COMP] = { + .num = WSA881X_PORT_COMP + 1, .ch_mask = 0xf, - }, { - .num = 3, + }, + [WSA881X_PORT_BOOST] = { + .num = WSA881X_PORT_BOOST + 1, .ch_mask = 0x3, - }, { /* IV feedback */ - .num = 4, + }, + [WSA881X_PORT_VISENSE] = { + .num = WSA881X_PORT_VISENSE + 1, .ch_mask = 0x3, }, }; @@ -680,7 +682,6 @@ struct wsa881x_priv { * For backwards compatibility. */ unsigned int sd_n_val; - int version; int active_ports; bool port_prepared[WSA881X_MAX_SWR_PORTS]; bool port_enable[WSA881X_MAX_SWR_PORTS]; @@ -691,7 +692,6 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) struct regmap *rm = wsa881x->regmap; unsigned int val = 0; - regmap_read(rm, WSA881X_CHIP_ID1, &wsa881x->version); regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0, ARRAY_SIZE(wsa881x_rev_2_0)); diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 3e4fdaa3f44f..47da5674d7c9 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -438,8 +438,6 @@ struct wsa883x_priv { struct gpio_desc *sd_n; bool port_prepared[WSA883X_MAX_SWR_PORTS]; bool port_enable[WSA883X_MAX_SWR_PORTS]; - int version; - int variant; int active_ports; int dev_mode; int comp_offset; @@ -482,33 +480,32 @@ static const struct soc_enum wsa_dev_mode_enum = /* 4 ports */ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = { - { - /* DAC */ - .num = 1, + [WSA883X_PORT_DAC] = { + .num = WSA883X_PORT_DAC + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* COMP */ - .num = 2, + }, + [WSA883X_PORT_COMP] = { + .num = WSA883X_PORT_COMP + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* BOOST */ - .num = 3, + }, + [WSA883X_PORT_BOOST] = { + .num = WSA883X_PORT_BOOST + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { - /* VISENSE */ - .num = 4, + }, + [WSA883X_PORT_VISENSE] = { + .num = WSA883X_PORT_VISENSE + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, @@ -518,17 +515,20 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = { }; static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = { - { - .num = 1, + [WSA883X_PORT_DAC] = { + .num = WSA883X_PORT_DAC + 1, .ch_mask = 0x1, - }, { - .num = 2, + }, + [WSA883X_PORT_COMP] = { + .num = WSA883X_PORT_COMP + 1, .ch_mask = 0xf, - }, { - .num = 3, + }, + [WSA883X_PORT_BOOST] = { + .num = WSA883X_PORT_BOOST + 1, .ch_mask = 0x3, - }, { /* IV feedback */ - .num = 4, + }, + [WSA883X_PORT_VISENSE] = { + .num = WSA883X_PORT_VISENSE + 1, .ch_mask = 0x3, }, }; @@ -997,33 +997,36 @@ static const struct reg_sequence reg_init[] = { {WSA883X_GMAMP_SUP1, 0xE2}, }; -static void wsa883x_init(struct wsa883x_priv *wsa883x) +static int wsa883x_init(struct wsa883x_priv *wsa883x) { struct regmap *regmap = wsa883x->regmap; - int variant, version; + int variant, version, ret; - regmap_read(regmap, WSA883X_OTP_REG_0, &variant); - wsa883x->variant = variant & WSA883X_ID_MASK; + ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); + if (ret) + return ret; + variant = variant & WSA883X_ID_MASK; - regmap_read(regmap, WSA883X_CHIP_ID0, &version); - wsa883x->version = version; + ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version); + if (ret) + return ret; - switch (wsa883x->variant) { + switch (variant) { case WSA8830: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n", - wsa883x->version); + version); break; case WSA8835: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n", - wsa883x->version); + version); break; case WSA8832: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n", - wsa883x->version); + version); break; case WSA8835_V2: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n", - wsa883x->version); + version); break; default: break; @@ -1034,12 +1037,14 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x) /* Initial settings */ regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init)); - if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) { + if (variant == WSA8830 || variant == WSA8832) { wsa883x->comp_offset = COMP_OFFSET3; regmap_update_bits(regmap, WSA883X_DRE_CTL_0, WSA883X_DRE_OFFSET_MASK, wsa883x->comp_offset); } + + return 0; } static int wsa883x_update_status(struct sdw_slave *slave, @@ -1048,7 +1053,7 @@ static int wsa883x_update_status(struct sdw_slave *slave, struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) - wsa883x_init(wsa883x); + return wsa883x_init(wsa883x); return 0; } diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 89eb5e03a617..86df5152c547 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -5,11 +5,14 @@ */ #include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -301,8 +304,28 @@ #define WSA884X_PA_FSM_MSK1 (WSA884X_DIG_CTRL0_BASE + 0x3b) #define WSA884X_PA_FSM_BYP_CTL (WSA884X_DIG_CTRL0_BASE + 0x3c) #define WSA884X_PA_FSM_BYP0 (WSA884X_DIG_CTRL0_BASE + 0x3d) +#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK 0x01 +#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_SHIFT 0 +#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK 0x02 +#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_SHIFT 1 +#define WSA884X_PA_FSM_BYP0_BG_EN_MASK 0x04 +#define WSA884X_PA_FSM_BYP0_BG_EN_SHIFT 2 +#define WSA884X_PA_FSM_BYP0_BOOST_EN_MASK 0x08 +#define WSA884X_PA_FSM_BYP0_BOOST_EN_SHIFT 3 +#define WSA884X_PA_FSM_BYP0_PA_EN_MASK 0x10 +#define WSA884X_PA_FSM_BYP0_PA_EN_SHIFT 4 +#define WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK 0x20 +#define WSA884X_PA_FSM_BYP0_D_UNMUTE_SHIFT 5 +#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK 0x40 +#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_SHIFT 6 +#define WSA884X_PA_FSM_BYP0_TSADC_EN_MASK 0x80 +#define WSA884X_PA_FSM_BYP0_TSADC_EN_SHIFT 7 #define WSA884X_PA_FSM_BYP1 (WSA884X_DIG_CTRL0_BASE + 0x3e) #define WSA884X_TADC_VALUE_CTL (WSA884X_DIG_CTRL0_BASE + 0x50) +#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01 +#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0 +#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02 +#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1 #define WSA884X_TEMP_DETECT_CTL (WSA884X_DIG_CTRL0_BASE + 0x51) #define WSA884X_TEMP_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x52) #define WSA884X_TEMP_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x53) @@ -691,6 +714,17 @@ SNDRV_PCM_FMTBIT_S24_LE |\ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) +/* Two-point trimming for temperature calibration */ +#define WSA884X_T1_TEMP -10L +#define WSA884X_T2_TEMP 150L + +/* + * Device will report senseless data in many cases, so discard any measurements + * outside of valid range. + */ +#define WSA884X_LOW_TEMP_THRESHOLD 5 +#define WSA884X_HIGH_TEMP_THRESHOLD 45 + struct wsa884x_priv { struct regmap *regmap; struct device *dev; @@ -703,10 +737,16 @@ struct wsa884x_priv { struct reset_control *sd_reset; bool port_prepared[WSA884X_MAX_SWR_PORTS]; bool port_enable[WSA884X_MAX_SWR_PORTS]; - unsigned int variant; int active_ports; int dev_mode; bool hw_init; + /* + * Protects temperature reading code (related to speaker protection) and + * fields: temperature and pa_on. + */ + struct mutex sp_lock; + unsigned int temperature; + bool pa_on; }; enum { @@ -782,42 +822,47 @@ static const struct soc_enum wsa884x_dev_mode_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa884x_dev_mode_text), wsa884x_dev_mode_text); static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = { - { + [WSA884X_PORT_DAC] = { .num = WSA884X_PORT_DAC + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { + }, + [WSA884X_PORT_COMP] = { .num = WSA884X_PORT_COMP + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { + }, + [WSA884X_PORT_BOOST] = { .num = WSA884X_PORT_BOOST + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { + }, + [WSA884X_PORT_PBR] = { .num = WSA884X_PORT_PBR + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { + }, + [WSA884X_PORT_VISENSE] = { .num = WSA884X_PORT_VISENSE + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, .max_ch = 1, .simple_ch_prep_sm = true, .read_only_wordlength = true, - }, { + }, + [WSA884X_PORT_CPS] = { .num = WSA884X_PORT_CPS + 1, .type = SDW_DPN_SIMPLE, .min_ch = 1, @@ -828,22 +873,27 @@ static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = { }; static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = { - { + [WSA884X_PORT_DAC] = { .num = WSA884X_PORT_DAC + 1, .ch_mask = 0x1, - }, { + }, + [WSA884X_PORT_COMP] = { .num = WSA884X_PORT_COMP + 1, .ch_mask = 0xf, - }, { + }, + [WSA884X_PORT_BOOST] = { .num = WSA884X_PORT_BOOST + 1, .ch_mask = 0x3, - }, { + }, + [WSA884X_PORT_PBR] = { .num = WSA884X_PORT_PBR + 1, .ch_mask = 0x1, - }, { + }, + [WSA884X_PORT_VISENSE] = { .num = WSA884X_PORT_VISENSE + 1, .ch_mask = 0x3, - }, { + }, + [WSA884X_PORT_CPS] = { .num = WSA884X_PORT_CPS + 1, .ch_mask = 0x3, }, @@ -1465,7 +1515,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) unsigned int variant = 0; if (!regmap_read(wsa884x->regmap, WSA884X_OTP_REG_0, &variant)) - wsa884x->variant = variant & WSA884X_OTP_REG_0_ID_MASK; + variant = variant & WSA884X_OTP_REG_0_ID_MASK; regmap_multi_reg_write(wsa884x->regmap, wsa884x_reg_init, ARRAY_SIZE(wsa884x_reg_init)); @@ -1474,7 +1524,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK, WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER); /* Assume that compander is enabled by default unless it is haptics sku */ - if (wsa884x->variant == WSA884X_OTP_ID_WSA8845H) + if (variant == WSA884X_OTP_ID_WSA8845H) wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK, WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB); else @@ -1651,6 +1701,10 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: + mutex_lock(&wsa884x->sp_lock); + wsa884x->pa_on = true; + mutex_unlock(&wsa884x->sp_lock); + wsa884x_spkr_post_pmu(component, wsa884x); snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, @@ -1662,6 +1716,10 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, 0x0); + + mutex_lock(&wsa884x->sp_lock); + wsa884x->pa_on = false; + mutex_unlock(&wsa884x->sp_lock); break; } @@ -1801,6 +1859,144 @@ static struct snd_soc_dai_driver wsa884x_dais[] = { }, }; +static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp) +{ + unsigned int d1_msb = 0, d1_lsb = 0, d2_msb = 0, d2_lsb = 0; + unsigned int dmeas_msb = 0, dmeas_lsb = 0; + int d1, d2, dmeas; + unsigned int mask; + long val; + int ret; + + guard(mutex)(&wsa884x->sp_lock); + + if (wsa884x->pa_on) { + /* + * Reading temperature is possible only when Power Amplifier is + * off. Report last cached data. + */ + *temp = wsa884x->temperature; + return 0; + } + + ret = pm_runtime_resume_and_get(wsa884x->dev); + if (ret < 0) + return ret; + + mask = WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK | + WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK | + WSA884X_PA_FSM_BYP0_BG_EN_MASK | + WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK | + WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK | + WSA884X_PA_FSM_BYP0_TSADC_EN_MASK; + /* + * Here and further do not care about read or update failures. + * For example, before turning on Power Amplifier for the first + * time, reading WSA884X_TEMP_DIN_MSB will always return 0. + * Instead, check if returned value is within reasonable + * thresholds. + */ + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, mask); + + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0)); + + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_MSB, &dmeas_msb); + regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_LSB, &dmeas_lsb); + + regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL, + WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1)); + + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_1, &d1_msb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_2, &d1_lsb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_3, &d2_msb); + regmap_read(wsa884x->regmap, WSA884X_OTP_REG_4, &d2_lsb); + + regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, 0x0); + + dmeas = (((dmeas_msb & 0xff) << 0x8) | (dmeas_lsb & 0xff)) >> 0x6; + d1 = (((d1_msb & 0xff) << 0x8) | (d1_lsb & 0xff)) >> 0x6; + d2 = (((d2_msb & 0xff) << 0x8) | (d2_lsb & 0xff)) >> 0x6; + + if (d1 == d2) { + /* Incorrect data in OTP? */ + ret = -EINVAL; + goto out; + } + + val = WSA884X_T1_TEMP + (((dmeas - d1) * (WSA884X_T2_TEMP - WSA884X_T1_TEMP))/(d2 - d1)); + + dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n", + val, dmeas, d1, d2); + + if ((val > WSA884X_LOW_TEMP_THRESHOLD) && + (val < WSA884X_HIGH_TEMP_THRESHOLD)) { + wsa884x->temperature = val; + *temp = val; + ret = 0; + } else { + ret = -EAGAIN; + } + +out: + pm_runtime_mark_last_busy(wsa884x->dev); + pm_runtime_put_autosuspend(wsa884x->dev); + + return ret; +} + +static umode_t wsa884x_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + break; + } + + return 0; +} + +static int wsa884x_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = wsa884x_get_temp(dev_get_drvdata(dev), temp); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static const struct hwmon_channel_info *const wsa884x_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops wsa884x_hwmon_ops = { + .is_visible = wsa884x_hwmon_is_visible, + .read = wsa884x_hwmon_read, +}; + +static const struct hwmon_chip_info wsa884x_hwmon_chip_info = { + .ops = &wsa884x_hwmon_ops, + .info = wsa884x_hwmon_info, +}; + static void wsa884x_reset_powerdown(void *data) { struct wsa884x_priv *wsa884x = data; @@ -1857,6 +2053,8 @@ static int wsa884x_probe(struct sdw_slave *pdev, if (!wsa884x) return -ENOMEM; + mutex_init(&wsa884x->sp_lock); + for (i = 0; i < WSA884X_SUPPLIES_NUM; i++) wsa884x->supplies[i].supply = wsa884x_supply_name[i]; @@ -1914,6 +2112,18 @@ static int wsa884x_probe(struct sdw_slave *pdev, regcache_cache_only(wsa884x->regmap, true); wsa884x->hw_init = true; + if (IS_REACHABLE(CONFIG_HWMON)) { + struct device *hwmon; + + hwmon = devm_hwmon_device_register_with_info(dev, "wsa884x", + wsa884x, + &wsa884x_hwmon_chip_info, + NULL); + if (IS_ERR(hwmon)) + return dev_err_probe(dev, PTR_ERR(hwmon), + "Failed to register hwmon sensor\n"); + } + pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); pm_runtime_mark_last_busy(dev); diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index c04466f5492e..57b789d7fbed 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -995,16 +995,12 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_assert_reset; } } - dev->clk = devm_clk_get(&pdev->dev, clk_id); + dev->clk = devm_clk_get_enabled(&pdev->dev, clk_id); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); goto err_assert_reset; } - - ret = clk_prepare_enable(dev->clk); - if (ret < 0) - goto err_assert_reset; } dev_set_drvdata(&pdev->dev, dev); @@ -1012,7 +1008,7 @@ static int dw_i2s_probe(struct platform_device *pdev) dw_i2s_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); - goto err_clk_disable; + goto err_assert_reset; } if (!pdata || dev->is_jh7110) { @@ -1030,16 +1026,13 @@ static int dw_i2s_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "could not register pcm: %d\n", ret); - goto err_clk_disable; + goto err_assert_reset; } } pm_runtime_enable(&pdev->dev); return 0; -err_clk_disable: - if (dev->capability & DW_I2S_MASTER) - clk_disable_unprepare(dev->clk); err_assert_reset: reset_control_assert(dev->reset); return ret; @@ -1049,9 +1042,6 @@ static void dw_i2s_remove(struct platform_device *pdev) { struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); - if (dev->capability & DW_I2S_MASTER) - clk_disable_unprepare(dev->clk); - reset_control_assert(dev->reset); pm_runtime_disable(&pdev->dev); } @@ -1099,7 +1089,7 @@ static const struct dev_pm_ops dwc_pm_ops = { static struct platform_driver dw_i2s_driver = { .probe = dw_i2s_probe, - .remove_new = dw_i2s_remove, + .remove = dw_i2s_remove, .driver = { .name = "designware-i2s", .of_match_table = of_match_ptr(dw_i2s_of_match), diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b793263291dc..bd5c46d763c0 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1392,7 +1392,7 @@ MODULE_DEVICE_TABLE(of, fsl_asrc_ids); static struct platform_driver fsl_asrc_driver = { .probe = fsl_asrc_probe, - .remove_new = fsl_asrc_remove, + .remove = fsl_asrc_remove, .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index a6cbaa6364c7..021d73e409aa 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -296,7 +296,7 @@ static const struct dev_pm_ops fsl_aud2htx_pm_ops = { static struct platform_driver fsl_aud2htx_driver = { .probe = fsl_aud2htx_probe, - .remove_new = fsl_aud2htx_remove, + .remove = fsl_aud2htx_remove, .driver = { .name = "fsl-aud2htx", .pm = pm_ptr(&fsl_aud2htx_pm_ops), diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 1671a3037c60..3cd9a66b70a1 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -512,7 +512,6 @@ static void fsl_audmix_remove(struct platform_device *pdev) platform_device_unregister(priv->pdev); } -#ifdef CONFIG_PM static int fsl_audmix_runtime_resume(struct device *dev) { struct fsl_audmix *priv = dev_get_drvdata(dev); @@ -540,23 +539,20 @@ static int fsl_audmix_runtime_suspend(struct device *dev) return 0; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_audmix_pm = { - SET_RUNTIME_PM_OPS(fsl_audmix_runtime_suspend, - fsl_audmix_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_audmix_runtime_suspend, fsl_audmix_runtime_resume, + NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_audmix_driver = { .probe = fsl_audmix_probe, - .remove_new = fsl_audmix_remove, + .remove = fsl_audmix_remove, .driver = { .name = "fsl-audmix", .of_match_table = fsl_audmix_ids, - .pm = &fsl_audmix_pm, + .pm = pm_ptr(&fsl_audmix_pm), }, }; module_platform_driver(fsl_audmix_driver); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index c4bc9395dff7..aca066b5a43c 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -911,7 +911,7 @@ static struct platform_driver fsl_soc_dma_driver = { .of_match_table = fsl_soc_dma_ids, }, .probe = fsl_soc_dma_probe, - .remove_new = fsl_soc_dma_remove, + .remove = fsl_soc_dma_remove, }; module_platform_driver(fsl_soc_dma_driver); diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 962f30912091..82359edd6a8b 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2093,7 +2093,7 @@ static const struct dev_pm_ops fsl_easrc_pm_ops = { static struct platform_driver fsl_easrc_driver = { .probe = fsl_easrc_probe, - .remove_new = fsl_easrc_remove, + .remove = fsl_easrc_remove, .driver = { .name = "fsl-easrc", .pm = pm_ptr(&fsl_easrc_pm_ops), diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index d0d8a01da9bd..a65f5b9935a2 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -1198,7 +1198,7 @@ static const struct dev_pm_ops fsl_esai_pm_ops = { static struct platform_driver fsl_esai_driver = { .probe = fsl_esai_probe, - .remove_new = fsl_esai_remove, + .remove = fsl_esai_remove, .driver = { .name = "fsl-esai-dai", .pm = &fsl_esai_pm_ops, diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 22b240a70ad4..193be098fa5e 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1317,7 +1317,7 @@ static const struct dev_pm_ops fsl_micfil_pm_ops = { static struct platform_driver fsl_micfil_driver = { .probe = fsl_micfil_probe, - .remove_new = fsl_micfil_remove, + .remove = fsl_micfil_remove, .driver = { .name = "fsl-micfil-dai", .pm = &fsl_micfil_pm_ops, diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index c95b84a54dc4..145f9ca15e43 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -265,7 +265,6 @@ static void fsl_mqs_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -#ifdef CONFIG_PM static int fsl_mqs_runtime_resume(struct device *dev) { struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); @@ -299,14 +298,10 @@ static int fsl_mqs_runtime_suspend(struct device *dev) return 0; } -#endif static const struct dev_pm_ops fsl_mqs_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_mqs_runtime_suspend, - fsl_mqs_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_mqs_runtime_suspend, fsl_mqs_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { @@ -386,11 +381,11 @@ MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); static struct platform_driver fsl_mqs_driver = { .probe = fsl_mqs_probe, - .remove_new = fsl_mqs_remove, + .remove = fsl_mqs_remove, .driver = { .name = "fsl-mqs", .of_match_table = fsl_mqs_dt_ids, - .pm = &fsl_mqs_pm_ops, + .pm = pm_ptr(&fsl_mqs_pm_ops), }, }; diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 467d6bc9f956..0a551be3053b 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -286,7 +286,6 @@ static void fsl_rpmsg_remove(struct platform_device *pdev) platform_device_unregister(rpmsg->card_pdev); } -#ifdef CONFIG_PM static int fsl_rpmsg_runtime_resume(struct device *dev) { struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev); @@ -321,20 +320,18 @@ static int fsl_rpmsg_runtime_suspend(struct device *dev) return 0; } -#endif static const struct dev_pm_ops fsl_rpmsg_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend, - fsl_rpmsg_runtime_resume, - NULL) + RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend, fsl_rpmsg_runtime_resume, + NULL) }; static struct platform_driver fsl_rpmsg_driver = { .probe = fsl_rpmsg_probe, - .remove_new = fsl_rpmsg_remove, + .remove = fsl_rpmsg_remove, .driver = { .name = "fsl_rpmsg", - .pm = &fsl_rpmsg_pm_ops, + .pm = pm_ptr(&fsl_rpmsg_pm_ops), .of_match_table = fsl_rpmsg_ids, }, }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d03b0172b8ad..ab58a4461073 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1817,7 +1817,7 @@ static const struct dev_pm_ops fsl_sai_pm_ops = { static struct platform_driver fsl_sai_driver = { .probe = fsl_sai_probe, - .remove_new = fsl_sai_remove, + .remove = fsl_sai_remove, .driver = { .name = "fsl-sai", .pm = &fsl_sai_pm_ops, diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index a63121c888e0..b6ff04f7138a 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1667,7 +1667,6 @@ static void fsl_spdif_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -#ifdef CONFIG_PM static int fsl_spdif_runtime_suspend(struct device *dev) { struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); @@ -1739,13 +1738,11 @@ disable_core_clk: return ret; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_spdif_pm = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, + NULL) }; static const struct of_device_id fsl_spdif_dt_ids[] = { @@ -1763,10 +1760,10 @@ static struct platform_driver fsl_spdif_driver = { .driver = { .name = "fsl-spdif-dai", .of_match_table = fsl_spdif_dt_ids, - .pm = &fsl_spdif_pm, + .pm = pm_ptr(&fsl_spdif_pm), }, .probe = fsl_spdif_probe, - .remove_new = fsl_spdif_remove, + .remove = fsl_spdif_remove, }; module_platform_driver(fsl_spdif_driver); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 4ca3a16f7ac0..320108bebf30 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1693,7 +1693,6 @@ static void fsl_ssi_remove(struct platform_device *pdev) } } -#ifdef CONFIG_PM_SLEEP static int fsl_ssi_suspend(struct device *dev) { struct fsl_ssi *ssi = dev_get_drvdata(dev); @@ -1723,20 +1722,19 @@ static int fsl_ssi_resume(struct device *dev) return regcache_sync(regs); } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops fsl_ssi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume) + SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume) }; static struct platform_driver fsl_ssi_driver = { .driver = { .name = "fsl-ssi-dai", .of_match_table = fsl_ssi_ids, - .pm = &fsl_ssi_pm, + .pm = pm_sleep_ptr(&fsl_ssi_pm), }, .probe = fsl_ssi_probe, - .remove_new = fsl_ssi_remove, + .remove = fsl_ssi_remove, }; module_platform_driver(fsl_ssi_driver); diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c98e3db74fe7..beede7344efd 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1540,7 +1540,7 @@ static struct platform_driver fsl_xcvr_driver = { .pm = pm_ptr(&fsl_xcvr_pm_ops), .of_match_table = fsl_xcvr_dt_ids, }, - .remove_new = fsl_xcvr_remove, + .remove = fsl_xcvr_remove, }; module_platform_driver(fsl_xcvr_driver); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 747ab2f1aae3..43e14f2eca8d 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -320,7 +320,6 @@ static void imx_audmux_remove(struct platform_device *pdev) audmux_debugfs_remove(); } -#ifdef CONFIG_PM_SLEEP static int imx_audmux_suspend(struct device *dev) { int i; @@ -348,18 +347,17 @@ static int imx_audmux_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops imx_audmux_pm = { - SET_SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) + SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) }; static struct platform_driver imx_audmux_driver = { .probe = imx_audmux_probe, - .remove_new = imx_audmux_remove, + .remove = imx_audmux_remove, .driver = { .name = DRIVER_NAME, - .pm = &imx_audmux_pm, + .pm = pm_sleep_ptr(&imx_audmux_pm), .of_match_table = imx_audmux_dt_ids, } }; diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 0e18ccabe28c..98b37dd2b901 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -650,9 +650,6 @@ static int imx_card_parse_of(struct imx_card_data *data) link->ops = &imx_aif_ops; } - if (link->no_pcm || link->dynamic) - snd_soc_dai_link_set_capabilities(link); - /* Get dai fmt */ ret = simple_util_parse_daifmt(dev, np, codec, NULL, &link->dai_fmt); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index b0944a07ab47..1daf0be3d100 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -753,7 +753,6 @@ static void imx_rpmsg_pcm_remove(struct platform_device *pdev) destroy_workqueue(info->rpmsg_wq); } -#ifdef CONFIG_PM static int imx_rpmsg_pcm_runtime_resume(struct device *dev) { struct rpmsg_info *info = dev_get_drvdata(dev); @@ -771,9 +770,7 @@ static int imx_rpmsg_pcm_runtime_suspend(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int imx_rpmsg_pcm_suspend(struct device *dev) { struct rpmsg_info *info = dev_get_drvdata(dev); @@ -809,14 +806,11 @@ static int imx_rpmsg_pcm_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = { - SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend, - imx_rpmsg_pcm_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend, - imx_rpmsg_pcm_resume) + RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend, + imx_rpmsg_pcm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend, imx_rpmsg_pcm_resume) }; static const struct platform_device_id imx_rpmsg_pcm_id_table[] = { @@ -828,11 +822,11 @@ MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table); static struct platform_driver imx_pcm_rpmsg_driver = { .probe = imx_rpmsg_pcm_probe, - .remove_new = imx_rpmsg_pcm_remove, + .remove = imx_rpmsg_pcm_remove, .id_table = imx_rpmsg_pcm_id_table, .driver = { .name = IMX_PCM_DRV_NAME, - .pm = &imx_rpmsg_pcm_pm_ops, + .pm = pm_ptr(&imx_rpmsg_pcm_pm_ops), }, }; module_platform_driver(imx_pcm_rpmsg_driver); diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 3c1e69092d2f..8bcf54ef709e 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -214,7 +214,7 @@ static struct platform_driver imx_sgtl5000_driver = { .of_match_table = imx_sgtl5000_dt_ids, }, .probe = imx_sgtl5000_probe, - .remove_new = imx_sgtl5000_remove, + .remove = imx_sgtl5000_remove, }; module_platform_driver(imx_sgtl5000_driver); diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c index af995ca081a3..c65c17dfa174 100644 --- a/sound/soc/fsl/lpc3xxx-i2s.c +++ b/sound/soc/fsl/lpc3xxx-i2s.c @@ -39,7 +39,7 @@ static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u3 { u32 i2srate; u32 idxx, idyy; - u32 savedbitclkrate, diff, trate, baseclk; + u32 diff, trate, baseclk; /* Adjust rate for sample size (bits) and 2 channels and offset for * divider in clock output @@ -53,14 +53,12 @@ static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u3 /* Find the best divider */ *clkx = *clky = 0; - savedbitclkrate = 0; diff = ~0; for (idxx = 1; idxx < 0xFF; idxx++) { for (idyy = 1; idyy < 0xFF; idyy++) { trate = (baseclk * idxx) / idyy; if (abs(trate - i2srate) < diff) { diff = abs(trate - i2srate); - savedbitclkrate = trate; *clkx = idxx; *clky = idyy; } @@ -190,8 +188,7 @@ static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream, __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate); - dev_dbg(dev, "Stream : %s\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + dev_dbg(dev, "Stream : %s\n", snd_pcm_direction_name(substream->stream)); dev_dbg(dev, "Desired clock rate : %d\n", i2s_info_p->freq); dev_dbg(dev, "Base clock rate : %d\n", i2s_info_p->clkrate); dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize); @@ -260,7 +257,7 @@ static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } -const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { +static const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { .probe = lpc3xxx_i2s_dai_probe, .startup = lpc3xxx_i2s_startup, .shutdown = lpc3xxx_i2s_shutdown, @@ -270,7 +267,7 @@ const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { .set_fmt = lpc3xxx_i2s_set_dai_fmt, }; -struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = { +static struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = { .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/fsl/lpc3xxx-pcm.c b/sound/soc/fsl/lpc3xxx-pcm.c index c0d499b9b8ba..e6abaf63895a 100644 --- a/sound/soc/fsl/lpc3xxx-pcm.c +++ b/sound/soc/fsl/lpc3xxx-pcm.c @@ -52,7 +52,7 @@ static const struct snd_dmaengine_pcm_config lpc3xxx_dmaengine_pcm_config = { .prealloc_buffer_size = 128 * 1024, }; -const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = { +static const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = { .name = "lpc32xx-pcm", }; diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 0423cf43c7a0..8554fb690772 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -327,7 +327,7 @@ MODULE_DEVICE_TABLE(of, psc_ac97_match); static struct platform_driver psc_ac97_driver = { .probe = psc_ac97_of_probe, - .remove_new = psc_ac97_of_remove, + .remove = psc_ac97_of_remove, .driver = { .name = "mpc5200-psc-ac97", .of_match_table = psc_ac97_match, diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index af8b9d098d2d..9ad44eeed6ad 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -184,7 +184,7 @@ static int psc_i2s_of_probe(struct platform_device *op) /* Check for the codec handle. If it is not present then we * are done */ - if (!of_get_property(op->dev.of_node, "codec-handle", NULL)) + if (!of_property_present(op->dev.of_node, "codec-handle")) return 0; /* Due to errata in the dma mode; need to line up enabling @@ -225,7 +225,7 @@ MODULE_DEVICE_TABLE(of, psc_i2s_match); static struct platform_driver psc_i2s_driver = { .probe = psc_i2s_of_probe, - .remove_new = psc_i2s_of_remove, + .remove = psc_i2s_of_remove, .driver = { .name = "mpc5200-psc-i2s", .of_match_table = psc_i2s_match, diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 6f5eecf6d88c..66db05970d82 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -408,7 +408,7 @@ static void p1022_ds_remove(struct platform_device *pdev) static struct platform_driver p1022_ds_driver = { .probe = p1022_ds_probe, - .remove_new = p1022_ds_remove, + .remove = p1022_ds_remove, .driver = { /* * The name must match 'compatible' property in the device tree, diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index a42149311c8b..d4568346714f 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -370,7 +370,7 @@ static void p1022_rdk_remove(struct platform_device *pdev) static struct platform_driver p1022_rdk_driver = { .probe = p1022_rdk_probe, - .remove_new = p1022_rdk_remove, + .remove = p1022_rdk_remove, .driver = { /* * The name must match 'compatible' property in the device tree, diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 2bab0fc1de59..5542c4ee6d12 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -124,7 +124,7 @@ MODULE_DEVICE_TABLE(of, pcm030_audio_match); static struct platform_driver pcm030_fabric_driver = { .probe = pcm030_fabric_probe, - .remove_new = pcm030_fabric_remove, + .remove = pcm030_fabric_remove, .driver = { .name = DRV_NAME, .of_match_table = pcm030_audio_match, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3425fbbcbd7e..4b384475b972 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -279,8 +279,6 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, graph_parse_convert(dev, ep, &dai_props->adata); - snd_soc_dai_link_set_capabilities(dai_link); - ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); li->link++; @@ -363,7 +361,6 @@ static int __graph_for_each_link(struct simple_util_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *node = dev->of_node; struct device_node *cpu_port; - struct device_node *cpu_ep; struct device_node *codec_ep; struct device_node *codec_port; struct device_node *codec_port_old = NULL; @@ -373,14 +370,9 @@ static int __graph_for_each_link(struct simple_util_priv *priv, /* loop for all listed CPU port */ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { cpu_port = it.node; - cpu_ep = NULL; /* loop for all CPU endpoint */ - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - + for_each_child_of_node_scoped(cpu_port, cpu_ep) { /* get codec */ codec_ep = of_graph_get_remote_endpoint(cpu_ep); codec_port = ep_to_port(codec_ep); @@ -410,10 +402,8 @@ static int __graph_for_each_link(struct simple_util_priv *priv, of_node_put(codec_ep); of_node_put(codec_port); - if (ret < 0) { - of_node_put(cpu_ep); + if (ret < 0) return ret; - } codec_port_old = codec_port; } @@ -674,7 +664,7 @@ static struct platform_driver graph_card = { .of_match_table = graph_of_match, }, .probe = graph_probe, - .remove_new = simple_util_remove, + .remove = simple_util_remove, }; module_platform_driver(graph_card); diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c index 8e5a51098490..7151d426bee9 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.c +++ b/sound/soc/generic/audio-graph-card2-custom-sample.c @@ -177,7 +177,7 @@ static struct platform_driver custom_card = { .of_match_table = custom_of_match, }, .probe = custom_probe, - .remove_new = simple_util_remove, + .remove = simple_util_remove, }; module_platform_driver(custom_card); diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 56f7f946882e..4ad3d1b0714f 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -966,8 +966,6 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, graph_parse_convert(ep, dai_props); /* at node of */ graph_parse_convert(rep, dai_props); /* at node of */ - snd_soc_dai_link_set_capabilities(dai_link); - graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu); err: of_node_put(ep); @@ -1141,21 +1139,12 @@ static int graph_counter(struct device_node *lnk) */ if (graph_lnk_is_multi(lnk)) { struct device_node *ports = port_to_ports(lnk); - struct device_node *port = NULL; - int cnt = 0; /* * CPU/Codec = N:M case has many endpoints. * We can't use of_graph_get_endpoint_count() here */ - while(1) { - port = of_get_next_child(ports, port); - if (!port) - break; - cnt++; - } - - return cnt - 1; + return of_get_child_count(ports) - 1; } /* * Single CPU / Codec @@ -1449,7 +1438,7 @@ static struct platform_driver graph_card = { .of_match_table = graph_of_match, }, .probe = graph_probe, - .remove_new = simple_util_remove, + .remove = simple_util_remove, }; module_platform_driver(graph_card); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d2588f1ea54e..76a1d05e2ebe 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -291,8 +291,6 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, simple_parse_convert(dev, np, &dai_props->adata); - snd_soc_dai_link_set_capabilities(dai_link); - ret = simple_link_init(priv, np, codec, li, prefix, dai_name); out_put_node: @@ -840,7 +838,7 @@ static struct platform_driver simple_card = { .of_match_table = simple_of_match, }, .probe = simple_probe, - .remove_new = simple_util_remove, + .remove = simple_util_remove, }; module_platform_driver(simple_card); diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index e9e5e235a8a6..407288055741 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -181,14 +181,6 @@ static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct return 0; } -static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - mile_stone(dai); - - return 0; -} - static const u64 test_dai_formats = /* * Select below from Sound Card, not auto @@ -228,7 +220,6 @@ static const struct snd_soc_dai_ops test_verbose_ops = { .hw_params = test_dai_hw_params, .hw_free = test_dai_hw_free, .trigger = test_dai_trigger, - .bespoke_trigger = test_dai_bespoke_trigger, .auto_selectable_formats = &test_dai_formats, .num_auto_selectable_formats = 1, }; @@ -646,7 +637,7 @@ static struct platform_driver test_driver = { .of_match_table = test_of_match, }, .probe = test_driver_probe, - .remove_new = test_driver_remove, + .remove = test_driver_remove, }; module_platform_driver(test_driver); diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index b69a364d619e..6a988976fb0d 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -607,7 +607,7 @@ static struct platform_driver img_i2s_in_driver = { .pm = &img_i2s_in_pm_ops }, .probe = img_i2s_in_probe, - .remove_new = img_i2s_in_dev_remove + .remove = img_i2s_in_dev_remove }; module_platform_driver(img_i2s_in_driver); diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index 6f9831c6d6e0..1211e6184d97 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -607,7 +607,7 @@ static struct platform_driver img_i2s_out_driver = { .pm = &img_i2s_out_pm_ops }, .probe = img_i2s_out_probe, - .remove_new = img_i2s_out_dev_remove + .remove = img_i2s_out_dev_remove }; module_platform_driver(img_i2s_out_driver); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index 815e68a7048c..4ec63119d67c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -311,7 +311,7 @@ static struct platform_driver img_prl_out_driver = { .pm = &img_prl_out_pm_ops }, .probe = img_prl_out_probe, - .remove_new = img_prl_out_dev_remove + .remove = img_prl_out_dev_remove }; module_platform_driver(img_prl_out_driver); diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 9646e9d3f0bc..3c513f5b8c54 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -878,7 +878,7 @@ static struct platform_driver img_spdif_in_driver = { .pm = &img_spdif_in_pm_ops }, .probe = img_spdif_in_probe, - .remove_new = img_spdif_in_dev_remove + .remove = img_spdif_in_dev_remove }; module_platform_driver(img_spdif_in_driver); diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index dfa72afa946e..402695b5fc41 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -468,7 +468,7 @@ static struct platform_driver img_spdif_out_driver = { .pm = &img_spdif_out_pm_ops }, .probe = img_spdif_out_probe, - .remove_new = img_spdif_out_dev_remove + .remove = img_spdif_out_dev_remove }; module_platform_driver(img_spdif_out_driver); diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c index da6251680e41..fdeceb271e7f 100644 --- a/sound/soc/img/pistachio-internal-dac.c +++ b/sound/soc/img/pistachio-internal-dac.c @@ -271,7 +271,7 @@ static struct platform_driver pistachio_internal_dac_plat_driver = { .pm = &pistachio_internal_dac_pm_ops }, .probe = pistachio_internal_dac_probe, - .remove_new = pistachio_internal_dac_remove + .remove = pistachio_internal_dac_remove }; module_platform_driver(pistachio_internal_dac_plat_driver); diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 38b61dfd1487..a32fb0a8d7d7 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -67,126 +67,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI Baytrail/Cherrytrail. If you want to enable SOF on Baytrail/Cherrytrail, you need to deselect this option first. -config SND_SOC_INTEL_SKYLAKE - tristate "All Skylake/SST Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKL - select SND_SOC_INTEL_APL - select SND_SOC_INTEL_KBL - select SND_SOC_INTEL_GLK - select SND_SOC_INTEL_CNL - select SND_SOC_INTEL_CFL - help - This is a backwards-compatible option to select all devices - supported by the Intel SST/Skylake driver. This option is no - longer recommended and will be deprecated when the SOF - driver is introduced. Distributions should explicitly - select which platform uses this driver. - -config SND_SOC_INTEL_SKL - tristate "Skylake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Skylake platform with the DSP enabled - in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_APL - tristate "Broxton/ApolloLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Broxton/ApolloLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_KBL - tristate "Kabylake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Kabylake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_GLK - tristate "GeminiLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel GeminiLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CNL - tristate "CannonLake/WhiskyLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CNL/WHL platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CFL - tristate "CoffeeLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CoffeeLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CML_H - tristate "CometLake-H Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CometLake-H platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CML_LP - tristate "CometLake-LP Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CometLake-LP platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_SKYLAKE_FAMILY - tristate - select SND_SOC_INTEL_SKYLAKE_COMMON - -if SND_SOC_INTEL_SKYLAKE_FAMILY - -config SND_SOC_INTEL_SKYLAKE_SSP_CLK - tristate - -config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC - bool "HDAudio codec support" - help - If you have Intel Skylake or Kabylake with HDAudio codec - and DMIC present then enable this option by saying Y. - -config SND_SOC_INTEL_SKYLAKE_COMMON - tristate - select SND_HDA_EXT_CORE - select SND_HDA_DSP_LOADER - select SND_SOC_TOPOLOGY - select SND_SOC_INTEL_SST - select SND_SOC_HDAC_HDA - select SND_SOC_ACPI_INTEL_MATCH - select SND_INTEL_DSP_CONFIG - help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with the DSP enabled in the BIOS - then enable this option by saying Y or m. - -endif ## SND_SOC_INTEL_SKYLAKE_FAMILY - endif ## SND_SOC_INTEL_SST_TOPLEVEL if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index d44b2652c707..8ecc7047d700 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_SND_SOC) += common/ # Platform Support obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/ -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/ obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/ obj-$(CONFIG_SND_SOC_INTEL_AVS) += avs/ diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 8652b4a20020..373d68b4cf88 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -812,7 +812,7 @@ static struct platform_driver sst_platform_driver = { .pm = &sst_platform_pm, }, .probe = sst_platform_probe, - .remove_new = sst_platform_remove, + .remove = sst_platform_remove, }; module_platform_driver(sst_platform_driver); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 29d44c989e5f..9956dc63db74 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -358,7 +358,7 @@ static struct platform_driver sst_acpi_driver = { .pm = &intel_sst_pm, }, .probe = sst_acpi_probe, - .remove_new = sst_acpi_remove, + .remove = sst_acpi_remove, }; module_platform_driver(sst_acpi_driver); diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index f2dc82a2abc7..da7bac09acb4 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -422,8 +422,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) int ret; ret = snd_intel_dsp_driver_probe(pci); - if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS) + switch (ret) { + case SND_INTEL_DSP_DRIVER_ANY: + case SND_INTEL_DSP_DRIVER_SST: + case SND_INTEL_DSP_DRIVER_AVS: + break; + default: return -ENODEV; + } ret = pcim_enable_device(pci); if (ret < 0) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f1faa5dd2a4f..cc10ae58b0c7 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -252,51 +252,6 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -if SND_SOC_INTEL_SKL - -config SND_SOC_INTEL_SKL_RT286_MACH - tristate "SKL with RT286 I2S mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT286 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Skylake platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH - tristate "SKL with NAU88L25 and SSM4567 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_SSM4567 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + SSM4567. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH - tristate "SKL with NAU88L25 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + MAX98357A. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_SKL - config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC tristate select SND_SOC_DA7219 @@ -305,36 +260,6 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_HDAC_HDMI select SND_SOC_INTEL_HDA_DSP_COMMON -if SND_SOC_INTEL_APL - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "Broxton with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - help - This adds support for ASoC machine driver for Broxton-P platforms - with DA7219 + MAX98357A I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_BXT_RT298_MACH - tristate "Broxton with RT298 I2S mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT298 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON - help - This adds support for ASoC machine driver for Broxton platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_APL - if SND_SOC_SOF_APOLLOLAKE config SND_SOC_INTEL_SOF_WM8804_MACH @@ -351,79 +276,6 @@ config SND_SOC_INTEL_SOF_WM8804_MACH endif ## SND_SOC_SOF_APOLLOLAKE -if SND_SOC_INTEL_KBL - -config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH - tristate "KBL with RT5663 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT5663 - select SND_SOC_MAX98927 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH - tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SPI - select SND_SOC_RT5663 - select SND_SOC_RT5514 - select SND_SOC_RT5514_SPI - select SND_SOC_MAX98927 - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + RT5514 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH - tristate "KBL with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98357A I2S audio codec. - Say Y if you have such a device. - -config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH - tristate "KBL with DA7219 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98927 - select SND_SOC_MAX98373_I2C - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98927 I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5660_MACH - tristate "KBL with RT5660 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on GPIOLIB || COMPILE_TEST - select SND_SOC_RT5660 - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5660 I2S audio codec. - Say Y if you have such a device. - -endif ## SND_SOC_INTEL_KBL - if SND_SOC_SOF_GEMINILAKE config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH @@ -448,13 +300,13 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +if SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "Skylake+ with HDA Codecs" depends on SND_HDA_CODEC_HDMI - select SND_SOC_HDAC_HDMI select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help @@ -464,7 +316,7 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +endif ## SND_SOC_SOF_HDA_AUDIO_CODEC if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH @@ -656,6 +508,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE + select SND_SOC_SDW_UTILS select SND_SOC_MAX98363 select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW @@ -671,6 +524,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT1308 select SND_SOC_RT1316_SDW select SND_SOC_RT1318_SDW + select SND_SOC_RT1320_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW select SND_SOC_CS42L43 diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dc6fe110f279..fcd517d6c279 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -3,8 +3,6 @@ snd-soc-hsw-rt5640-y := hsw_rt5640.o snd-soc-sst-bdw-rt5650-mach-y := bdw-rt5650.o snd-soc-sst-bdw-rt5677-mach-y := bdw-rt5677.o snd-soc-bdw-rt286-y := bdw_rt286.o -snd-soc-sst-bxt-da7219_max98357a-y := bxt_da7219_max98357a.o -snd-soc-sst-bxt-rt298-y := bxt_rt298.o snd-soc-sst-sof-pcm512x-y := sof_pcm512x.o snd-soc-sst-sof-wm8804-y := sof_wm8804.o snd-soc-sst-bytcr-rt5640-y := bytcr_rt5640.o @@ -23,27 +21,10 @@ snd-soc-sof_cs42l42-y := sof_cs42l42.o snd-soc-sof_es8336-y := sof_es8336.o snd-soc-sof_nau8825-y := sof_nau8825.o snd-soc-sof_da7219-y := sof_da7219.o -snd-soc-kbl_da7219_max98357a-y := kbl_da7219_max98357a.o -snd-soc-kbl_da7219_max98927-y := kbl_da7219_max98927.o -snd-soc-kbl_rt5663_max98927-y := kbl_rt5663_max98927.o -snd-soc-kbl_rt5663_rt5514_max98927-y := kbl_rt5663_rt5514_max98927.o -snd-soc-kbl_rt5660-y := kbl_rt5660.o -snd-soc-skl_rt286-y := skl_rt286.o -snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o skl_hda_dsp_common.o -snd-skl_nau88l25_max98357a-y := skl_nau88l25_max98357a.o -snd-soc-skl_nau88l25_ssm4567-y := skl_nau88l25_ssm4567.o +snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o snd-soc-ehl-rt5660-y := ehl_rt5660.o snd-soc-sof-ssp-amp-y := sof_ssp_amp.o snd-soc-sof-sdw-y += sof_sdw.o \ - sof_sdw_maxim.o sof_sdw_rt_amp.o \ - bridge_cs35l56.o \ - sof_sdw_rt5682.o sof_sdw_rt700.o \ - sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ - sof_sdw_rt712_sdca.o sof_sdw_rt722_sdca.o \ - sof_sdw_rt_dmic.o \ - sof_sdw_cs42l42.o sof_sdw_cs42l43.o \ - sof_sdw_cs_amp.o \ - sof_sdw_dmic.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o @@ -51,8 +32,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SOF_ES8336_MACH) += snd-soc-sof_es8336.o obj-$(CONFIG_SND_SOC_INTEL_SOF_NAU8825_MACH) += snd-soc-sof_nau8825.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MACH) += snd-soc-sof_da7219.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-hsw-rt5640.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-bdw-rt286.o @@ -69,14 +48,6 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c deleted file mode 100644 index e1082bfe5ca9..000000000000 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ /dev/null @@ -1,720 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2016, Intel Corporation - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/da7219.h" -#include "../common/soc-intel-quirks.h" -#include "hda_dsp_common.h" - -#define BXT_DIALOG_CODEC_DAI "da7219-hifi" -#define BXT_MAXIM_CODEC_DAI "HiFi" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -struct bxt_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct bxt_card_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_HS_PB, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - int ret = 0; - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - - codec_dai = snd_soc_card_get_codec_dai(card, BXT_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if(SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Line Out"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget broxton_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SPK("Spk", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone Jack", NULL, "HPL"}, - {"Headphone Jack", NULL, "HPR"}, - - /* other jacks */ - {"MIC", NULL, "Headset Mic"}, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - {"hifi3", NULL, "iDisp3 Tx"}, - {"iDisp3 Tx", NULL, "iDisp3_out"}, - {"hifi2", NULL, "iDisp2 Tx"}, - {"iDisp2 Tx", NULL, "iDisp2_out"}, - {"hifi1", NULL, "iDisp1 Tx"}, - {"iDisp1 Tx", NULL, "iDisp1_out"}, - - /* DMIC */ - {"dmic01_hifi", NULL, "DMIC01 Rx"}, - {"DMIC01 Rx", NULL, "DMIC AIF"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, - - /* speaker */ - {"Spk", NULL, "Speaker"}, - - {"HiFi Playback", NULL, "ssp5 Tx"}, - {"ssp5 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp1 Rx"}, - {"ssp1 Rx", NULL, "Capture"}, -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, - }, -}; - -static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int clk_freq; - - /* Configure sysclk for codec */ - clk_freq = 19200000; - - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, - SND_SOC_CLOCK_IN); - - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &broxton_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3, - KEY_VOICECOMMAND); - - snd_soc_component_set_jack(component, &broxton_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static const unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int bxt_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops broxton_da7219_fe_ops = { - .startup = bxt_fe_startup, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops broxton_dmic_ops = { - .startup = broxton_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int broxton_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -}; - -static const struct snd_soc_ops broxton_refcap_ops = { - .startup = broxton_refcap_startup, -}; - -/* broxton digital audio interface glue - connects codec <--> CPU */ -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - - /* Back End DAI */ -SND_SOC_DAILINK_DEF(ssp5_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); -SND_SOC_DAILINK_DEF(ssp5_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", - BXT_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - BXT_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); - -static struct snd_soc_dai_link broxton_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .name = "Bxt Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = broxton_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .name = "Bxt Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_HS_PB] = { - .name = "Bxt Audio Headset Playback", - .stream_name = "Headset Playback", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "Refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP5 - Codec */ - .name = "SSP5-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = broxton_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .name = "dmic16k", - .id = 6, - .be_hw_params_fixup = broxton_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &broxton_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* broxton audio machine driver for SPT + da7219 */ -static struct snd_soc_card broxton_audio_card = { - .name = "bxtda7219max", - .owner = THIS_MODULE, - .dai_link = broxton_dais, - .num_links = ARRAY_SIZE(broxton_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - broxton_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&broxton_audio_card, ctx); - - /* override platform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_da7219_mx98357a" }, - { } -}; -MODULE_DEVICE_TABLE(platform, bxt_board_ids); - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -module_platform_driver(broxton_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Sathyanarayana Nujella "); -MODULE_AUTHOR("Rohit Ainapure "); -MODULE_AUTHOR("Harsha Priya "); -MODULE_AUTHOR("Conrad Cooke "); -MODULE_AUTHOR("Naveen Manohar "); -MODULE_AUTHOR("Mac Chiang "); -MODULE_AUTHOR("Brent Lu "); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c deleted file mode 100644 index 6da1517c53c6..000000000000 --- a/sound/soc/intel/boards/bxt_rt298.c +++ /dev/null @@ -1,670 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2014-2016, Intel Corporation - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt298.h" -#include "hda_dsp_common.h" - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -struct bxt_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct bxt_rt286_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -static struct snd_soc_jack_pin broxton_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget broxton_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), -}; - -static const struct snd_soc_dapm_route broxton_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp5 Tx"}, - { "ssp5 Tx", NULL, "codec0_out"}, - { "ssp5 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp5 Rx" }, - { "ssp5 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static const struct snd_soc_dapm_route geminilake_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp2 Tx"}, - { "ssp2 Tx", NULL, "codec0_out"}, - { "ssp2 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp2 Rx" }, - { "ssp2 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "dmic_voice", NULL, "DMIC16k Rx" }, - { "DMIC16k Rx", NULL, "Capture" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int ret = 0; - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &broxton_headset, - broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins)); - - if (ret) - return ret; - - snd_soc_component_set_jack(component, &broxton_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP5 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, - 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - return ret; -} - -static const struct snd_soc_ops broxton_rt298_ops = { - .hw_params = broxton_rt298_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 1, 2, 3, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops broxton_dmic_ops = { - .startup = broxton_dmic_startup, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int bxt_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support: - * 48Khz - * stereo - * 16-bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops broxton_rt286_fe_ops = { - .startup = bxt_fe_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp5_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); -SND_SOC_DAILINK_DEF(ssp5_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", - "rt298-aif1"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", - "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); - -/* broxton digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link broxton_rt298_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .name = "Bxt Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = broxton_rt298_fe_init, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .name = "Bxt Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP5 - Codec */ - .name = "SSP5-Codec", - .id = 0, - .no_pcm = 1, - .init = broxton_rt298_codec_init, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp5_fixup, - .ops = &broxton_rt298_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &broxton_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - - -/* broxton audio machine driver for SPT + RT298S */ -static struct snd_soc_card broxton_rt298 = { - .name = "broxton-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_rt298_map, - .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = bxt_card_late_probe, - -}; - -static struct snd_soc_card geminilake_rt298 = { - .name = "geminilake-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = geminilake_rt298_map, - .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_rt286_private *ctx; - struct snd_soc_card *card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - int i; - - for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { - if (card->dai_link[i].num_codecs && - !strncmp(card->dai_link[i].codecs->name, "i2c-INT343A:00", - I2C_NAME_SIZE)) { - if (!strncmp(card->name, "broxton-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP5-Codec"; - card->dai_link[i].cpus->dai_name = "SSP5 Pin"; - } else if (!strncmp(card->name, "geminilake-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP2-Codec"; - card->dai_link[i].cpus->dai_name = "SSP2 Pin"; - } - } - } - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); - - /* override platform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_alc298s_i2s", .driver_data = - (unsigned long)&broxton_rt298 }, - { .name = "glk_alc298s_i2s", .driver_data = - (unsigned long)&geminilake_rt298 }, - {} -}; -MODULE_DEVICE_TABLE(platform, bxt_board_ids); - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_alc298s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -module_platform_driver(broxton_audio) - -/* Module information */ -MODULE_AUTHOR("Ramesh Babu "); -MODULE_AUTHOR("Senthilnathan Veppur "); -MODULE_DESCRIPTION("Intel SST Audio for Broxton"); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index df3c2a7b64d2..8c2b4ab764bb 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -255,7 +255,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* override platform name, if required */ diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 08c598b7e1ee..9178bbe8d995 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -258,7 +258,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* override platform name, if required */ diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 77b91ea4dc32..d3327bc237b5 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -562,7 +562,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codecs->name = codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -709,7 +709,7 @@ static struct platform_driver snd_byt_cht_es8316_mc_driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, - .remove_new = snd_byt_cht_es8316_mc_remove, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index db4a33680d94..2ed49acb4e36 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1693,7 +1693,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -1918,7 +1918,7 @@ static struct platform_driver snd_byt_rt5640_mc_driver = { .name = "bytcr_rt5640", }, .probe = snd_byt_rt5640_mc_probe, - .remove_new = snd_byt_rt5640_mc_remove, + .remove = snd_byt_rt5640_mc_remove, }; module_platform_driver(snd_byt_rt5640_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8514b79f389b..8e4b821efe92 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -926,7 +926,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -1142,7 +1142,7 @@ static struct platform_driver snd_byt_rt5651_mc_driver = { .name = "bytcr_rt5651", }, .probe = snd_byt_rt5651_mc_probe, - .remove_new = snd_byt_rt5651_mc_remove, + .remove = snd_byt_rt5651_mc_remove, }; module_platform_driver(snd_byt_rt5651_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index e5a7cc606aa9..0b10d89cb189 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -663,7 +663,7 @@ static struct platform_driver snd_byt_wm5102_mc_driver = { .name = "bytcr_wm5102", }, .probe = snd_byt_wm5102_mc_probe, - .remove_new = snd_byt_wm5102_mc_remove, + .remove = snd_byt_wm5102_mc_remove, }; module_platform_driver(snd_byt_wm5102_mc_driver); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index f43bc20d6aae..d7c114858833 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -637,7 +637,7 @@ static struct platform_driver snd_cht_mc_driver = { .name = "cht-bsw-max98090", }, .probe = snd_cht_mc_probe, - .remove_new = snd_cht_mc_remove, + .remove = snd_cht_mc_remove, }; module_platform_driver(snd_cht_mc_driver) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 1da9ceee4d59..ac23a8b7cafc 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -582,7 +582,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), "i2c-%s", acpi_dev_name(adev)); cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */ codec_dev = acpi_get_first_physical_node(adev); acpi_dev_put(adev); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index d68e5bc755de..c6c469d51243 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -479,7 +479,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", acpi_dev_name(adev)); cht_dailink[dai_index].codecs->name = drv->codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* Use SSP0 on Bay Trail CR devices */ diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 26289e8fdd87..90d93e667bd9 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -256,8 +256,7 @@ static void hdmi_link_init(struct snd_soc_card *card, { int i; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) { + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) { ctx->idisp_codec = true; return; } diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c deleted file mode 100644 index 154f6a74ed15..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ /dev/null @@ -1,688 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2017-18 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98357A & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define KBL_MAXIM_CODEC_DAI "HiFi" -#define MAXIM_DEV0_NAME "MX98357A:00" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, - 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_jack *jack; - int ret; - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME, - KBL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kabylake_audio_card_da7219_m98357a = { - .name = "kblda7219max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_mx98357a", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_da7219_m98357a, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Naveen Manohar "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c deleted file mode 100644 index 02ed77a07e23..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ /dev/null @@ -1,1175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAX98927 and - * RT5663 codecs - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define MAX98927_CODEC_DAI "max98927-aif1" -#define MAX98927_DEV0_NAME "i2c-MX98927:00" -#define MAX98927_DEV1_NAME "i2c-MX98927:01" - -#define MAX98373_CODEC_DAI "max98373-aif1" -#define MAX98373_DEV0_NAME "i2c-MX98373:00" -#define MAX98373_DEV1_NAME "i2c-MX98373:01" - - -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 -#define NAME_SIZE 32 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack kabylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_CP, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(card->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, - 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* AEC capture path */ - { "echo_ref_out", NULL, "ssp0 Rx" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret, j; - - for_each_rtd_codec_dais(runtime, j, codec_dai) { - - if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, - "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, - "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - - return 0; -} - -static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int j, ret; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - const char *name = codec_dai->component->name; - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char pin_name[20]; - - if (strcmp(name, MAX98927_DEV0_NAME) && - strcmp(name, MAX98927_DEV1_NAME) && - strcmp(name, MAX98373_DEV0_NAME) && - strcmp(name, MAX98373_DEV1_NAME)) - continue; - - snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", - codec_dai->component->name_prefix); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = snd_soc_dapm_enable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to enable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = snd_soc_dapm_disable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to disable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - } - } - - return 0; -} - -static const struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, - .trigger = kabylake_ssp0_trigger, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - struct snd_soc_card *card = rtd->card; - int ret; - - - ret = snd_soc_dapm_add_routes(&card->dapm, - kabylake_ssp1_map, - ARRAY_SIZE(kabylake_ssp1_map)); - - if (ret) - return ret; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - return 0; -} - -static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_codec_conf max98373_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { - { /* Left */ - .name = MAX98373_DEV0_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - - { /* For Right */ - .name = MAX98373_DEV1_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAX98927_DEV0_NAME, MAX98927_CODEC_DAI), - /* For Right */ COMP_CODEC(MAX98927_DEV1_NAME, MAX98927_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec), - }, - { - .name = "dmic01", - .id = 1, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_dapm_context *dapm = &card->dapm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &kabylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &kabylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - - err = hdac_hdmi_jack_port_init(component, &card->dapm); - - if (err < 0) - return err; - - err = snd_soc_dapm_disable_pin(dapm, "Left Spk"); - if (err) { - dev_err(card->dev, "failed to disable Left Spk: %d\n", err); - return err; - } - - err = snd_soc_dapm_disable_pin(dapm, "Right Spk"); - if (err) { - dev_err(card->dev, "failed to disable Right Spk: %d\n", err); - return err; - } - - return snd_soc_dapm_sync(dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kbl_audio_card_da7219_m98927 = { - .name = "kblda7219m98927", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for Maxim98927 */ -static struct snd_soc_card kbl_audio_card_max98927 = { - .name = "kblmax98927", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_da7219_m98373 = { - .name = "kblda7219m98373", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_max98373 = { - .name = "kblmax98373", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_dai_link *kbl_dai_link; - struct snd_soc_dai_link_component **codecs; - int i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kbl_dai_link = kabylake_audio_card->dai_link; - - /* Update codecs for SSP0 with max98373 codec info */ - if (!strcmp(pdev->name, "kbl_da7219_max98373") || - (!strcmp(pdev->name, "kbl_max98373"))) { - for (i = 0; i < kabylake_audio_card->num_links; ++i) { - if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) - continue; - - codecs = &(kbl_dai_link[i].codecs); - *codecs = max98373_ssp0_codec_components; - kbl_dai_link[i].num_codecs = - ARRAY_SIZE(max98373_ssp0_codec_components); - break; - } - } - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98927, - }, - { - .name = "kbl_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98927, - }, - { - .name = "kbl_da7219_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98373, - }, - { - .name = "kbl_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98373, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98_927_373", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); -MODULE_AUTHOR("Mac Chiang "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c deleted file mode 100644 index 66885cb36f24..000000000000 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ /dev/null @@ -1,567 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018-19 Canonical Corporation. - -/* - * Intel Kabylake I2S Machine Driver with RT5660 Codec - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98357a and - * DA7219 codecs - * Also referred to: - * Intel Broadwell I2S Machine driver supporting RT5677 codec - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt5660.h" - -#define KBL_RT5660_CODEC_DAI "rt5660-aif1" -#define DUAL_CHANNEL 2 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; -static struct snd_soc_jack lineout_jack; -static struct snd_soc_jack mic_jack; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct gpio_desc *gpio_lo_mute; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -#define GPIO_LINEOUT_MUTE_INDEX 0 -#define GPIO_LINEOUT_DET_INDEX 3 -#define GPIO_LINEIN_DET_INDEX 4 - -static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; -static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; -static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; - - -static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { - { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, - { "lineout-det-gpios", &lineout_det_gpio, 1 }, - { "mic-det-gpios", &mic_det_gpio, 1 }, - { NULL }, -}; - -static struct snd_soc_jack_pin lineout_jack_pin = { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, -}; - -static struct snd_soc_jack_pin mic_jack_pin = { - .pin = "Line In", - .mask = SND_JACK_MICROPHONE, -}; - -static struct snd_soc_jack_gpio lineout_jack_gpio = { - .name = "lineout-det", - .report = SND_JACK_LINEOUT, - .debounce_time = 200, -}; - -static struct snd_soc_jack_gpio mic_jack_gpio = { - .name = "mic-det", - .report = SND_JACK_MICROPHONE, - .debounce_time = 200, -}; - -static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); - - gpiod_set_value_cansleep(priv->gpio_lo_mute, - !(SND_SOC_DAPM_EVENT_ON(event))); - - return 0; -} - -static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { - SOC_DAPM_PIN_SWITCH("Line In"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { - SND_SOC_DAPM_MIC("Line In", NULL), - SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), -}; - -static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { - /* other jacks */ - {"IN1P", NULL, "Line In"}, - {"IN2P", NULL, "Line In"}, - {"Line Out", NULL, "LOUTR"}, - {"Line Out", NULL, "LOUTL"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - - ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); - if (ret) - dev_warn(component->dev, "Failed to add driver gpios\n"); - - /* Request rt5660 GPIO for lineout mute control, return if fails */ - ctx->gpio_lo_mute = gpiod_get(component->dev, "lineout-mute", - GPIOD_OUT_HIGH); - if (IS_ERR(ctx->gpio_lo_mute)) { - dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); - return PTR_ERR(ctx->gpio_lo_mute); - } - - /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Lineout Jack", - SND_JACK_LINEOUT, &lineout_jack, - &lineout_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create Lineout jack\n"); - else { - lineout_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&lineout_jack, 1, - &lineout_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add Lineout jack gpio\n"); - } - - /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", - SND_JACK_MICROPHONE, &mic_jack, - &mic_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create mic jack\n"); - else { - mic_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add mic jack gpio\n"); - } - - /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ - snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); - snd_soc_dapm_force_enable_pin(dapm, "BST1"); - snd_soc_dapm_force_enable_pin(dapm, "BST2"); - - return 0; -} - -static void kabylake_rt5660_codec_exit(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - - /* - * The .exit() can be reached without going through the .init() - * so explicitly test if the gpiod is valid - */ - if (!IS_ERR_OR_NULL(ctx->gpio_lo_mute)) - gpiod_put(ctx->gpio_lo_mute); -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5660_SCLK_S_PLL1, params_rate(params) * 512, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5660_PLL1_S_BCLK, - params_rate(params) * 50, - params_rate(params) * 512); - if (ret < 0) - dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops kabylake_rt5660_ops = { - .hw_params = kabylake_rt5660_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5660_fe_ops = { - .startup = kbl_fe_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC3277:00", KBL_RT5660_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ -static struct snd_soc_dai_link kabylake_rt5660_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5660_codec_init, - .exit = kabylake_rt5660_codec_exit, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp0_fixup, - .ops = &kabylake_rt5660_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for rt5660 */ -static struct snd_soc_card kabylake_audio_card_rt5660 = { - .name = "kblrt5660", - .owner = THIS_MODULE, - .dai_link = kabylake_rt5660_dais, - .num_links = ARRAY_SIZE(kabylake_rt5660_dais), - .controls = kabylake_rt5660_controls, - .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), - .dapm_widgets = kabylake_rt5660_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), - .dapm_routes = kabylake_rt5660_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5660", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5660, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5660", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); -MODULE_AUTHOR("Hui Wang "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c deleted file mode 100644 index 9da89436a917..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ /dev/null @@ -1,1073 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include -#include -#include - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define DMIC_CH(p) p->list[p->count-1] -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" - -static struct snd_soc_card *kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_rt5663_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -enum { - KBL_DPCM_AUDIO_5663_PB = 0, - KBL_DPCM_AUDIO_5663_CP, - KBL_DPCM_AUDIO_5663_HDMI1_PB, - KBL_DPCM_AUDIO_5663_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_5663_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_5663_map[] = { - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) { - dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - return ret; -} - -static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - ret = kabylake_rt5663_codec_init(rtd); - if (ret) - return ret; - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) { - dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB); -} - -static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB); -} - -static unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - /* - * Use channel 4 and 5 for the first amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - /* - * Use channel 6 and 7 for the second amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static const struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static unsigned int channels_dmic[] = { - 2, 4, -}; - -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5663:00", - KBL_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_max98927_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static struct snd_soc_dai_link kabylake_5663_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_5663_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5663_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_5663_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_5663_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = { - .name = "kblrt5663max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663 = { - .name = "kblrt5663", - .owner = THIS_MODULE, - .dai_link = kabylake_5663_dais, - .num_links = ARRAY_SIZE(kabylake_5663_dais), - .controls = kabylake_5663_controls, - .num_controls = ARRAY_SIZE(kabylake_5663_controls), - .dapm_widgets = kabylake_5663_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets), - .dapm_routes = kabylake_5663_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_rt5663_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5663", - .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663, - }, - { - .name = "kbl_rt5663_m98927", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5663_m98927", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); -MODULE_AUTHOR("Naveen M "); -MODULE_AUTHOR("Harsha Priya "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c deleted file mode 100644 index a32ce8f972f3..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ /dev/null @@ -1,869 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * RT5514 and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/rt5514.h" -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include -#include -#include - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" -#define RT5514_DEV_NAME "i2c-10EC5514:00" -#define RT5663_DEV_NAME "i2c-10EC5663:00" -#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16) -#define RT5514_AIF1_SYSCLK_FREQ 12288000 -#define NAME_SIZE 32 - -#define DMIC_CH(p) p->list[p->count-1] - - -static struct snd_soc_card kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct snd_soc_jack kabylake_hdmi[2]; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_RT5514_DSP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("DMIC"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), - -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* Headphones */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "DMIC1L", NULL, "DMIC" }, - { "DMIC1R", NULL, "DMIC" }, - { "DMIC2L", NULL, "DMIC" }, - { "DMIC2R", NULL, "DMIC" }, - - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - int ret; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) - dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); - if (ret) - dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } else if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio DMIC cap")) { - if (params_channels(params) == 2 || - DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "set sysclk err: %d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static const struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(spi_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("spi-PRP0001:00"))); -SND_SOC_DAILINK_DEF(spi_platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-PRP0001:00"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI), - /* dmic */ COMP_CODEC(RT5514_DEV_NAME, KBL_REALTEK_DMIC_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(RT5663_DEV_NAME, KBL_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_RT5514_DSP] = { - .name = "rt5514 dsp", - .stream_name = "Wake on Voice", - SND_SOC_DAILINK_REG(spi_cpu, dummy, spi_platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - /* Back End DAI links */ - /* single Back end dai for both max speakers and dmic */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -static int kabylake_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) -{ - struct snd_soc_component *component = dapm->component; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - if (!component || strcmp(component->name, RT5514_DEV_NAME)) - return 0; - - if (IS_ERR(priv->mclk)) - return 0; - - /* - * It's required to control mclk directly in the set_bias_level - * function for rt5514 codec or the recording function could - * break. - */ - switch (level) { - case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_ON) { - if (!__clk_is_enabled(priv->mclk)) - return 0; - dev_dbg(card->dev, "Disable mclk"); - clk_disable_unprepare(priv->mclk); - } else { - dev_dbg(card->dev, "Enable mclk"); - ret = clk_set_rate(priv->mclk, 24000000); - if (ret) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", - ret); - - /* mclk is already enabled in FW */ - ret = 0; - } - } - break; - default: - break; - } - - return ret; -} - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP,pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &ctx->kabylake_hdmi[i]); - - if (err) - return err; - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &ctx->kabylake_hdmi[i]); - if (err < 0) - return err; - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* - * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 - */ -static struct snd_soc_card kabylake_audio_card = { - .name = "kbl-r5514-5663-max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .set_bias_level = kabylake_set_bias_level, - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_mclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { .name = "kbl_r5514_5663_max" }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_r5514_5663_max", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); -MODULE_AUTHOR("Harsha Priya "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c deleted file mode 100644 index e9cefa4ae56d..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2015-18 Intel Corporation. - -/* - * Common functions used in different Intel machine drivers - */ -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -#include -#include "../../codecs/hdac_hda.h" - -#define NAME_SIZE 32 - -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hda_hdmi_pcm *pcm; - char dai_name[NAME_SIZE]; - - pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", - ctx->dai_index); - pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); - if (!pcm->codec_dai) - return -EINVAL; - - pcm->device = device; - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -SND_SOC_DAILINK_DEF(idisp1_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(analog_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); -SND_SOC_DAILINK_DEF(analog_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); - -SND_SOC_DAILINK_DEF(digital_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); -SND_SOC_DAILINK_DEF(digital_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skl_hda_digital audio interface glue - connects codec <--> CPU */ -struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { - /* Back End DAI links */ - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_cpu, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_cpu, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_cpu, idisp3_codec, platform), - }, - { - .name = "Analog Playback and Capture", - .id = 4, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(analog_cpu, analog_codec, platform), - }, - { - .name = "Digital Playback and Capture", - .id = 5, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(digital_cpu, digital_codec, platform), - }, - { - .name = "dmic01", - .id = 6, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 7, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, -}; - -int skl_hda_hdmi_jack_init(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - struct skl_hda_hdmi_pcm *pcm; - char jack_name[NAME_SIZE]; - int err; - - if (ctx->common_hdmi_codec_drv) - return skl_hda_hdmi_build_controls(card); - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &pcm->hdmi_jack); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &pcm->hdmi_jack); - if (err < 0) - return err; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h deleted file mode 100644 index 19b814dee4ad..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2015-18 Intel Corporation. - */ - -/* - * This file defines data structures used in Machine Driver for Intel - * platforms with HDA Codecs. - */ - -#ifndef __SKL_HDA_DSP_COMMON_H -#define __SKL_HDA_DSP_COMMON_H -#include -#include -#include -#include -#include -#include "../../codecs/hdac_hda.h" -#include "hda_dsp_common.h" - -#define HDA_DSP_MAX_BE_DAI_LINKS 7 - -struct skl_hda_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - struct snd_soc_jack hdmi_jack; - int device; -}; - -struct skl_hda_private { - struct snd_soc_card card; - struct list_head hdmi_pcm_list; - int pcm_count; - int dai_index; - const char *platform_name; - bool common_hdmi_codec_drv; - bool idisp_codec; -}; - -extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; -int skl_hda_hdmi_jack_init(struct snd_soc_card *card); -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); - -/* - * Search card topology and register HDMI PCM related controls - * to codec driver. - */ -static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component; - struct skl_hda_hdmi_pcm *pcm; - - /* HDMI disabled, do not create controls */ - if (list_empty(&ctx->hdmi_pcm_list)) - return 0; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm, - head); - component = pcm->codec_dai->component; - if (!component) - return -EINVAL; - - return hda_dsp_hdmi_build_controls(card, component); -} - -#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 88d91c0280bb..9edd6d985cf1 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -8,157 +8,23 @@ #include #include #include +#include #include #include #include #include #include -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -static const struct snd_soc_dapm_widget skl_hda_widgets[] = { - SND_SOC_DAPM_HP("Analog Out", NULL), - SND_SOC_DAPM_MIC("Analog In", NULL), - SND_SOC_DAPM_HP("Alt Analog Out", NULL), - SND_SOC_DAPM_MIC("Alt Analog In", NULL), - SND_SOC_DAPM_SPK("Digital Out", NULL), - SND_SOC_DAPM_MIC("Digital In", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route skl_hda_map[] = { - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Analog Out", NULL, "Codec Output Pin1" }, - { "Digital Out", NULL, "Codec Output Pin2" }, - { "Alt Analog Out", NULL, "Codec Output Pin3" }, - - { "Codec Input Pin1", NULL, "Analog In" }, - { "Codec Input Pin2", NULL, "Digital In" }, - { "Codec Input Pin3", NULL, "Alt Analog In" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Analog Codec Playback", NULL, "Analog CPU Playback" }, - { "Analog CPU Playback", NULL, "codec0_out" }, - { "Digital Codec Playback", NULL, "Digital CPU Playback" }, - { "Digital CPU Playback", NULL, "codec1_out" }, - { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, - { "Alt Analog CPU Playback", NULL, "codec2_out" }, - - { "codec0_in", NULL, "Analog CPU Capture" }, - { "Analog CPU Capture", NULL, "Analog Codec Capture" }, - { "codec1_in", NULL, "Digital CPU Capture" }, - { "Digital CPU Capture", NULL, "Digital Codec Capture" }, - { "codec2_in", NULL, "Alt Analog CPU Capture" }, - { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, -}; +#include "../../codecs/hdac_hda.h" +#include "../../sof/intel/hda.h" +#include "sof_board_helpers.h" static int skl_hda_card_late_probe(struct snd_soc_card *card) { - return skl_hda_hdmi_jack_init(card); + return sof_intel_board_card_late_probe(card); } -static int -skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - int ret = 0; - - dev_dbg(card->dev, "dai link name - %s\n", link->name); - link->platforms->name = ctx->platform_name; - link->nonatomic = 1; - - if (!ctx->idisp_codec) - return 0; - - if (strstr(link->name, "HDMI")) { - ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); - - if (ret < 0) - return ret; - - ctx->dai_index++; - } - - ctx->pcm_count++; - return ret; -} - -#define IDISP_DAI_COUNT 3 -#define HDAC_DAI_COUNT 2 -#define DMIC_DAI_COUNT 2 - -/* there are two routes per iDisp output */ -#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) -#define IDISP_CODEC_MASK 0x4 - #define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 -static int skl_hda_fill_card_info(struct snd_soc_card *card, - struct snd_soc_acpi_mach_params *mach_params) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *dai_link; - u32 codec_count, codec_mask; - int i, num_links, num_route; - - codec_mask = mach_params->codec_mask; - codec_count = hweight_long(codec_mask); - ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK); - - if (!codec_count || codec_count > 2 || - (codec_count == 2 && !ctx->idisp_codec)) - return -EINVAL; - - if (codec_mask == IDISP_CODEC_MASK) { - /* topology with iDisp as the only HDA codec */ - num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT; - num_route = IDISP_ROUTE_COUNT; - - /* - * rearrange the dai link array and make the - * dmic dai links follow idsp dai links for only - * num_links of dai links need to be registered - * to ASoC. - */ - for (i = 0; i < DMIC_DAI_COUNT; i++) { - skl_hda_be_dai_links[IDISP_DAI_COUNT + i] = - skl_hda_be_dai_links[IDISP_DAI_COUNT + - HDAC_DAI_COUNT + i]; - } - } else { - /* topology with external and iDisp HDA codecs */ - num_links = ARRAY_SIZE(skl_hda_be_dai_links); - num_route = ARRAY_SIZE(skl_hda_map); - card->dapm_widgets = skl_hda_widgets; - card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); - if (!ctx->idisp_codec) { - card->dapm_routes = &skl_hda_map[IDISP_ROUTE_COUNT]; - num_route -= IDISP_ROUTE_COUNT; - for (i = 0; i < IDISP_DAI_COUNT; i++) { - skl_hda_be_dai_links[i].codecs = &snd_soc_dummy_dlc; - skl_hda_be_dai_links[i].num_codecs = 1; - } - } - } - - card->num_links = num_links; - card->num_dapm_routes = num_route; - - for_each_card_prelinks(card, i, dai_link) - dai_link->platforms->name = mach_params->platform; - - return 0; -} - static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -182,47 +48,80 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) } } +#define IDISP_HDMI_BE_ID 1 +#define HDA_BE_ID 4 +#define DMIC01_BE_ID 6 +#define DMIC16K_BE_ID 7 +#define BT_OFFLOAD_BE_ID 8 + +#define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \ + SOF_LINK_HDA, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \ + HDA_BE_ID, \ + DMIC01_BE_ID, \ + DMIC16K_BE_ID, \ + BT_OFFLOAD_BE_ID, \ + 0, \ + 0) + +static unsigned long +skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) +{ + unsigned long board_quirk = 0; + int ssp_bt; + + if (hweight_long(mach_params->bt_link_mask) == 1) { + ssp_bt = fls(mach_params->bt_link_mask) - 1; + board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) | + SOF_BT_OFFLOAD_PRESENT; + } + + return board_quirk; +} + static int skl_hda_audio_probe(struct platform_device *pdev) { - struct snd_soc_acpi_mach *mach; - struct skl_hda_private *ctx; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; struct snd_soc_card *card; + unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params); int ret; - dev_dbg(&pdev->dev, "entry\n"); + card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL); + if (!card) + return -ENOMEM; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + card->name = "hda-dsp"; + card->owner = THIS_MODULE; + card->fully_routed = true; + card->late_probe = skl_hda_card_late_probe; + + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); if (!ctx) return -ENOMEM; - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + if (HDA_EXT_CODEC(mach->mach_params.codec_mask)) + ctx->hda_codec_present = true; - mach = pdev->dev.platform_data; - if (!mach) - return -EINVAL; + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; - card = &ctx->card; - card->name = "hda-dsp", - card->owner = THIS_MODULE, - card->dai_link = skl_hda_be_dai_links, - card->dapm_widgets = skl_hda_widgets, - card->dapm_routes = skl_hda_map, - card->add_dai_link = skl_hda_add_dai_link, - card->fully_routed = true, - card->late_probe = skl_hda_card_late_probe, + ctx->link_order_overwrite = HDA_LINK_ORDER; + ctx->link_id_overwrite = HDA_LINK_IDS; - snd_soc_card_set_drvdata(card, ctx); - - ret = skl_hda_fill_card_info(card, &mach->mach_params); - if (ret < 0) { - dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + /* update dai_link */ + ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx); + if (ret) return ret; - } - - ctx->pcm_count = card->num_links; - ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = mach->mach_params.platform; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; card->dev = &pdev->dev; if (!snd_soc_acpi_sof_parent(&pdev->dev)) @@ -236,6 +135,13 @@ static int skl_hda_audio_probe(struct platform_device *pdev) return -ENOMEM; } + ret = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, ctx); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (!ret) skl_set_hda_codec_autosuspend_delay(card); @@ -258,4 +164,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c deleted file mode 100644 index 91fe9834aab4..000000000000 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ /dev/null @@ -1,704 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver with MAXIM98357A - * and NAU88L25 - * - * Copyright (C) 2015, Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_MAXIM_CODEC_DAI "HiFi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau8825_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - - return ret; -} - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", SKL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", - SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, - &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825max", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau8825_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_m98357a" }, - { .name = "kbl_n88l25_m98357a" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_m98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Rohit Ainapure -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_SSM_CODEC_DAI "ssm4567-hifi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau88125_private { - struct list_head hdmi_pcm_list; -}; -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Speaker"), - SOC_DAPM_PIN_SWITCH("Right Speaker"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - return ret; -} - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Speaker", NULL), - SND_SOC_DAPM_SPK("Right Speaker", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone Jack", NULL, "HPOL"}, - {"Headphone Jack", NULL, "HPOR"}, - - /* speaker */ - {"Left Speaker", NULL, "Left OUT"}, - {"Right Speaker", NULL, "Right OUT"}, - - /* other jacks */ - {"MIC", NULL, "Headset Mic"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Left Playback", NULL, "ssp0 Tx"}, - { "Right Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - /* IV feedback path */ - { "codec0_lp_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left Capture Sense" }, - { "ssp0 Rx", NULL, "Right Capture Sense" }, - - { "Playback", NULL, "ssp1 Tx"}, - { "ssp1 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static struct snd_soc_codec_conf ssm4567_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:00"), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:01"), - .name_prefix = "Right", - }, -}; - -static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - /* Slot 1 for left */ - ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0x01, 0x01, 2, 48); - if (ret < 0) - return ret; - - /* Slot 2 for right */ - ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 1), 0x02, 0x02, 2, 48); - if (ret < 0) - return ret; - - return ret; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - - /* - * 4 buttons here map to the google Reference headset - * The use of these buttons can be decided by the user space. - */ - ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC("i2c-INT343B:00", SKL_SSM_CODEC_DAI), - /* Right */ COMP_CODEC("i2c-INT343B:01", SKL_SSM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .init = skylake_ssm4567_codec_init, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, - &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825adi", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .codec_conf = ssm4567_codec_conf, - .num_configs = ARRAY_SIZE(ssm4567_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau88125_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_s4567" }, - { .name = "kbl_n88l25_s4567" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_s4567", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Conrad Cooke "); -MODULE_AUTHOR("Harsha Priya "); -MODULE_AUTHOR("Naveen M "); -MODULE_AUTHOR("Sathya Prakash M R "); -MODULE_AUTHOR("Yong Zhi "); -MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c deleted file mode 100644 index 3ea03f814403..000000000000 --- a/sound/soc/intel/boards/skl_rt286.c +++ /dev/null @@ -1,568 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver - * - * Copyright (C) 2014-2015, Intel Corporation - * - * Modified from: - * Intel Broadwell Wildcatpoint SST Audio - * - * Copyright (C) 2013, Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/rt286.h" -#include "../../codecs/hdac_hdmi.h" - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_rt286_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_DB_PB, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin skylake_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), -}; - -static const struct snd_soc_dapm_route skylake_rt286_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack deteck */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - { "ssp0 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - -}; - -static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int ret; - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &skylake_headset, - skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins)); - - if (ret) - return ret; - - snd_soc_component_set_jack(component, &skylake_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_rt286_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The output is 48KHz, stereo, 16bits */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, - SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_rt286_ops = { - .hw_params = skylake_rt286_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(deepbuffer, - DAILINK_COMP_ARRAY(COMP_CPU("Deepbuffer Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_rt286_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = skylake_rt286_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_DB_PB] = { - .name = "Skl Deepbuffer Port", - .stream_name = "Deep Buffer Audio", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_capture = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = skylake_rt286_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp0_fixup, - .ops = &skylake_rt286_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + RT286S */ -static struct snd_soc_card skylake_rt286 = { - .name = "skylake-rt286", - .owner = THIS_MODULE, - .dai_link = skylake_rt286_dais, - .num_links = ARRAY_SIZE(skylake_rt286_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_rt286_map, - .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_rt286_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_rt286.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_rt286, ctx); - - return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_alc286s_i2s" }, - { .name = "kbl_alc286s_i2s" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_alc286s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, - -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Omair Mohammed Abdullah "); -MODULE_DESCRIPTION("Intel SST Audio for Skylake"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 7519c545cbe2..24f716e42d6a 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -70,6 +70,64 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) return 0; } +/* + * HDA External Codec DAI Link + */ +static const struct snd_soc_dapm_widget hda_widgets[] = { + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), +}; + +static const struct snd_soc_dapm_route hda_routes[] = { + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + /* CODEC BE connections */ + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, + + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, +}; + +static int hda_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets, + ARRAY_SIZE(hda_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes, + ARRAY_SIZE(hda_routes)); + if (ret) + dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret); + + return ret; +} + /* * DAI Link Helpers */ @@ -79,6 +137,11 @@ enum sof_dmic_be_type { SOF_DMIC_16K, }; +enum sof_hda_be_type { + SOF_HDA_ANALOG, + SOF_HDA_DIGITAL, +}; + /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ #define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ SOF_LINK_DMIC01, \ @@ -95,6 +158,16 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +SND_SOC_DAILINK_DEF(hda_analog_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_analog_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); + +SND_SOC_DAILINK_DEF(hda_digital_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_digital_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); + static struct snd_soc_dai_link_component platform_component[] = { { /* name might be overridden during probe */ @@ -380,6 +453,55 @@ static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, return 0; } +static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum sof_hda_be_type be_type) +{ + switch (be_type) { + case SOF_HDA_ANALOG: + dev_dbg(dev, "link %d: hda analog\n", be_id); + + link->name = "Analog Playback and Capture"; + + /* cpus */ + link->cpus = hda_analog_cpus; + link->num_cpus = ARRAY_SIZE(hda_analog_cpus); + + /* codecs */ + link->codecs = hda_analog_codecs; + link->num_codecs = ARRAY_SIZE(hda_analog_codecs); + break; + case SOF_HDA_DIGITAL: + dev_dbg(dev, "link %d: hda digital\n", be_id); + + link->name = "Digital Playback and Capture"; + + /* cpus */ + link->cpus = hda_digital_cpus; + link->num_cpus = ARRAY_SIZE(hda_digital_cpus); + + /* codecs */ + link->codecs = hda_digital_codecs; + link->num_codecs = ARRAY_SIZE(hda_digital_codecs); + break; + default: + dev_err(dev, "invalid be type %d\n", be_type); + return -EINVAL; + } + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + if (be_type == SOF_HDA_ANALOG) + link->init = hda_init; + link->no_pcm = 1; + link->dpcm_capture = 1; + link->dpcm_playback = 1; + + return 0; +} + static int calculate_num_links(struct sof_card_private *ctx) { int num_links = 0; @@ -409,6 +531,10 @@ static int calculate_num_links(struct sof_card_private *ctx) /* HDMI-In */ num_links += hweight32(ctx->ssp_mask_hdmi_in); + /* HDA external codec */ + if (ctx->hda_codec_present) + num_links += 2; + return num_links; } @@ -566,6 +692,32 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, be_id++; } break; + case SOF_LINK_HDA: + /* HDA external codec */ + if (!ctx->hda_codec_present) + continue; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_ANALOG); + if (ret) { + dev_err(dev, "fail to set hda analog link, ret %d\n", + ret); + return ret; + } + + idx++; + be_id++; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_DIGITAL); + if (ret) { + dev_err(dev, "fail to set hda digital link, ret %d\n", + ret); + return ret; + } + + idx++; + break; case SOF_LINK_NONE: /* caught here if it's not used as terminator in macro */ fallthrough; diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index faba847bb7c9..33a9601b770c 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -57,6 +57,7 @@ enum { SOF_LINK_AMP, SOF_LINK_BT_OFFLOAD, SOF_LINK_HDMI_IN, + SOF_LINK_HDA, }; #define SOF_LINK_ORDER_MASK (0xF) @@ -121,6 +122,7 @@ struct sof_rt5682_private { * @ssp_bt: ssp port number of BT offload BE link * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link * @bt_offload_present: true to create BT offload BE link + * @hda_codec_present: true to create HDA codec BE links * @codec_link: pointer to headset codec dai link * @amp_link: pointer to speaker amplifier dai link * @link_order_overwrite: custom DAI link order @@ -144,6 +146,7 @@ struct sof_card_private { unsigned long ssp_mask_hdmi_in; bool bt_offload_present; + bool hda_codec_present; struct snd_soc_dai_link *codec_link; struct snd_soc_dai_link *amp_link; diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 2a88efaa6d26..fc998fe4b196 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -681,7 +681,7 @@ static int sof_es8336_probe(struct platform_device *pdev) dai_links[0].codecs->dai_name = "ES8326 HiFi"; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -818,6 +818,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "arl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); @@ -828,7 +838,7 @@ static struct platform_driver sof_es8336_driver = { .pm = &snd_soc_pm_ops, }, .probe = sof_es8336_probe, - .remove_new = sof_es8336_remove, + .remove = sof_es8336_remove, .id_table = board_ids, }; module_platform_driver(sof_es8336_driver); diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index b01cb2329542..8d237f67bd06 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -371,8 +371,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2); } else { dmic_be_num = 2; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->idisp_codec = true; /* links are always present in topology */ @@ -430,7 +429,7 @@ static void sof_pcm512x_remove(struct platform_device *pdev) static struct platform_driver sof_audio = { .probe = sof_audio_probe, - .remove_new = sof_pcm512x_remove, + .remove = sof_pcm512x_remove, .driver = { .name = "sof_pcm512x", .pm = &snd_soc_pm_ops, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 23a40b913290..bc581fea0e3a 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -870,6 +870,13 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_PORT_BT_OFFLOAD(2) | SOF_BT_OFFLOAD_PRESENT), }, + { + .name = "arl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e5feaef669d1..5196d96f5c0e 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -5,42 +5,43 @@ * sof_sdw - ASOC Machine driver for Intel SoundWire platforms */ +#include #include #include #include #include #include #include -#include +#include #include #include "sof_sdw_common.h" #include "../../codecs/rt711.h" -unsigned long sof_sdw_quirk = RT711_JD1; +static unsigned long sof_sdw_quirk = RT711_JD1; static int quirk_override = -1; module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (SOF_JACK_JDSRC(sof_sdw_quirk)) + if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk)) dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", - SOF_JACK_JDSRC(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - dev_err(dev, "quirk SOF_SDW_FOUR_SPK enabled but no longer supported\n"); + SOC_SDW_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & SOC_SDW_FOUR_SPK) + dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n"); if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) - dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n"); + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) + dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n"); if (SOF_SSP_GET_PORT(sof_sdw_quirk)) dev_dbg(dev, "SSP port %ld\n", SOF_SSP_GET_PORT(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) - dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n"); - if (sof_sdw_quirk & SOF_CODEC_SPKR) - dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n"); - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) - dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n"); + if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION) + dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR) + dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); + if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS) + dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n"); } static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -57,7 +58,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, { .callback = sof_sdw_quirk_cb, @@ -99,7 +100,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, /* TigerLake devices */ { @@ -111,7 +112,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD1 | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_SSP_PORT(SOF_I2S_SSP2)), }, { @@ -159,7 +160,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -170,7 +171,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC), + SOC_SDW_PCH_DMIC), }, { /* @@ -185,7 +186,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -199,7 +200,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "8709"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -210,7 +211,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -221,7 +222,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -232,7 +233,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, { @@ -243,7 +244,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, /* TigerLake-SDCA devices */ @@ -293,7 +294,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -479,6 +480,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD2), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, /* MeteorLake devices */ { .callback = sof_sdw_quirk_cb, @@ -501,7 +510,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC | + .driver_data = (void *)(SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(1) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -529,7 +538,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") }, - .driver_data = (void *)(SOF_SIDECAR_AMPS), + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), }, { .callback = sof_sdw_quirk_cb, @@ -537,7 +546,57 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") }, - .driver_data = (void *)(SOF_SIDECAR_AMPS), + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + + /* ArrowLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, {} }; @@ -549,1089 +608,26 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; -static const struct snd_soc_dapm_widget generic_dmic_widgets[] = { - SND_SOC_DAPM_MIC("DMIC", NULL), -}; - -static const struct snd_soc_dapm_widget generic_jack_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_kcontrol_new generic_jack_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static const struct snd_soc_dapm_widget generic_spk_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_kcontrol_new generic_spk_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static const struct snd_soc_dapm_widget maxim_widgets[] = { - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - -static const struct snd_kcontrol_new maxim_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget rt700_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_MIC("AMIC", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_kcontrol_new rt700_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphones"), - SOC_DAPM_PIN_SWITCH("AMIC"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -/* these wrappers are only needed to avoid typecast compilation errors */ -int sdw_startup(struct snd_pcm_substream *substream) -{ - return sdw_startup_stream(substream); -} - -int sdw_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - return sdw_prepare_stream(sdw_stream); -} - -int sdw_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - int ret; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - ret = sdw_enable_stream(sdw_stream); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = sdw_disable_stream(sdw_stream); - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); - - return ret; -} - -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link_ch_map *ch_maps; - int ch = params_channels(params); - unsigned int ch_mask; - int num_codecs; - int step; - int i; - - if (!rtd->dai_link->ch_maps) - return 0; - - /* Identical data will be sent to all codecs in playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ch_mask = GENMASK(ch - 1, 0); - step = 0; - } else { - num_codecs = rtd->dai_link->num_codecs; - - if (ch < num_codecs || ch % num_codecs != 0) { - dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", - ch, num_codecs); - return -EINVAL; - } - - ch_mask = GENMASK(ch / num_codecs - 1, 0); - step = hweight_long(ch_mask); - - } - - /* - * The captured data will be combined from each cpu DAI if the dai - * link has more than one codec DAIs. Set codec channel mask and - * ASoC will set the corresponding channel numbers for each cpu dai. - */ - for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_maps->ch_mask = ch_mask << (i * step); - - return 0; -} - -int sdw_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - return sdw_deprepare_stream(sdw_stream); -} - -void sdw_shutdown(struct snd_pcm_substream *substream) -{ - sdw_shutdown_stream(substream); -} - static const struct snd_soc_ops sdw_ops = { - .startup = sdw_startup, - .prepare = sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = sdw_hw_free, - .shutdown = sdw_shutdown, -}; - -static struct sof_sdw_codec_info codec_info_list[] = { - { - .part_id = 0x700, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt700-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = rt700_rtd_init, - .controls = rt700_controls, - .num_controls = ARRAY_SIZE(rt700_controls), - .widgets = rt700_widgets, - .num_widgets = ARRAY_SIZE(rt700_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x711, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x711, - .version_id = 2, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt711_init, - .exit = sof_sdw_rt711_exit, - .rtd_init = rt711_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x712, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - { - .direction = {true, false}, - .dai_name = "rt712-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt712_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 2, - }, - { - .part_id = 0x1712, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x713, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1713, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1308, - .acpi_id = "10EC1308", - .dais = { - { - .direction = {true, false}, - .dai_name = "rt1308-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 1, - .ops = &sof_sdw_rt1308_i2s_ops, - }, - { - .part_id = 0x1316, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1316-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1318, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1318-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x714, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x714, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x722, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt722-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - { - .direction = {true, false}, - .dai_name = "rt722-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - /* No feedback capability is provided by rt722-sdca codec driver*/ - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt722_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - { - .direction = {false, true}, - .dai_name = "rt722-sdca-aif3", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 3, - }, - { - .part_id = 0x8373, - .dais = { - { - .direction = {true, true}, - .dai_name = "max98373-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_maxim_init, - .rtd_init = maxim_spk_rtd_init, - .controls = maxim_controls, - .num_controls = ARRAY_SIZE(maxim_controls), - .widgets = maxim_widgets, - .num_widgets = ARRAY_SIZE(maxim_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x8363, - .dais = { - { - .direction = {true, false}, - .dai_name = "max98363-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_maxim_init, - .rtd_init = maxim_spk_rtd_init, - .controls = maxim_controls, - .num_controls = ARRAY_SIZE(maxim_controls), - .widgets = maxim_widgets, - .num_widgets = ARRAY_SIZE(maxim_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x5682, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt5682-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = rt5682_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x3556, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs35l56-sdw1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_cs_amp_init, - .rtd_init = cs_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x4242, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs42l42-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = cs42l42_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x4243, - .codec_name = "cs42l43-codec", - .count_sidecar = bridge_cs35l56_count_sidecar, - .add_sidecar = bridge_cs35l56_add_sidecar, - .dais = { - { - .direction = {true, false}, - .dai_name = "cs42l43-dp5", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .rtd_init = cs42l43_hs_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - { - .direction = {false, true}, - .dai_name = "cs42l43-dp1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = cs42l43_dmic_rtd_init, - .widgets = generic_dmic_widgets, - .num_widgets = ARRAY_SIZE(generic_dmic_widgets), - }, - { - .direction = {false, true}, - .dai_name = "cs42l43-dp2", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - { - .direction = {true, false}, - .dai_name = "cs42l43-dp6", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_cs42l43_spk_init, - .rtd_init = cs42l43_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS, - }, - }, - .dai_num = 4, - }, - { - .part_id = 0xaaaa, /* generic codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0xaa55, /* headset codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x55aa, /* amplifier mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x5555, - .version_id = 0, - .dais = { - { - .dai_name = "sdw-mockup-aif1", - .direction = {false, true}, - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - }, - }, - .dai_num = 1, - }, -}; - -static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr) -{ - unsigned int part_id, sdw_version; - int i; - - part_id = SDW_PART_ID(adr); - sdw_version = SDW_VERSION(adr); - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - /* - * A codec info is for all sdw version with the part id if - * version_id is not specified in the codec info. - */ - if (part_id == codec_info_list[i].part_id && - (!codec_info_list[i].version_id || - sdw_version == codec_info_list[i].version_id)) - return &codec_info_list[i]; - - return NULL; - -} - -static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id) -{ - int i; - - if (!acpi_id[0]) - return NULL; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) - return &codec_info_list[i]; - - return NULL; -} - -static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name, - int *dai_index) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { - *dai_index = j; - return &codec_info_list[i]; - } - } - } - - return NULL; -} - -static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - struct snd_soc_dai_link_component *cpus, int cpus_num, - struct snd_soc_dai_link_component *codecs, int codecs_num, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); - dai_links->id = (*be_id)++; - dai_links->name = name; - dai_links->platforms = platform_component; - dai_links->num_platforms = ARRAY_SIZE(platform_component); - dai_links->no_pcm = 1; - dai_links->cpus = cpus; - dai_links->num_cpus = cpus_num; - dai_links->codecs = codecs; - dai_links->num_codecs = codecs_num; - dai_links->dpcm_playback = playback; - dai_links->dpcm_capture = capture; - dai_links->init = init; - dai_links->ops = ops; -} - -static int init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - const char *cpu_dai_name, - const char *codec_name, const char *codec_dai_name, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - struct snd_soc_dai_link_component *dlc; - - /* Allocate two DLCs one for the CPU, one for the CODEC */ - dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); - if (!dlc || !name || !cpu_dai_name || !codec_name || !codec_dai_name) - return -ENOMEM; - - dlc[0].dai_name = cpu_dai_name; - - dlc[1].name = codec_name; - dlc[1].dai_name = codec_dai_name; - - init_dai_link(dev, dai_links, be_id, name, playback, capture, - &dlc[0], 1, &dlc[1], 1, init, ops); - - return 0; -} - -static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, - unsigned int sdw_version, - unsigned int mfg_id, - unsigned int part_id, - unsigned int class_id, - int index_in_link) -{ - int i; - - for (i = 0; i < adr_link->num_adr; i++) { - unsigned int sdw1_version, mfg1_id, part1_id, class1_id; - u64 adr; - - /* skip itself */ - if (i == index_in_link) - continue; - - adr = adr_link->adr_d[i].adr; - - sdw1_version = SDW_VERSION(adr); - mfg1_id = SDW_MFG_ID(adr); - part1_id = SDW_PART_ID(adr); - class1_id = SDW_CLASS_ID(adr); - - if (sdw_version == sdw1_version && - mfg_id == mfg1_id && - part_id == part1_id && - class_id == class1_id) - return false; - } - - return true; -} - -static const char *get_codec_name(struct device *dev, - const struct sof_sdw_codec_info *codec_info, - const struct snd_soc_acpi_link_adr *adr_link, - int adr_index) -{ - u64 adr = adr_link->adr_d[adr_index].adr; - unsigned int sdw_version = SDW_VERSION(adr); - unsigned int link_id = SDW_DISCO_LINK_ID(adr); - unsigned int unique_id = SDW_UNIQUE_ID(adr); - unsigned int mfg_id = SDW_MFG_ID(adr); - unsigned int part_id = SDW_PART_ID(adr); - unsigned int class_id = SDW_CLASS_ID(adr); - - if (codec_info->codec_name) - return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); - else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, - class_id, adr_index)) - return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", - link_id, mfg_id, part_id, class_id); - else - return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", - link_id, mfg_id, part_id, class_id, unique_id); - - return NULL; -} - -static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct sof_sdw_codec_info *codec_info; - struct snd_soc_dai *dai; - int dai_index; - int ret; - int i; - - for_each_rtd_codec_dais(rtd, i, dai) { - codec_info = find_codec_info_dai(dai->name, &dai_index); - if (!codec_info) - return -EINVAL; - - /* - * A codec dai can be connected to different dai links for capture and playback, - * but we only need to call the rtd_init function once. - * The rtd_init for each codec dai is independent. So, the order of rtd_init - * doesn't matter. - */ - if (codec_info->dais[dai_index].rtd_init_done) - continue; - - /* - * Add card controls and dapm widgets for the first codec dai. - * The controls and widgets will be used for all codec dais. - */ - - if (i > 0) - goto skip_add_controls_widgets; - - if (codec_info->dais[dai_index].controls) { - ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, - codec_info->dais[dai_index].num_controls); - if (ret) { - dev_err(card->dev, "%#x controls addition failed: %d\n", - codec_info->part_id, ret); - return ret; - } - } - if (codec_info->dais[dai_index].widgets) { - ret = snd_soc_dapm_new_controls(&card->dapm, - codec_info->dais[dai_index].widgets, - codec_info->dais[dai_index].num_widgets); - if (ret) { - dev_err(card->dev, "%#x widgets addition failed: %d\n", - codec_info->part_id, ret); - return ret; - } - } - -skip_add_controls_widgets: - if (codec_info->dais[dai_index].rtd_init) { - ret = codec_info->dais[dai_index].rtd_init(rtd, dai); - if (ret) - return ret; - } - codec_info->dais[dai_index].rtd_init_done = true; - } - - return 0; -} - -struct sof_sdw_endpoint { - struct list_head list; - - u32 link_mask; - const char *codec_name; - const char *name_prefix; - bool include_sidecar; - - struct sof_sdw_codec_info *codec_info; - const struct sof_sdw_dai_info *dai_info; -}; - -struct sof_sdw_dailink { - bool initialised; - - u8 group_id; - u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; - int num_devs[SNDRV_PCM_STREAM_LAST + 1]; - struct list_head endpoints; + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, }; static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) -{ - struct device *dev = card->dev; - struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); - struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link; - int i; - - for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { - *num_devs += adr_link->num_adr; - - for (i = 0; i < adr_link->num_adr; i++) - *num_ends += adr_link->adr_d[i].num_endpoints; - } - - dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); - - return 0; -} - -static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks, - const struct snd_soc_acpi_endpoint *new) -{ - while (dailinks->initialised) { - if (new->aggregated && dailinks->group_id == new->group_id) - return dailinks; - - dailinks++; - } - - INIT_LIST_HEAD(&dailinks->endpoints); - dailinks->group_id = new->group_id; - dailinks->initialised = true; - - return dailinks; -} - -static int parse_sdw_endpoints(struct snd_soc_card *card, - struct sof_sdw_dailink *sof_dais, - struct sof_sdw_endpoint *sof_ends, - int *num_devs) -{ - struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); - struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link; - struct sof_sdw_endpoint *sof_end = sof_ends; - int num_dais = 0; - int i, j; - int ret; - - for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { - int num_link_dailinks = 0; - - if (!is_power_of_2(adr_link->mask)) { - dev_err(dev, "link with multiple mask bits: 0x%x\n", - adr_link->mask); - return -EINVAL; - } - - for (i = 0; i < adr_link->num_adr; i++) { - const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; - struct sof_sdw_codec_info *codec_info; - const char *codec_name; - - if (!adr_dev->name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_dev->adr); - return -EINVAL; - } - - codec_info = find_codec_info_part(adr_dev->adr); - if (!codec_info) - return -EINVAL; - - ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic; - - codec_name = get_codec_name(dev, codec_info, adr_link, i); - if (!codec_name) - return -ENOMEM; - - dev_dbg(dev, "Adding prefix %s for %s\n", - adr_dev->name_prefix, codec_name); - - sof_end->name_prefix = adr_dev->name_prefix; - - if (codec_info->count_sidecar && codec_info->add_sidecar) { - ret = codec_info->count_sidecar(card, &num_dais, num_devs); - if (ret) - return ret; - - sof_end->include_sidecar = true; - } - - for (j = 0; j < adr_dev->num_endpoints; j++) { - const struct snd_soc_acpi_endpoint *adr_end; - const struct sof_sdw_dai_info *dai_info; - struct sof_sdw_dailink *sof_dai; - int stream; - - adr_end = &adr_dev->endpoints[j]; - dai_info = &codec_info->dais[adr_end->num]; - sof_dai = find_dailink(sof_dais, adr_end); - - if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk)) - continue; - - dev_dbg(dev, - "Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n", - ffs(adr_link->mask) - 1, adr_dev->adr, - adr_end->num, type_strings[dai_info->dai_type], - dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', - dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', - adr_end->aggregated ? "group" : "solo", - adr_end->group_id); - - if (adr_end->num >= codec_info->dai_num) { - dev_err(dev, - "%d is too many endpoints for codec: 0x%x\n", - adr_end->num, codec_info->part_id); - return -EINVAL; - } - - for_each_pcm_streams(stream) { - if (dai_info->direction[stream] && - dai_info->dailink[stream] < 0) { - dev_err(dev, - "Invalid dailink id %d for codec: 0x%x\n", - dai_info->dailink[stream], - codec_info->part_id); - return -EINVAL; - } - - if (dai_info->direction[stream]) { - num_dais += !sof_dai->num_devs[stream]; - sof_dai->num_devs[stream]++; - sof_dai->link_mask[stream] |= adr_link->mask; - } - } - - num_link_dailinks += !!list_empty(&sof_dai->endpoints); - list_add_tail(&sof_end->list, &sof_dai->endpoints); - - sof_end->link_mask = adr_link->mask; - sof_end->codec_name = codec_name; - sof_end->codec_info = codec_info; - sof_end->dai_info = dai_info; - sof_end++; - } - } - - ctx->append_dai_type |= (num_link_dailinks > 1); - } - - return num_dais; -} - static int create_sdw_dailink(struct snd_soc_card *card, - struct sof_sdw_dailink *sof_dai, + struct asoc_sdw_dailink *sof_dai, struct snd_soc_dai_link **dai_links, int *be_id, struct snd_soc_codec_conf **codec_conf) { struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct sof_sdw_endpoint *sof_end; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + struct asoc_sdw_endpoint *sof_end; int stream; int ret; @@ -1670,7 +666,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, continue; sof_end = list_first_entry(&sof_dai->endpoints, - struct sof_sdw_endpoint, list); + struct asoc_sdw_endpoint, list); *be_id = sof_end->dai_info->dailink[stream]; if (*be_id < 0) { @@ -1709,7 +705,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (cur_link != sof_end->link_mask) { int link_num = ffs(sof_end->link_mask) - 1; - int pin_num = ctx->sdw_pin_index[link_num]++; + int pin_num = intel_ctx->sdw_pin_index[link_num]++; cur_link = sof_end->link_mask; @@ -1734,9 +730,10 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, *dai_links, be_id, name, playback, capture, - cpus, num_cpus, codecs, num_codecs, - sof_sdw_rtd_init, &sdw_ops); + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform_component, + ARRAY_SIZE(platform_component), codecs, num_codecs, + asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -1760,14 +757,15 @@ static int create_sdw_dailink(struct snd_soc_card *card, static int create_sdw_dailinks(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, int *be_id, - struct sof_sdw_dailink *sof_dais, + struct asoc_sdw_dailink *sof_dais, struct snd_soc_codec_conf **codec_conf) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int ret, i; - for (i = 0; i < SDW_MAX_LINKS; i++) - ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; + for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) + intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; /* generate DAI links by each sdw link */ while (sof_dais->initialised) { @@ -1790,7 +788,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, static int create_ssp_dailinks(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, int *be_id, - struct sof_sdw_codec_info *ssp_info, + struct asoc_sdw_codec_info *ssp_info, unsigned long ssp_mask) { struct device *dev = card->dev; @@ -1805,10 +803,12 @@ static int create_ssp_dailinks(struct snd_soc_card *card, int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - ret = init_simple_dai_link(dev, *dai_links, be_id, name, - playback, capture, cpu_dai_name, - codec_name, ssp_info->dais[0].dai_name, - NULL, ssp_info->ops); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + playback, capture, cpu_dai_name, + platform_component->name, + ARRAY_SIZE(platform_component), codec_name, + ssp_info->dais[0].dai_name, NULL, + ssp_info->ops); if (ret) return ret; @@ -1828,20 +828,24 @@ static int create_dmic_dailinks(struct snd_soc_card *card, struct device *dev = card->dev; int ret; - ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic01", - 0, 1, // DMIC only supports capture - "DMIC01 Pin", "dmic-codec", "dmic-hifi", - sof_sdw_dmic_init, NULL); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", + 0, 1, // DMIC only supports capture + "DMIC01 Pin", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + asoc_sdw_dmic_init, NULL); if (ret) return ret; (*dai_links)++; - ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", - 0, 1, // DMIC only supports capture - "DMIC16k Pin", "dmic-codec", "dmic-hifi", - /* don't call sof_sdw_dmic_init() twice */ - NULL, NULL); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", + 0, 1, // DMIC only supports capture + "DMIC16k Pin", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + /* don't call asoc_sdw_dmic_init() twice */ + NULL, NULL); if (ret) return ret; @@ -1855,7 +859,8 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, int hdmi_num) { struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int i, ret; for (i = 0; i < hdmi_num; i++) { @@ -1863,7 +868,7 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); char *codec_name, *codec_dai_name; - if (ctx->hdmi.idisp_codec) { + if (intel_ctx->hdmi.idisp_codec) { codec_name = "ehdaudio0D2"; codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, "intel-hdmi-hifi%d", i + 1); @@ -1872,10 +877,12 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, codec_dai_name = "snd-soc-dummy-dai"; } - ret = init_simple_dai_link(dev, *dai_links, be_id, name, - 1, 0, // HDMI only supports playback - cpu_dai_name, codec_name, codec_dai_name, - i == 0 ? sof_sdw_hdmi_init : NULL, NULL); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 0, // HDMI only supports playback + cpu_dai_name, platform_component->name, + ARRAY_SIZE(platform_component), + codec_name, codec_dai_name, + i == 0 ? sof_sdw_hdmi_init : NULL, NULL); if (ret) return ret; @@ -1895,9 +902,11 @@ static int create_bt_dailinks(struct snd_soc_card *card, char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); int ret; - ret = init_simple_dai_link(dev, *dai_links, be_id, name, - 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, - snd_soc_dummy_dlc.dai_name, NULL, NULL); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 1, cpu_dai_name, platform_component->name, + ARRAY_SIZE(platform_component), + snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, + NULL, NULL); if (ret) return ret; @@ -1911,12 +920,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct snd_soc_codec_conf *codec_conf; - struct sof_sdw_codec_info *ssp_info; - struct sof_sdw_endpoint *sof_ends; - struct sof_sdw_dailink *sof_dais; + struct asoc_sdw_codec_info *ssp_info; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; int num_devs = 0; int num_ends = 0; struct snd_soc_dai_link *dai_links; @@ -1926,7 +936,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) unsigned long ssp_mask; int ret; - ret = count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -1944,7 +954,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); if (ret < 0) goto err_end; @@ -1956,14 +966,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) * system only when I2S mode is supported, not sdw mode. * Here check ACPI ID to confirm I2S is supported. */ - ssp_info = find_codec_info_acpi(mach->id); + ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); if (ssp_info) { ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); ssp_num = hweight_long(ssp_mask); } if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->hdmi.idisp_codec = true; + intel_ctx->hdmi.idisp_codec = true; if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) hdmi_num = SOF_TGL_HDMI_COUNT; @@ -1971,15 +981,24 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) hdmi_num = SOF_PRE_TGL_HDMI_COUNT; /* enable dmic01 & dmic16k */ - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) - dmic_num = 2; + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC || mach_params->dmic_num) { + if (ctx->ignore_internal_dmic) + dev_warn(dev, "Ignoring PCH DMIC\n"); + else + dmic_num = 2; + } + /* + * mach_params->dmic_num will be used to set the cfg-mics value of card->components + * string. Overwrite it to the actual number of PCH DMICs used in the device. + */ + mach_params->dmic_num = dmic_num; if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) bt_num = 1; dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", sdw_be_num, ssp_num, dmic_num, - ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); + intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) { @@ -2017,14 +1036,10 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) } /* dmic */ - if (dmic_num > 0) { - if (ctx->ignore_pch_dmic) { - dev_warn(dev, "Ignoring PCH DMIC\n"); - } else { - ret = create_dmic_dailinks(card, &dai_links, &be_id); - if (ret) - goto err_end; - } + if (dmic_num) { + ret = create_dmic_dailinks(card, &dai_links, &be_id); + if (ret) + goto err_end; } /* HDMI */ @@ -2052,88 +1067,41 @@ err_dai: static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int ret = 0; - int i; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - if (codec_info_list[i].codec_card_late_probe) { - ret = codec_info_list[i].codec_card_late_probe(card); + ret = asoc_sdw_card_late_probe(card); + if (ret < 0) + return ret; - if (ret < 0) - return ret; - } - } - - if (ctx->hdmi.idisp_codec) + if (intel_ctx->hdmi.idisp_codec) ret = sof_sdw_hdmi_card_late_probe(card); return ret; } -/* helper to get the link that the codec DAI is used */ -static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, - const char *dai_name) -{ - struct snd_soc_dai_link *dai_link; - int i; - int j; - - for_each_card_prelinks(card, i, dai_link) { - for (j = 0; j < dai_link->num_codecs; j++) { - /* Check each codec in a link */ - if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) - return dai_link; - } - } - return NULL; -} - -static void mc_dailink_exit_loop(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int ret; - int i, j; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - codec_info_list[i].dais[j].rtd_init_done = false; - /* Check each dai in codec_info_lis to see if it is used in the link */ - if (!codec_info_list[i].dais[j].exit) - continue; - /* - * We don't need to call .exit function if there is no matched - * dai link found. - */ - dai_link = mc_find_codec_dai_used(card, - codec_info_list[i].dais[j].dai_name); - if (dai_link) { - /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, dai_link); - if (ret) - dev_warn(card->dev, - "codec exit failed %d\n", - ret); - break; - } - } - } -} - static int mc_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); struct snd_soc_card *card; - struct mc_private *ctx; + struct asoc_sdw_mc_private *ctx; + struct intel_mc_ctx *intel_ctx; int amp_num = 0, i; int ret; dev_dbg(&pdev->dev, "Entry\n"); + intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); + if (!intel_ctx) + return -ENOMEM; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + ctx->private = intel_ctx; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); card = &ctx->card; card->dev = &pdev->dev; card->name = "soundwire"; @@ -2152,8 +1120,9 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); + ctx->mc_quirk = sof_sdw_quirk; /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) codec_info_list[i].amp_num = 0; if (mach->mach_params.subsystem_id_set) { @@ -2171,7 +1140,7 @@ static int mc_probe(struct platform_device *pdev) * amp_num will only be increased for active amp * codecs on used platform */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; card->components = devm_kasprintf(card->dev, GFP_KERNEL, @@ -2192,7 +1161,7 @@ static int mc_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); return ret; } @@ -2205,7 +1174,7 @@ static void mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); } static const struct platform_device_id mc_id_table[] = { @@ -2220,7 +1189,7 @@ static struct platform_driver sof_sdw_driver = { .pm = &snd_soc_pm_ops, }, .probe = mc_probe, - .remove_new = mc_remove, + .remove = mc_remove, .id_table = mc_id_table, }; @@ -2232,3 +1201,4 @@ MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 2a3145d1feb6..3aa1dcec5172 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -12,20 +12,12 @@ #include #include #include +#include #include "sof_hdmi_common.h" -#define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 -#define SDW_UNUSED_DAI_ID -1 -#define SDW_JACK_OUT_DAI_ID 0 -#define SDW_JACK_IN_DAI_ID 1 -#define SDW_AMP_OUT_DAI_ID 2 -#define SDW_AMP_IN_DAI_ID 3 -#define SDW_DMIC_DAI_ID 4 -#define SDW_MAX_CPU_DAIS 16 -#define SDW_INTEL_BIDIR_PDI_BASE 2 - -#define SDW_MAX_LINKS 4 +#define SOC_SDW_MAX_CPU_DAIS 16 +#define SOC_SDW_INTEL_BIDIR_PDI_BASE 2 /* 8 combinations with 4 links + unused group 0 */ #define SDW_MAX_GROUPS 9 @@ -44,27 +36,14 @@ enum { SOF_I2S_SSP5 = BIT(5), }; -#define SOF_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) /* Deprecated and no longer supported by the code */ -#define SOF_SDW_FOUR_SPK BIT(4) +#define SOC_SDW_FOUR_SPK BIT(4) #define SOF_SDW_TGL_HDMI BIT(5) -#define SOF_SDW_PCH_DMIC BIT(6) +#define SOC_SDW_PCH_DMIC BIT(6) #define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7) #define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0)) /* Deprecated and no longer supported by the code */ -#define SOF_SDW_NO_AGGREGATION BIT(14) -/* If a CODEC has an optional speaker output, this quirk will enable it */ -#define SOF_CODEC_SPKR BIT(15) -/* - * If the CODEC has additional devices attached directly to it. - * - * For the cs42l43: - * - 0 - No speaker output - * - SOF_CODEC_SPKR - CODEC internal speaker - * - SOF_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker - * - SOF_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported - */ -#define SOF_SIDECAR_AMPS BIT(16) +#define SOC_SDW_NO_AGGREGATION BIT(14) /* BT audio offload: reserve 3 bits for future */ #define SOF_BT_OFFLOAD_SSP_SHIFT 15 @@ -73,150 +52,15 @@ enum { (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18) -#define SOF_SDW_DAI_TYPE_JACK 0 -#define SOF_SDW_DAI_TYPE_AMP 1 -#define SOF_SDW_DAI_TYPE_MIC 2 - -#define SOF_SDW_MAX_DAI_NUM 8 - -struct sof_sdw_codec_info; - -struct sof_sdw_dai_info { - const bool direction[2]; /* playback & capture support */ - const char *dai_name; - const int dai_type; - const int dailink[2]; /* dailink id for each direction */ - const struct snd_kcontrol_new *controls; - const int num_controls; - const struct snd_soc_dapm_widget *widgets; - const int num_widgets; - int (*init)(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - int (*rtd_init)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); - bool rtd_init_done; /* Indicate that the rtd_init callback is done */ - unsigned long quirk; -}; - -struct sof_sdw_codec_info { - const int part_id; - const int version_id; - const char *codec_name; - int amp_num; - const u8 acpi_id[ACPI_ID_LEN]; - const bool ignore_pch_dmic; - const struct snd_soc_ops *ops; - struct sof_sdw_dai_info dais[SOF_SDW_MAX_DAI_NUM]; - const int dai_num; - - int (*codec_card_late_probe)(struct snd_soc_card *card); - - int (*count_sidecar)(struct snd_soc_card *card, - int *num_dais, int *num_devs); - int (*add_sidecar)(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, - struct snd_soc_codec_conf **codec_conf); -}; - -struct mc_private { - struct snd_soc_card card; - struct snd_soc_jack sdw_headset; +struct intel_mc_ctx { struct sof_hdmi_private hdmi; - struct device *headset_codec_dev; /* only one headset per card */ - struct device *amp_dev1, *amp_dev2; /* To store SDW Pin index for each SoundWire link */ - unsigned int sdw_pin_index[SDW_MAX_LINKS]; - bool append_dai_type; - bool ignore_pch_dmic; + unsigned int sdw_pin_index[SDW_INTEL_MAX_LINKS]; }; -extern unsigned long sof_sdw_quirk; - -int sdw_startup(struct snd_pcm_substream *substream); -int sdw_prepare(struct snd_pcm_substream *substream); -int sdw_trigger(struct snd_pcm_substream *substream, int cmd); -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params); -int sdw_hw_free(struct snd_pcm_substream *substream); -void sdw_shutdown(struct snd_pcm_substream *substream); - /* generic HDMI support */ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd); int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card); -/* DMIC support */ -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); - -/* RT711 support */ -int sof_sdw_rt711_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT711-SDCA support */ -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT1308 I2S support */ -extern const struct snd_soc_ops sof_sdw_rt1308_i2s_ops; - -/* generic amp support */ -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* MAXIM codec support */ -int sof_sdw_maxim_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* CS42L43 support */ -int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* CS AMP support */ -int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, - int *num_dais, int *num_devs); -int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, - struct snd_soc_codec_conf **codec_conf); -int bridge_cs35l56_spk_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -int sof_sdw_cs_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* dai_link init callbacks */ - -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); - #endif diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index f34fabdf9d93..f92867deb029 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -5,10 +5,12 @@ * sof_sdw_hdmi - Helpers to handle HDMI from generic machine driver */ +#include #include #include #include #include +#include #include #include #include @@ -17,23 +19,25 @@ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd) { - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - ctx->hdmi.hdmi_comp = dai->component; + intel_ctx->hdmi.hdmi_comp = dai->component; return 0; } int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; - if (!ctx->hdmi.idisp_codec) + if (!intel_ctx->hdmi.idisp_codec) return 0; - if (!ctx->hdmi.hdmi_comp) + if (!intel_ctx->hdmi.hdmi_comp) return -EINVAL; - return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); + return hda_dsp_hdmi_build_controls(card, intel_ctx->hdmi.hdmi_comp); } diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index f51f1008e016..6ff8895a294a 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -210,6 +210,12 @@ static const struct platform_device_id board_ids[] = { /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_HDMI_PLAYBACK_PRESENT), }, + { + .name = "arl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index b2d02cc92a6a..facc6c32cbfe 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -270,7 +270,11 @@ static int sof_wm8804_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", acpi_dev_name(adev)); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); snd_soc_card_set_drvdata(card, ctx); @@ -290,7 +294,7 @@ static struct platform_driver sof_wm8804_driver = { .pm = &snd_soc_pm_ops, }, .probe = sof_wm8804_probe, - .remove_new = sof_wm8804_remove, + .remove = sof_wm8804_remove, }; module_platform_driver(sof_wm8804_driver); diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index 2e1fa79a04d4..2aa637124bec 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -374,7 +374,7 @@ MODULE_DEVICE_TABLE(acpi, catpt_ids); static struct platform_driver catpt_acpi_driver = { .probe = catpt_acpi_probe, - .remove_new = catpt_acpi_remove, + .remove = catpt_acpi_remove, .driver = { .name = "intel_catpt", .acpi_match_table = catpt_ids, diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 40a74a19c508..91e146e2487d 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -12,6 +12,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \ soc-acpi-intel-arl-match.o \ soc-acpi-intel-lnl-match.o \ + soc-acpi-intel-ptl-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-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 4167b2e9bc6a..bb1324fb588e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -35,6 +35,86 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { + { + .adr = 0x00023201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00023301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -416,6 +496,25 @@ static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { } }; +static const struct snd_soc_acpi_link_adr adl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r_adr), + .adr_d = cs35l56_2_r_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l_adr), + .adr_d = cs35l56_3_l_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr adl_rvp[] = { { .mask = BIT(0), @@ -560,6 +659,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = adl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-cs42l43-l0-cs35l56-l23.tplg", + }, { .link_mask = 0xF, /* 4 active links required */ .links = adl_default, diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index cc87c34e5a08..c97c961187dd 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -7,6 +7,7 @@ #include #include +#include static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, @@ -15,6 +16,112 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = { + { + .adr = 0x00023001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = { + { + .adr = 0x00033001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033401FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { + { + .adr = 0x00023201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00023301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = { + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -51,6 +158,15 @@ static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -77,6 +193,80 @@ static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = { }, }; +static const struct snd_soc_acpi_link_adr arl_cs42l43_l2[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l2_cs35l56_l3[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr), + .adr_d = cs35l56_3_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_l2[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_lr_adr), + .adr_d = cs35l56_2_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r_adr), + .adr_d = cs35l56_2_r_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l_adr), + .adr_d = cs35l56_3_l_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r1_adr), + .adr_d = cs35l56_2_r1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l1_adr), + .adr_d = cs35l56_3_l1_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr arl_rvp[] = { { .mask = BIT(0), @@ -95,19 +285,92 @@ static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = { {} }; +static const struct snd_soc_acpi_codecs arl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + +static const struct snd_soc_acpi_codecs arl_rt5682_hp = { + .num_codecs = 2, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, +}; + +static const struct snd_soc_acpi_codecs arl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = { + { + .comp_ids = &arl_essx_83x6, + .drv_name = "arl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &arl_lt6911_hdmi, + .sof_tplg_filename = "sof-arl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &arl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-arl-es8336", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, + { + .comp_ids = &arl_rt5682_hp, + .drv_name = "arl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &arl_lt6911_hdmi, + .sof_tplg_filename = "sof-arl-rt5682-ssp1-hdmi-ssp02.tplg", + }, + /* place amp-only boards in the end of table */ + { + .id = "INTC10B0", + .drv_name = "arl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-arl-hdmi-ssp02.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + }, + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_2_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + }, + { + .link_mask = BIT(0) | BIT(2), + .links = arl_cs42l43_l0_cs35l56_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg", + }, { .link_mask = BIT(0), .links = arl_cs42l43_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg", }, + { + .link_mask = BIT(2), + .links = arl_cs42l43_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg", + }, + { + .link_mask = BIT(2) | BIT(3), + .links = arl_cs42l43_l2_cs35l56_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = arl_rvp, diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 3df89e4511da..8bbb1052faf2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -8,7 +8,6 @@ #include #include -#include "../skylake/skl.h" #include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs essx_83x6 = { @@ -16,16 +15,11 @@ static const struct snd_soc_acpi_codecs essx_83x6 = { .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; -static struct skl_machine_pdata cnl_pdata = { - .use_tplg_pcm = true, -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", - .pdata = &cnl_pdata, .sof_tplg_filename = "sof-cnl-rt274.tplg", }, { diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c index 84639c41a268..78255d56b08c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -8,7 +8,6 @@ #include #include -#include "../skylake/skl.h" struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { { diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 2017fd0d676f..e93336e27beb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -8,27 +8,13 @@ #include #include -#include "../skylake/skl.h" - -static struct skl_machine_pdata hda_pdata = { - .use_tplg_pcm = true, -}; struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { { /* .id is not used in this file */ .drv_name = "skl_hda_dsp_generic", - - /* .fw_filename is dynamically set in skylake driver */ - - .sof_tplg_filename = "sof-hda-generic.tplg", - - /* - * .machine_quirk and .quirk_data are not used here but - * can be used if we need a more complicated machine driver - * combining HDA+other device (e.g. DMIC). - */ - .pdata = &hda_pdata, + .sof_tplg_filename = "sof-hda-generic", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 39875d67dcd1..6ce75fbb842e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -8,23 +8,17 @@ #include #include -#include "../skylake/skl.h" static const struct snd_soc_acpi_codecs essx_83x6 = { .num_codecs = 3, .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; -static struct skl_machine_pdata icl_pdata = { - .use_tplg_pcm = true, -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { { .id = "INT34C2", .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", - .pdata = &icl_pdata, .sof_tplg_filename = "sof-icl-rt274.tplg", }, { diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 4e817f559d38..d4c158d8441b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -8,9 +8,6 @@ #include #include -#include "../skylake/skl.h" - -static struct skl_machine_pdata skl_dmic_data; static const struct snd_soc_acpi_codecs kbl_codecs = { .num_codecs = 1, @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98357A", @@ -62,7 +58,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98927", @@ -70,7 +65,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_5663_5514_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98927", @@ -78,7 +72,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_poppy_codecs, - .pdata = &skl_dmic_data, }, { .id = "10EC5663", @@ -91,7 +84,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98357_codecs, - .pdata = &skl_dmic_data, }, { .id = "DLGS7219", @@ -99,7 +91,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98927_codecs, - .pdata = &skl_dmic_data }, { .id = "10EC5660", @@ -117,13 +108,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98373_codecs, - .pdata = &skl_dmic_data }, { .id = "MX98373", .drv_name = "kbl_max98373", .fw_filename = "intel/dsp_fw_kbl.bin", - .pdata = &skl_dmic_data }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index e6ffcd5be6c5..2522e6f11749 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -36,6 +36,20 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { { .num = 0, @@ -103,6 +117,51 @@ static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { }, }; +static const struct snd_soc_acpi_adr_device cs35l56_2_l_adr[] = { + { + .adr = 0x00023001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_r_adr[] = { + { + .adr = 0x00033201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { { .adr = 0x00003001FA424301ull, @@ -210,6 +269,39 @@ static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0[] = { }, }; +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr), + .adr_d = cs35l56_3_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_l_adr), + .adr_d = cs35l56_2_l_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_r_adr), + .adr_d = cs35l56_3_r_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr lnl_rvp[] = { { .mask = BIT(0), @@ -312,6 +404,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg", }, + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = lnl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg", + }, + { + .link_mask = BIT(0) | BIT(3), + .links = lnl_cs42l43_l0_cs35l56_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg", + }, { .link_mask = BIT(0), .links = lnl_cs42l43_l0, diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c new file mode 100644 index 000000000000..90f97a44b607 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-ptl-match.c - tables and support for PTL ACPI enumeration. + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#include +#include +#include "soc-acpi-intel-sdw-mockup-match.h" + +struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +/* + * RT722 is a multi-function codec, three endpoints are created for + * its headset, amp and dmic functions. + */ +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .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_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = { + { + .adr = 0x000330025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt722_3_single_adr), + .adr_d = rt722_3_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_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_ptl_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-ptl-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-ptl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.tplg", + }, + { + .link_mask = BIT(0), + .links = ptl_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt711.tplg", + }, + { + .link_mask = BIT(0), + .links = ptl_rt722_only, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + }, + { + .link_mask = BIT(3), + .links = ptl_rt722_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c index 75302e956742..ee6463202918 100644 --- a/sound/soc/intel/common/soc-acpi-intel-skl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c @@ -8,9 +8,6 @@ #include #include -#include "../skylake/skl.h" - -static struct skl_machine_pdata skl_dmic_data; static const struct snd_soc_acpi_codecs skl_codecs = { .num_codecs = 1, @@ -29,7 +26,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = { .fw_filename = "intel/dsp_fw_release.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &skl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98357A", @@ -37,7 +33,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = { .fw_filename = "intel/dsp_fw_release.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &skl_codecs, - .pdata = &skl_dmic_data, }, {}, }; diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile deleted file mode 100644 index ad9be6168428..000000000000 --- a/sound/soc/intel/skylake/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -snd-soc-skl-y := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \ - skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \ - skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o - -ifdef CONFIG_DEBUG_FS - snd-soc-skl-y += skl-debug.o -endif - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += snd-soc-skl.o - -#Skylake Clock device support -snd-soc-skl-ssp-clk-y := skl-ssp-clk.o - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK) += snd-soc-skl-ssp-clk.o diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c deleted file mode 100644 index fd4fdcb95224..000000000000 --- a/sound/soc/intel/skylake/bxt-sst.c +++ /dev/null @@ -1,629 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * bxt-sst.c - DSP library functions for BXT platform - * - * Copyright (C) 2015-16 Intel Corp - * Author:Rafal Redzimski - * Jeeja KP - */ - -#include -#include -#include -#include - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -#define BXT_BASEFW_TIMEOUT 3000 -#define BXT_ROM_INIT_TIMEOUT 70 -#define BXT_IPC_PURGE_FW 0x01004000 - -#define BXT_ROM_INIT 0x5 -#define BXT_ADSP_SRAM0_BASE 0x80000 - -/* Firmware status window */ -#define BXT_ADSP_FW_STATUS BXT_ADSP_SRAM0_BASE -#define BXT_ADSP_ERROR_CODE (BXT_ADSP_FW_STATUS + 0x4) - -#define BXT_ADSP_SRAM1_BASE 0xA0000 - -#define BXT_INSTANCE_ID 0 -#define BXT_BASE_FW_MODULE_ID 0 - -#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 - -/* Delay before scheduling D0i3 entry */ -#define BXT_D0I3_DELAY 5000 - -static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); -} - -static int -bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) -{ - struct snd_dma_buffer dmab; - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - int ret = 0, i, dma_id, stream_tag; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, - BXT_ADSP_FW_BIN_HDR_OFFSET, i); - if (ret < 0) - goto load_library_failed; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, - stripped_fw.size, &dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "Lib prepare DMA err: %x\n", - stream_tag); - ret = stream_tag; - goto load_library_failed; - } - - dma_id = stream_tag - 1; - memcpy(dmab.area, stripped_fw.data, stripped_fw.size); - - ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); - ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true); - if (ret < 0) - dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", - linfo[i].name, ret); - - ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); - } - - return ret; - -load_library_failed: - skl_release_library(linfo, lib_count); - return ret; -} - -/* - * First boot sequence has some extra steps. Core 0 waits for power - * status on core 1, so power up core 1 also momentarily, keep it in - * reset/stall and then turn it off - */ -static int sst_bxt_prepare_fw(struct sst_dsp *ctx, - const void *fwdata, u32 fwsize) -{ - int stream_tag, ret; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", - stream_tag); - return stream_tag; - } - - ctx->dsp_ops.stream_tag = stream_tag; - memcpy(ctx->dmab.area, fwdata, fwsize); - - /* Step 1: Power up core 0 and core1 */ - ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK | - SKL_DSP_CORE_MASK(1)); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0/1 power up failed\n"); - goto base_fw_load_failed; - } - - /* Step 2: Purge FW request */ - sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | - (BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9))); - - /* Step 3: Unset core0 reset state & unstall/run core0 */ - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); - ret = -EIO; - goto base_fw_load_failed; - } - - /* Step 4: Wait for DONE Bit */ - ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE, - BXT_INIT_TIMEOUT, "HIPCIE Done"); - if (ret < 0) { - dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret); - goto base_fw_load_failed; - } - - /* Step 5: power down core1 */ - ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - if (ret < 0) { - dev_err(ctx->dev, "dsp core1 power down failed\n"); - goto base_fw_load_failed; - } - - /* Step 6: Enable Interrupt */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - - /* Step 7: Wait for ROM init */ - ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, - SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load"); - if (ret < 0) { - dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); - goto base_fw_load_failed; - } - - return ret; - -base_fw_load_failed: - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); - skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - return ret; -} - -static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) -{ - int ret; - - ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); - ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, - BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot"); - - ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); - - return ret; -} - -static int bxt_load_base_firmware(struct sst_dsp *ctx) -{ - struct firmware stripped_fw; - struct skl_dev *skl = ctx->thread_context; - int ret, i; - - if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - return ret; - } - } - - /* prase uuids on first boot */ - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); - if (ret < 0) - goto sst_load_base_firmware_failed; - } - - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - skl_dsp_strip_extended_manifest(&stripped_fw); - - - for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { - ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (ret == 0) - break; - } - - if (ret < 0) { - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - - dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); - goto sst_load_base_firmware_failed; - } - - ret = sst_transfer_fw_host_dma(ctx); - if (ret < 0) { - dev_err(ctx->dev, "Transfer firmware failed %d\n", ret); - dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - } else { - dev_dbg(ctx->dev, "Firmware download successful\n"); - ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - ret = -EIO; - } else { - ret = 0; - skl->fw_loaded = true; - } - } - - return ret; - -sst_load_base_firmware_failed: - release_firmware(ctx->fw); - ctx->fw = NULL; - return ret; -} - -/* - * Decide the D0i3 state that can be targeted based on the usecase - * ref counts and DSP state - * - * Decision Matrix: (X= dont care; state = target state) - * - * DSP state != SKL_DSP_RUNNING ; state = no d0i3 - * - * DSP state == SKL_DSP_RUNNING , the following matrix applies - * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 - * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 - * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 - * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 - */ -static int bxt_d0i3_target_state(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) - return SKL_DSP_D0I3_NONE; - - if (d0i3->non_d0i3) - return SKL_DSP_D0I3_NONE; - else if (d0i3->streaming) - return SKL_DSP_D0I3_STREAMING; - else if (d0i3->non_streaming) - return SKL_DSP_D0I3_NON_STREAMING; - else - return SKL_DSP_D0I3_NONE; -} - -static void bxt_set_dsp_D0i3(struct work_struct *work) -{ - int ret; - struct skl_ipc_d0ix_msg msg; - struct skl_dev *skl = container_of(work, - struct skl_dev, d0i3.work.work); - struct sst_dsp *ctx = skl->dsp; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - int target_state; - - dev_dbg(ctx->dev, "In %s:\n", __func__); - - /* D0i3 entry allowed only if core 0 alone is running */ - if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) { - dev_warn(ctx->dev, - "D0i3 allowed when only core0 running:Exit\n"); - return; - } - - target_state = bxt_d0i3_target_state(ctx); - if (target_state == SKL_DSP_D0I3_NONE) - return; - - msg.instance_id = 0; - msg.module_id = 0; - msg.wake = 1; - msg.streaming = 0; - if (target_state == SKL_DSP_D0I3_STREAMING) - msg.streaming = 1; - - ret = skl_ipc_set_d0ix(&skl->ipc, &msg); - - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); - return; - } - - /* Set Vendor specific register D0I3C.I3 to enable D0i3*/ - if (skl->update_d0i3c) - skl->update_d0i3c(skl->dev, true); - - d0i3->state = target_state; - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; -} - -static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - /* Schedule D0i3 only if the usecase ref counts are appropriate */ - if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { - - dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); - - schedule_delayed_work(&d0i3->work, - msecs_to_jiffies(BXT_D0I3_DELAY)); - } - - return 0; -} - -static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) -{ - int ret; - struct skl_ipc_d0ix_msg msg; - struct skl_dev *skl = ctx->thread_context; - - dev_dbg(ctx->dev, "In %s:\n", __func__); - - /* First Cancel any pending attempt to put DSP to D0i3 */ - cancel_delayed_work_sync(&skl->d0i3.work); - - /* If DSP is currently in D0i3, bring it to D0i0 */ - if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) - return 0; - - dev_dbg(ctx->dev, "Set DSP to D0i0\n"); - - msg.instance_id = 0; - msg.module_id = 0; - msg.streaming = 0; - msg.wake = 0; - - if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) - msg.streaming = 1; - - /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ - if (skl->update_d0i3c) - skl->update_d0i3c(skl->dev, false); - - ret = skl_ipc_set_d0ix(&skl->ipc, &msg); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); - return ret; - } - - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; - skl->d0i3.state = SKL_DSP_D0I3_NONE; - - return 0; -} - -static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret; - struct skl_ipc_dxstate_info dx; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - if (skl->fw_loaded == false) { - skl->boot_complete = false; - ret = bxt_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "reload fw failed: %d\n", ret); - return ret; - } - - if (skl->lib_count > 1) { - ret = bxt_load_library(ctx, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(ctx->dev, "reload libs failed: %d\n", ret); - return ret; - } - } - skl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; - } - - /* If core 0 is being turned on, turn on core 1 as well */ - if (core_id == SKL_DSP_CORE0_ID) - ret = skl_dsp_core_power_up(ctx, core_mask | - SKL_DSP_CORE_MASK(1)); - else - ret = skl_dsp_core_power_up(ctx, core_mask); - - if (ret < 0) - goto err; - - if (core_id == SKL_DSP_CORE0_ID) { - - /* - * Enable interrupt after SPA is set and before - * DSP is unstalled - */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - skl->boot_complete = false; - } - - ret = skl_dsp_start_core(ctx, core_mask); - if (ret < 0) - goto err; - - if (core_id == SKL_DSP_CORE0_ID) { - ret = wait_event_timeout(skl->boot_wait, - skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - - /* If core 1 was turned on for booting core 0, turn it off */ - skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - if (ret == 0) { - dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__); - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - dev_err(ctx->dev, "Failed to set core0 to D0 state\n"); - ret = -EIO; - goto err; - } - } - - /* Tell FW if additional core in now On */ - - if (core_id != SKL_DSP_CORE0_ID) { - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, - BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n", - core_id, ret); - goto err; - } - } - - skl->cores.state[core_id] = SKL_DSP_RUNNING; - return 0; -err: - if (core_id == SKL_DSP_CORE0_ID) - core_mask |= SKL_DSP_CORE_MASK(1); - skl_dsp_disable_core(ctx, core_mask); - - return ret; -} - -static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n", - dx.core_mask, dx.dx_mask); - - ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, - BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, - "Failed to set DSP to D3:core id = %d;Continue reset\n", - core_id); - /* - * In case of D3 failure, re-download the firmware, so set - * fw_loaded to false. - */ - skl->fw_loaded = false; - } - - if (core_id == SKL_DSP_CORE0_ID) { - /* disable Interrupt */ - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - ret = skl_dsp_disable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "Failed to disable core %d\n", ret); - return ret; - } - skl->cores.state[core_id] = SKL_DSP_RESET; - return 0; -} - -static const struct skl_dsp_fw_ops bxt_fw_ops = { - .set_state_D0 = bxt_set_dsp_D0, - .set_state_D3 = bxt_set_dsp_D3, - .set_state_D0i3 = bxt_schedule_dsp_D0i3, - .set_state_D0i0 = bxt_set_dsp_D0i0, - .load_fw = bxt_load_base_firmware, - .get_fw_errcode = bxt_get_errorcode, - .load_library = bxt_load_library, -}; - -static struct sst_ops skl_ops = { - .irq_handler = skl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = skl_dsp_free, -}; - -static struct sst_dsp_device skl_dev = { - .thread = skl_dsp_irq_thread_handler, - .ops = &skl_ops, -}; - -int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *skl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - skl = *dsp; - sst = skl->dsp; - sst->fw_ops = bxt_fw_ops; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE; - sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), - SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - - ret = skl_ipc_init(dev, skl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - /* set the D0i3 check */ - skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; - - skl->boot_complete = false; - init_waitqueue_head(&skl->boot_wait); - INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); - skl->d0i3.state = SKL_DSP_D0I3_NONE; - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); - -int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = sst->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "Load base fw failed: %x\n", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - if (skl->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(dev, "Load Library failed : %x\n", ret); - return ret; - } - } - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(bxt_sst_init_fw); - -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - - skl_release_library(skl->lib_info, skl->lib_count); - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - skl_freeup_uuid_list(skl); - skl_ipc_free(&skl->ipc); - skl->dsp->ops->free(skl->dsp); -} -EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Broxton IPC driver"); diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c deleted file mode 100644 index 3ef1b194add1..000000000000 --- a/sound/soc/intel/skylake/cnl-sst-dsp.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cnl-sst-dsp.c - CNL SST library generic function - * - * Copyright (C) 2016-17, Intel Corporation. - * Author: Guneshwor Singh - * - * Modified from: - * SKL SST library generic function - * Copyright (C) 2014-15, Intel Corporation. - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include -#include "../common/sst-dsp.h" -#include "../common/sst-ipc.h" -#include "../common/sst-dsp-priv.h" -#include "cnl-sst-dsp.h" - -/* various timeout values */ -#define CNL_DSP_PU_TO 50 -#define CNL_DSP_PD_TO 50 -#define CNL_DSP_RESET_TO 50 - -static int -cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, - CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask), - CNL_ADSPCS_CRST(core_mask)); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), - CNL_ADSPCS_CRST(core_mask), - CNL_DSP_RESET_TO, - "Set reset"); -} - -static int -cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), - 0, - CNL_DSP_RESET_TO, - "Unset reset"); -} - -static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) -{ - int val; - bool is_enable; - - val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS); - - is_enable = (val & CNL_ADSPCS_CPA(core_mask)) && - (val & CNL_ADSPCS_SPA(core_mask)) && - !(val & CNL_ADSPCS_CRST(core_mask)) && - !(val & CNL_ADSPCS_CSTALL(core_mask)); - - dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n", - is_enable, core_mask); - - return is_enable; -} - -static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* stall core */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CSTALL(core_mask), - CNL_ADSPCS_CSTALL(core_mask)); - - /* set reset state */ - return cnl_dsp_core_set_reset_state(ctx, core_mask); -} - -static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* unset reset state */ - ret = cnl_dsp_core_unset_reset_state(ctx, core_mask); - if (ret < 0) - return ret; - - /* run core */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CSTALL(core_mask), 0); - - if (!is_cnl_dsp_core_enable(ctx, core_mask)) { - cnl_dsp_reset_core(ctx, core_mask); - dev_err(ctx->dev, "DSP core mask %#x enable failed\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_SPA(core_mask), - CNL_ADSPCS_SPA(core_mask)); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CPA(core_mask), - CNL_ADSPCS_CPA(core_mask), - CNL_DSP_PU_TO, - "Power up"); -} - -static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_SPA(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CPA(core_mask), - 0, - CNL_DSP_PD_TO, - "Power down"); -} - -int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* power up */ - ret = cnl_dsp_core_power_up(ctx, core_mask); - if (ret < 0) { - dev_dbg(ctx->dev, "DSP core mask %#x power up failed", - core_mask); - return ret; - } - - return cnl_dsp_start_core(ctx, core_mask); -} - -int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - ret = cnl_dsp_reset_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "DSP core mask %#x reset failed\n", - core_mask); - return ret; - } - - /* power down core*/ - ret = cnl_dsp_core_power_down(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "DSP core mask %#x power down failed\n", - core_mask); - return ret; - } - - if (is_cnl_dsp_core_enable(ctx, core_mask)) { - dev_err(ctx->dev, "DSP core mask %#x disable failed\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id) -{ - struct sst_dsp *ctx = dev_id; - u32 val; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&ctx->spinlock); - - val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS); - ctx->intr_status = val; - - if (val == 0xffffffff) { - spin_unlock(&ctx->spinlock); - return IRQ_NONE; - } - - if (val & CNL_ADSPIS_IPC) { - cnl_ipc_int_disable(ctx); - ret = IRQ_WAKE_THREAD; - } - - spin_unlock(&ctx->spinlock); - - return ret; -} - -void cnl_dsp_free(struct sst_dsp *dsp) -{ - cnl_ipc_int_disable(dsp); - - free_irq(dsp->irq, dsp); - cnl_ipc_op_int_disable(dsp); - cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); -} -EXPORT_SYMBOL_GPL(cnl_dsp_free); - -void cnl_ipc_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC, - CNL_ADSPIC_IPC, CNL_ADSPIC_IPC); -} - -void cnl_ipc_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC, - CNL_ADSPIC_IPC, 0); -} - -void cnl_ipc_op_int_enable(struct sst_dsp *ctx) -{ - /* enable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, - CNL_ADSP_REG_HIPCCTL_DONE); - - /* enable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_BUSY, - CNL_ADSP_REG_HIPCCTL_BUSY); -} - -void cnl_ipc_op_int_disable(struct sst_dsp *ctx) -{ - /* disable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, 0); - - /* disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_BUSY, 0); -} - -bool cnl_ipc_int_status(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) & - CNL_ADSPIS_IPC; -} - -void cnl_ipc_free(struct sst_generic_ipc *ipc) -{ - cnl_ipc_op_int_disable(ipc->dsp); - sst_ipc_fini(ipc); -} diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h deleted file mode 100644 index d3cf4bd1a070..000000000000 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Cannonlake SST DSP Support - * - * Copyright (C) 2016-17, Intel Corporation. - */ - -#ifndef __CNL_SST_DSP_H__ -#define __CNL_SST_DSP_H__ - -struct sst_dsp; -struct sst_dsp_device; -struct sst_generic_ipc; - -/* Intel HD Audio General DSP Registers */ -#define CNL_ADSP_GEN_BASE 0x0 -#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04) -#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08) -#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c) - -/* Intel HD Audio Inter-Processor Communication Registers */ -#define CNL_ADSP_IPC_BASE 0xc0 -#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00) -#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04) -#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08) -#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10) -#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14) -#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18) -#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28) - -/* HIPCTDR */ -#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31) - -/* HIPCTDA */ -#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31) - -/* HIPCIDR */ -#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31) - -/* HIPCIDA */ -#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31) - -/* CNL HIPCCTL */ -#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1) -#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0) - -/* CNL HIPCT */ -#define CNL_ADSP_REG_HIPCT_BUSY BIT(31) - -/* Intel HD Audio SRAM Window 1 */ -#define CNL_ADSP_SRAM1_BASE 0xa0000 - -#define CNL_ADSP_MMIO_LEN 0x10000 - -#define CNL_ADSP_W0_STAT_SZ 0x1000 - -#define CNL_ADSP_W0_UP_SZ 0x1000 - -#define CNL_ADSP_W1_SZ 0x1000 - -#define CNL_FW_STS_MASK 0xf - -#define CNL_ADSPIC_IPC 0x1 -#define CNL_ADSPIS_IPC 0x1 - -#define CNL_DSP_CORES 4 -#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1) - -/* core reset - asserted high */ -#define CNL_ADSPCS_CRST_SHIFT 0 -#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT) - -/* core run/stall - when set to 1 core is stalled */ -#define CNL_ADSPCS_CSTALL_SHIFT 8 -#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT) - -/* set power active - when set to 1 turn core on */ -#define CNL_ADSPCS_SPA_SHIFT 16 -#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT) - -/* current power active - power status of cores, set by hardware */ -#define CNL_ADSPCS_CPA_SHIFT 24 -#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT) - -int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); -int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); -irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id); -void cnl_dsp_free(struct sst_dsp *dsp); - -void cnl_ipc_int_enable(struct sst_dsp *ctx); -void cnl_ipc_int_disable(struct sst_dsp *ctx); -void cnl_ipc_op_int_enable(struct sst_dsp *ctx); -void cnl_ipc_op_int_disable(struct sst_dsp *ctx); -bool cnl_ipc_int_status(struct sst_dsp *ctx); -void cnl_ipc_free(struct sst_generic_ipc *ipc); - -int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); - -#endif /*__CNL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c deleted file mode 100644 index 1275c149acc0..000000000000 --- a/sound/soc/intel/skylake/cnl-sst.c +++ /dev/null @@ -1,508 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cnl-sst.c - DSP library functions for CNL platform - * - * Copyright (C) 2016-17, Intel Corporation. - * - * Author: Guneshwor Singh - * - * Modified from: - * HDA DSP library functions for SKL platform - * Copyright (C) 2014-15, Intel Corporation. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "../common/sst-ipc.h" -#include "cnl-sst-dsp.h" -#include "skl.h" - -#define CNL_FW_ROM_INIT 0x1 -#define CNL_FW_INIT 0x5 -#define CNL_IPC_PURGE 0x01004000 -#define CNL_INIT_TIMEOUT 300 -#define CNL_BASEFW_TIMEOUT 3000 - -#define CNL_ADSP_SRAM0_BASE 0x80000 - -/* Firmware status window */ -#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE -#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4) - -#define CNL_INSTANCE_ID 0 -#define CNL_BASE_FW_MODULE_ID 0 -#define CNL_ADSP_FW_HDR_OFFSET 0x2000 -#define CNL_ROM_CTRL_DMA_ID 0x9 - -static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) -{ - - int ret, stream_tag; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag); - return stream_tag; - } - - ctx->dsp_ops.stream_tag = stream_tag; - memcpy(ctx->dmab.area, fwdata, fwsize); - - ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 power up failed\n"); - ret = -EIO; - goto base_fw_load_failed; - } - - /* purge FW request */ - sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR, - CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE | - ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID))); - - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); - ret = -EIO; - goto base_fw_load_failed; - } - - ret = sst_dsp_register_poll(ctx, CNL_ADSP_REG_HIPCIDA, - CNL_ADSP_REG_HIPCIDA_DONE, - CNL_ADSP_REG_HIPCIDA_DONE, - BXT_INIT_TIMEOUT, "HIPCIDA Done"); - if (ret < 0) { - dev_err(ctx->dev, "timeout for purge request: %d\n", ret); - goto base_fw_load_failed; - } - - /* enable interrupt */ - cnl_ipc_int_enable(ctx); - cnl_ipc_op_int_enable(ctx); - - ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, - CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT, - "rom load"); - if (ret < 0) { - dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret); - goto base_fw_load_failed; - } - - return 0; - -base_fw_load_failed: - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - - return ret; -} - -static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) -{ - int ret; - - ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); - ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, - CNL_FW_INIT, CNL_BASEFW_TIMEOUT, - "firmware boot"); - - ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); - - return ret; -} - -static int cnl_load_base_firmware(struct sst_dsp *ctx) -{ - struct firmware stripped_fw; - struct skl_dev *cnl = ctx->thread_context; - int ret, i; - - if (!ctx->fw) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "request firmware failed: %d\n", ret); - goto cnl_load_base_firmware_failed; - } - } - - /* parse uuids if first boot */ - if (cnl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, - CNL_ADSP_FW_HDR_OFFSET, 0); - if (ret < 0) - goto cnl_load_base_firmware_failed; - } - - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - skl_dsp_strip_extended_manifest(&stripped_fw); - - for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { - ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (!ret) - break; - dev_dbg(ctx->dev, "prepare firmware failed: %d\n", ret); - } - - if (ret < 0) - goto cnl_load_base_firmware_failed; - - ret = sst_transfer_fw_host_dma(ctx); - if (ret < 0) { - dev_err(ctx->dev, "transfer firmware failed: %d\n", ret); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - goto cnl_load_base_firmware_failed; - } - - ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "FW ready timed-out\n"); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - ret = -EIO; - goto cnl_load_base_firmware_failed; - } - - cnl->fw_loaded = true; - - return 0; - -cnl_load_base_firmware_failed: - dev_err(ctx->dev, "firmware load failed: %d\n", ret); - release_firmware(ctx->fw); - ctx->fw = NULL; - - return ret; -} - -static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *cnl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_ipc_dxstate_info dx; - int ret; - - if (!cnl->fw_loaded) { - cnl->boot_complete = false; - ret = cnl_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "fw reload failed: %d\n", ret); - return ret; - } - - cnl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; - } - - ret = cnl_dsp_enable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "enable dsp core %d failed: %d\n", - core_id, ret); - goto err; - } - - if (core_id == SKL_DSP_CORE0_ID) { - /* enable interrupt */ - cnl_ipc_int_enable(ctx); - cnl_ipc_op_int_enable(ctx); - cnl->boot_complete = false; - - ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, - "dsp boot timeout, status=%#x error=%#x\n", - sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS), - sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE)); - ret = -ETIMEDOUT; - goto err; - } - } else { - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, - CNL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n", - core_id, ret); - goto err; - } - } - cnl->cores.state[core_id] = SKL_DSP_RUNNING; - - return 0; -err: - cnl_dsp_disable_core(ctx, core_mask); - - return ret; -} - -static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *cnl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_ipc_dxstate_info dx; - int ret; - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, - CNL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, - "dsp core %d to d3 failed; continue reset\n", - core_id); - cnl->fw_loaded = false; - } - - /* disable interrupts if core 0 */ - if (core_id == SKL_DSP_CORE0_ID) { - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - - ret = cnl_dsp_disable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "disable dsp core %d failed: %d\n", - core_id, ret); - return ret; - } - - cnl->cores.state[core_id] = SKL_DSP_RESET; - - return ret; -} - -static unsigned int cnl_get_errno(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE); -} - -static const struct skl_dsp_fw_ops cnl_fw_ops = { - .set_state_D0 = cnl_set_dsp_D0, - .set_state_D3 = cnl_set_dsp_D3, - .load_fw = cnl_load_base_firmware, - .get_fw_errcode = cnl_get_errno, -}; - -static struct sst_ops cnl_ops = { - .irq_handler = cnl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = cnl_dsp_free, -}; - -#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29 -#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1 -#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \ - & CNL_IPC_GLB_NOTIFY_RSP_MASK) - -static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) -{ - struct sst_dsp *dsp = context; - struct skl_dev *cnl = dsp->thread_context; - struct sst_generic_ipc *ipc = &cnl->ipc; - struct skl_ipc_header header = {0}; - u32 hipcida, hipctdr, hipctdd; - int ipc_irq = 0; - - /* here we handle ipc interrupts only */ - if (!(dsp->intr_status & CNL_ADSPIS_IPC)) - return IRQ_NONE; - - hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA); - hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR); - hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD); - - /* reply message from dsp */ - if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) { - sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, 0); - - /* clear done bit - tell dsp operation is complete */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA, - CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE); - - ipc_irq = 1; - - /* unmask done interrupt */ - sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE); - } - - /* new message from dsp */ - if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) { - header.primary = hipctdr; - header.extension = hipctdd; - dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", - header.primary); - dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", - header.extension); - - if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { - /* Handle Immediate reply from DSP Core */ - skl_ipc_process_reply(ipc, header); - } else { - dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); - skl_ipc_process_notification(ipc, header); - } - /* clear busy interrupt */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR, - CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY); - - /* set done bit to ack dsp */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA, - CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE); - ipc_irq = 1; - } - - if (ipc_irq == 0) - return IRQ_NONE; - - cnl_ipc_int_enable(dsp); - - /* continue to send any remaining messages */ - schedule_work(&ipc->kwork); - - return IRQ_HANDLED; -} - -static struct sst_dsp_device cnl_dev = { - .thread = cnl_dsp_irq_thread_handler, - .ops = &cnl_ops, -}; - -static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) -{ - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - - if (msg->tx.size) - sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, - header->extension); - sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, - header->primary | CNL_ADSP_REG_HIPCIDR_BUSY); -} - -static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) -{ - u32 hipcidr; - - hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR); - - return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); -} - -static int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) -{ - struct sst_generic_ipc *ipc; - int err; - - ipc = &cnl->ipc; - ipc->dsp = cnl->dsp; - ipc->dev = dev; - - ipc->tx_data_max_size = CNL_ADSP_W1_SZ; - ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ; - - err = sst_ipc_init(ipc); - if (err) - return err; - - /* - * overriding tx_msg and is_dsp_busy since - * ipc registers are different for cnl - */ - ipc->ops.tx_msg = cnl_ipc_tx_msg; - ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; - ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy; - - return 0; -} - -int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *cnl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - cnl = *dsp; - sst = cnl->dsp; - sst->fw_ops = cnl_fw_ops; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE; - sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ), - CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE, - CNL_ADSP_W1_SZ); - - ret = cnl_ipc_init(dev, cnl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - cnl->boot_complete = false; - init_waitqueue_head(&cnl->boot_wait); - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); - -int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = skl->dsp->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "load base fw failed: %d", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(cnl_sst_init_fw); - -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - - skl_freeup_uuid_list(skl); - cnl_ipc_free(&skl->ipc); - - skl->dsp->ops->free(skl->dsp); -} -EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Cannonlake IPC driver"); diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c deleted file mode 100644 index a15aa2ffa681..000000000000 --- a/sound/soc/intel/skylake/skl-debug.c +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-debug.c - Debugfs for skl driver - * - * Copyright (C) 2016-17 Intel Corp - */ - -#include -#include -#include -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl-topology.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -#define MOD_BUF PAGE_SIZE -#define FW_REG_BUF PAGE_SIZE -#define FW_REG_SIZE 0x60 - -struct skl_debug { - struct skl_dev *skl; - struct device *dev; - - struct dentry *fs; - struct dentry *modules; - u8 fw_read_buff[FW_REG_BUF]; -}; - -static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, - int max_pin, ssize_t size, bool direction) -{ - int i; - ssize_t ret = 0; - - for (i = 0; i < max_pin; i++) { - ret += scnprintf(buf + size, MOD_BUF - size, - "%s %d\n\tModule %d\n\tInstance %d\n\t" - "In-used %s\n\tType %s\n" - "\tState %d\n\tIndex %d\n", - direction ? "Input Pin:" : "Output Pin:", - i, m_pin[i].id.module_id, - m_pin[i].id.instance_id, - m_pin[i].in_use ? "Used" : "Unused", - m_pin[i].is_dynamic ? "Dynamic" : "Static", - m_pin[i].pin_state, i); - size += ret; - } - return ret; -} - -static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf, - ssize_t size, bool direction) -{ - return scnprintf(buf + size, MOD_BUF - size, - "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t" - "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t" - "Sample Type %d\n\tCh Map %#x\n", - direction ? "Input Format:" : "Output Format:", - fmt->channels, fmt->s_freq, fmt->bit_depth, - fmt->valid_bit_depth, fmt->ch_cfg, - fmt->interleaving_style, fmt->sample_type, - fmt->ch_map); -} - -static ssize_t module_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct skl_module_cfg *mconfig = file->private_data; - struct skl_module *module = mconfig->module; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - char *buf; - ssize_t ret; - - buf = kzalloc(MOD_BUF, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" - "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid, - mconfig->id.module_id, mconfig->id.instance_id, - mconfig->id.pvt_id); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n", - res->cpc, res->ibs, res->obs); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Module data:\n\tCore %d\n\tIn queue %d\n\t" - "Out queue %d\n\tType %s\n", - mconfig->core_id, mconfig->max_in_queue, - mconfig->max_out_queue, - mconfig->is_loadable ? "loadable" : "inbuilt"); - - ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true); - ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Fixup:\n\tParams %#x\n\tConverter %#x\n", - mconfig->params_fixup, mconfig->converter); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n", - mconfig->dev_type, mconfig->vbus_id, - mconfig->hw_conn_type, mconfig->time_slot); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t" - "Pages %#x\n", mconfig->pipe->ppl_id, - mconfig->pipe->pipe_priority, mconfig->pipe->conn_type, - mconfig->pipe->memory_pages); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n", - mconfig->pipe->p_params->host_dma_id, - mconfig->pipe->p_params->link_dma_id); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n", - mconfig->pipe->p_params->ch, - mconfig->pipe->p_params->s_freq, - mconfig->pipe->p_params->s_fmt); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tLink %#x\n\tStream %#x\n", - mconfig->pipe->p_params->linktype, - mconfig->pipe->p_params->stream); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tState %d\n\tPassthru %s\n", - mconfig->pipe->state, - mconfig->pipe->passthru ? "true" : "false"); - - ret += skl_print_pins(mconfig->m_in_pin, buf, - mconfig->max_in_queue, ret, true); - ret += skl_print_pins(mconfig->m_out_pin, buf, - mconfig->max_out_queue, ret, false); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t" - "Homogeneous Output %s\n\tIn Queue Mask %d\n\t" - "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t" - "Module Type %d\n\tModule State %d\n", - mconfig->domain, - mconfig->homogenous_inputs ? "true" : "false", - mconfig->homogenous_outputs ? "true" : "false", - mconfig->in_queue_mask, mconfig->out_queue_mask, - mconfig->dma_id, mconfig->mem_pages, mconfig->m_state, - mconfig->m_type); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); - return ret; -} - -static const struct file_operations mcfg_fops = { - .open = simple_open, - .read = module_read, - .llseek = default_llseek, -}; - - -void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig) -{ - debugfs_create_file(w->name, 0444, d->modules, mconfig, - &mcfg_fops); -} - -static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct skl_debug *d = file->private_data; - struct sst_dsp *sst = d->skl->dsp; - size_t w0_stat_sz = sst->addr.w0_stat_sz; - void __iomem *in_base = sst->mailbox.in_base; - void __iomem *fw_reg_addr; - unsigned int offset; - char *tmp; - ssize_t ret = 0; - - tmp = kzalloc(FW_REG_BUF, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - fw_reg_addr = in_base - w0_stat_sz; - memset(d->fw_read_buff, 0, FW_REG_BUF); - - if (w0_stat_sz > 0) - __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); - - for (offset = 0; offset < FW_REG_SIZE; offset += 16) { - ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); - hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4, - tmp + ret, FW_REG_BUF - ret, 0); - ret += strlen(tmp + ret); - - /* print newline for each offset */ - if (FW_REG_BUF - ret > 0) - tmp[ret++] = '\n'; - } - - ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret); - kfree(tmp); - - return ret; -} - -static const struct file_operations soft_regs_ctrl_fops = { - .open = simple_open, - .read = fw_softreg_read, - .llseek = default_llseek, -}; - -struct skl_debug *skl_debugfs_init(struct skl_dev *skl) -{ - struct skl_debug *d; - - d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL); - if (!d) - return NULL; - - /* create the debugfs dir with platform component's debugfs as parent */ - d->fs = debugfs_create_dir("dsp", skl->component->debugfs_root); - - d->skl = skl; - d->dev = &skl->pci->dev; - - /* now create the module dir */ - d->modules = debugfs_create_dir("modules", d->fs); - - debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, - &soft_regs_ctrl_fops); - - return d; -} - -void skl_debugfs_exit(struct skl_dev *skl) -{ - struct skl_debug *d = skl->debugfs; - - debugfs_remove_recursive(d->fs); - - d = NULL; -} diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h deleted file mode 100644 index dfce91e11be1..000000000000 --- a/sound/soc/intel/skylake/skl-i2s.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl-i2s.h - i2s blob mapping - * - * Copyright (C) 2017 Intel Corp - * Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SOUND_SOC_SKL_I2S_H -#define __SOUND_SOC_SKL_I2S_H - -#define SKL_I2S_MAX_TIME_SLOTS 8 -#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16) - -#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20) -#define SKL_SHIFT(x) (ffs(x) - 1) -#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0) - -#define is_legacy_blob(x) (x.signature != 0xEE) -#define ext_to_legacy_blob(i2s_config_blob_ext) \ - ((struct skl_i2s_config_blob_legacy *) i2s_config_blob_ext) - -#define get_clk_src(mclk, mask) \ - ((mclk.mdivctrl & mask) >> SKL_SHIFT(mask)) -struct skl_i2s_config { - u32 ssc0; - u32 ssc1; - u32 sscto; - u32 sspsp; - u32 sstsa; - u32 ssrsa; - u32 ssc2; - u32 sspsp2; - u32 ssc3; - u32 ssioc; -} __packed; - -struct skl_i2s_config_mclk { - u32 mdivctrl; - u32 mdivr; -}; - -struct skl_i2s_config_mclk_ext { - u32 mdivctrl; - u32 mdivr_count; - u32 mdivr[]; -} __packed; - -struct skl_i2s_config_blob_signature { - u32 minor_ver : 8; - u32 major_ver : 8; - u32 resvdz : 8; - u32 signature : 8; -} __packed; - -struct skl_i2s_config_blob_header { - struct skl_i2s_config_blob_signature sig; - u32 size; -}; - -/** - * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway - * configuration legacy blob - * - * @gtw_attr: Gateway attribute for the I2S Gateway - * @tdm_ts_group: TDM slot mapping against channels in the Gateway. - * @i2s_cfg: I2S HW registers - * @mclk: MCLK clock source and divider values - */ -struct skl_i2s_config_blob_legacy { - u32 gtw_attr; - u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; - struct skl_i2s_config i2s_cfg; - struct skl_i2s_config_mclk mclk; -}; - -struct skl_i2s_config_blob_ext { - u32 gtw_attr; - struct skl_i2s_config_blob_header hdr; - u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; - struct skl_i2s_config i2s_cfg; - struct skl_i2s_config_mclk_ext mclk; -} __packed; -#endif /* __SOUND_SOC_SKL_I2S_H */ diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c deleted file mode 100644 index fc2eb04da172..000000000000 --- a/sound/soc/intel/skylake/skl-messages.c +++ /dev/null @@ -1,1419 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-message.c - HDA DSP interface for FW registration, Pipe and Module - * configurations - * - * Copyright (C) 2015 Intel Corp - * Author:Rafal Redzimski - * Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include "skl-sst-dsp.h" -#include "cnl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl-topology.h" - -static int skl_alloc_dma_buf(struct device *dev, - struct snd_dma_buffer *dmab, size_t size) -{ - return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); -} - -static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) -{ - snd_dma_free_pages(dmab); - return 0; -} - -#define SKL_ASTATE_PARAM_ID 4 - -void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) -{ - struct skl_ipc_large_config_msg msg = {0}; - - msg.large_param_id = SKL_ASTATE_PARAM_ID; - msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + - sizeof(cnt)); - - skl_ipc_set_large_config(&skl->ipc, &msg, data); -} - -static int skl_dsp_setup_spib(struct device *dev, unsigned int size, - int stream_tag, int enable) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - - if (!stream) - return -EINVAL; - - /* enable/disable SPIB for this hdac stream */ - snd_hdac_stream_spbcap_enable(bus, enable, stream->index); - - /* set the spib value */ - snd_hdac_stream_set_spib(bus, stream, size); - - return 0; -} - -static int skl_dsp_prepare(struct device *dev, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_ext_stream *estream; - struct hdac_stream *stream; - struct snd_pcm_substream substream; - int ret; - - if (!bus) - return -ENODEV; - - memset(&substream, 0, sizeof(substream)); - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - - estream = snd_hdac_ext_stream_assign(bus, &substream, - HDAC_EXT_STREAM_TYPE_HOST); - if (!estream) - return -ENODEV; - - stream = hdac_stream(estream); - - /* assign decouple host dma channel */ - ret = snd_hdac_dsp_prepare(stream, format, size, dmab); - if (ret < 0) - return ret; - - skl_dsp_setup_spib(dev, size, stream->stream_tag, true); - - return stream->stream_tag; -} - -static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream; - - if (!bus) - return -ENODEV; - - stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - if (!stream) - return -EINVAL; - - snd_hdac_dsp_trigger(stream, start); - - return 0; -} - -static int skl_dsp_cleanup(struct device *dev, - struct snd_dma_buffer *dmab, int stream_tag) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream; - struct hdac_ext_stream *estream; - - if (!bus) - return -ENODEV; - - stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - if (!stream) - return -EINVAL; - - estream = stream_to_hdac_ext_stream(stream); - skl_dsp_setup_spib(dev, 0, stream_tag, false); - snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST); - - snd_hdac_dsp_cleanup(stream, dmab); - - return 0; -} - -static struct skl_dsp_loader_ops skl_get_loader_ops(void) -{ - struct skl_dsp_loader_ops loader_ops; - - memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops)); - - loader_ops.alloc_dma_buf = skl_alloc_dma_buf; - loader_ops.free_dma_buf = skl_free_dma_buf; - - return loader_ops; -}; - -static struct skl_dsp_loader_ops bxt_get_loader_ops(void) -{ - struct skl_dsp_loader_ops loader_ops; - - memset(&loader_ops, 0, sizeof(loader_ops)); - - loader_ops.alloc_dma_buf = skl_alloc_dma_buf; - loader_ops.free_dma_buf = skl_free_dma_buf; - loader_ops.prepare = skl_dsp_prepare; - loader_ops.trigger = skl_dsp_trigger; - loader_ops.cleanup = skl_dsp_cleanup; - - return loader_ops; -}; - -static const struct skl_dsp_ops dsp_ops[] = { - { - .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, - .num_cores = 2, - .loader_ops = skl_get_loader_ops, - .init = skl_sst_dsp_init, - .init_fw = skl_sst_init_fw, - .cleanup = skl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, - .num_cores = 2, - .loader_ops = skl_get_loader_ops, - .init = skl_sst_dsp_init, - .init_fw = skl_sst_init_fw, - .cleanup = skl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_APL, - .num_cores = 2, - .loader_ops = bxt_get_loader_ops, - .init = bxt_sst_dsp_init, - .init_fw = bxt_sst_init_fw, - .cleanup = bxt_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_GML, - .num_cores = 2, - .loader_ops = bxt_get_loader_ops, - .init = bxt_sst_dsp_init, - .init_fw = bxt_sst_init_fw, - .cleanup = bxt_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CML_H, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, -}; - -const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { - if (dsp_ops[i].id == pci_id) - return &dsp_ops[i]; - } - - return NULL; -} - -int skl_init_dsp(struct skl_dev *skl) -{ - void __iomem *mmio_base; - struct hdac_bus *bus = skl_to_bus(skl); - struct skl_dsp_loader_ops loader_ops; - int irq = bus->irq; - const struct skl_dsp_ops *ops; - struct skl_dsp_cores *cores; - int ret; - - /* enable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_enable(bus, true); - snd_hdac_ext_bus_ppcap_int_enable(bus, true); - - /* read the BAR of the ADSP MMIO */ - mmio_base = pci_ioremap_bar(skl->pci, 4); - if (mmio_base == NULL) { - dev_err(bus->dev, "ioremap error\n"); - return -ENXIO; - } - - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) { - ret = -EIO; - goto unmap_mmio; - } - - loader_ops = ops->loader_ops(); - ret = ops->init(bus->dev, mmio_base, irq, - skl->fw_name, loader_ops, - &skl); - - if (ret < 0) - goto unmap_mmio; - - skl->dsp_ops = ops; - cores = &skl->cores; - cores->count = ops->num_cores; - - cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); - if (!cores->state) { - ret = -ENOMEM; - goto unmap_mmio; - } - - cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count), - GFP_KERNEL); - if (!cores->usage_count) { - ret = -ENOMEM; - goto free_core_state; - } - - dev_dbg(bus->dev, "dsp registration status=%d\n", ret); - - return 0; - -free_core_state: - kfree(cores->state); - -unmap_mmio: - iounmap(mmio_base); - - return ret; -} - -int skl_free_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - - /* disable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_int_enable(bus, false); - - skl->dsp_ops->cleanup(bus->dev, skl); - - kfree(skl->cores.state); - kfree(skl->cores.usage_count); - - if (skl->dsp->addr.lpe) - iounmap(skl->dsp->addr.lpe); - - return 0; -} - -/* - * In the case of "suspend_active" i.e, the Audio IP being active - * during system suspend, immediately excecute any pending D0i3 work - * before suspending. This is needed for the IP to work in low power - * mode during system suspend. In the case of normal suspend, cancel - * any pending D0i3 work. - */ -int skl_suspend_late_dsp(struct skl_dev *skl) -{ - struct delayed_work *dwork; - - if (!skl) - return 0; - - dwork = &skl->d0i3.work; - - if (dwork->work.func) { - if (skl->supend_active) - flush_delayed_work(dwork); - else - cancel_delayed_work_sync(dwork); - } - - return 0; -} - -int skl_suspend_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - int ret; - - /* if ppcap is not supported return 0 */ - if (!bus->ppcap) - return 0; - - ret = skl_dsp_sleep(skl->dsp); - if (ret < 0) - return ret; - - /* disable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_int_enable(bus, false); - snd_hdac_ext_bus_ppcap_enable(bus, false); - - return 0; -} - -int skl_resume_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - int ret; - - /* if ppcap is not supported return 0 */ - if (!bus->ppcap) - return 0; - - /* enable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_enable(bus, true); - snd_hdac_ext_bus_ppcap_int_enable(bus, true); - - /* check if DSP 1st boot is done */ - if (skl->is_first_boot) - return 0; - - /* - * Disable dynamic clock and power gating during firmware - * and library download - */ - skl->enable_miscbdcge(skl->dev, false); - skl->clock_power_gating(skl->dev, false); - - ret = skl_dsp_wake(skl->dsp); - skl->enable_miscbdcge(skl->dev, true); - skl->clock_power_gating(skl->dev, true); - if (ret < 0) - return ret; - - if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, - skl->cfg.astate_cfg); - } - return ret; -} - -enum skl_bitdepth skl_get_bit_depth(int params) -{ - switch (params) { - case 8: - return SKL_DEPTH_8BIT; - - case 16: - return SKL_DEPTH_16BIT; - - case 24: - return SKL_DEPTH_24BIT; - - case 32: - return SKL_DEPTH_32BIT; - - default: - return SKL_DEPTH_INVALID; - - } -} - -/* - * Each module in DSP expects a base module configuration, which consists of - * PCM format information, which we calculate in driver and resource values - * which are read from widget information passed through topology binary - * This is send when we create a module with INIT_INSTANCE IPC msg - */ -static void skl_set_base_module_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_cfg *base_cfg) -{ - struct skl_module *module = mconfig->module; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *format = &fmt->inputs[0].fmt; - - base_cfg->audio_fmt.number_of_channels = format->channels; - - base_cfg->audio_fmt.s_freq = format->s_freq; - base_cfg->audio_fmt.bit_depth = format->bit_depth; - base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; - base_cfg->audio_fmt.ch_cfg = format->ch_cfg; - base_cfg->audio_fmt.sample_type = format->sample_type; - - dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", - format->bit_depth, format->valid_bit_depth, - format->ch_cfg); - - base_cfg->audio_fmt.channel_map = format->ch_map; - - base_cfg->audio_fmt.interleaving = format->interleaving_style; - - base_cfg->cpc = res->cpc; - base_cfg->ibs = res->ibs; - base_cfg->obs = res->obs; - base_cfg->is_pages = res->is_pages; -} - -static void fill_pin_params(struct skl_audio_data_format *pin_fmt, - struct skl_module_fmt *format) -{ - pin_fmt->number_of_channels = format->channels; - pin_fmt->s_freq = format->s_freq; - pin_fmt->bit_depth = format->bit_depth; - pin_fmt->valid_bit_depth = format->valid_bit_depth; - pin_fmt->ch_cfg = format->ch_cfg; - pin_fmt->sample_type = format->sample_type; - pin_fmt->channel_map = format->ch_map; - pin_fmt->interleaving = format->interleaving_style; -} - -/* - * Any module configuration begins with a base module configuration but - * can be followed by a generic extension containing audio format for all - * module's pins that are in use. - */ -static void skl_set_base_ext_module_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_cfg_ext *base_cfg_ext) -{ - struct skl_module *module = mconfig->module; - struct skl_module_pin_resources *pin_res; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - struct skl_module_fmt *format; - struct skl_pin_format *pin_fmt; - char *params; - int i; - - base_cfg_ext->nr_input_pins = res->nr_input_pins; - base_cfg_ext->nr_output_pins = res->nr_output_pins; - base_cfg_ext->priv_param_length = - mconfig->formats_config[SKL_PARAM_INIT].caps_size; - - for (i = 0; i < res->nr_input_pins; i++) { - pin_res = &res->input[i]; - pin_fmt = &base_cfg_ext->pins_fmt[i]; - - pin_fmt->pin_idx = pin_res->pin_index; - pin_fmt->buf_size = pin_res->buf_size; - - format = &fmt->inputs[pin_res->pin_index].fmt; - fill_pin_params(&pin_fmt->audio_fmt, format); - } - - for (i = 0; i < res->nr_output_pins; i++) { - pin_res = &res->output[i]; - pin_fmt = &base_cfg_ext->pins_fmt[res->nr_input_pins + i]; - - pin_fmt->pin_idx = pin_res->pin_index; - pin_fmt->buf_size = pin_res->buf_size; - - format = &fmt->outputs[pin_res->pin_index].fmt; - fill_pin_params(&pin_fmt->audio_fmt, format); - } - - if (!base_cfg_ext->priv_param_length) - return; - - params = (char *)base_cfg_ext + sizeof(struct skl_base_cfg_ext); - params += (base_cfg_ext->nr_input_pins + base_cfg_ext->nr_output_pins) * - sizeof(struct skl_pin_format); - - memcpy(params, mconfig->formats_config[SKL_PARAM_INIT].caps, - mconfig->formats_config[SKL_PARAM_INIT].caps_size); -} - -/* - * Copies copier capabilities into copier module and updates copier module - * config size. - */ -static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - if (mconfig->formats_config[SKL_PARAM_INIT].caps_size == 0) - return; - - memcpy(&cpr_mconfig->gtw_cfg.config_data, - mconfig->formats_config[SKL_PARAM_INIT].caps, - mconfig->formats_config[SKL_PARAM_INIT].caps_size); - - cpr_mconfig->gtw_cfg.config_length = - (mconfig->formats_config[SKL_PARAM_INIT].caps_size) / 4; -} - -#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF -/* - * Calculate the gatewat settings required for copier module, type of - * gateway and index of gateway to use - */ -static u32 skl_get_node_id(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - union skl_connector_node_id node_id = {0}; - union skl_ssp_dma_node ssp_node = {0}; - struct skl_pipe_params *params = mconfig->pipe->p_params; - - switch (mconfig->dev_type) { - case SKL_DEVICE_BT: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_I2S_LINK_OUTPUT_CLASS : - SKL_DMA_I2S_LINK_INPUT_CLASS; - node_id.node.vindex = params->host_dma_id + - (mconfig->vbus_id << 3); - break; - - case SKL_DEVICE_I2S: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_I2S_LINK_OUTPUT_CLASS : - SKL_DMA_I2S_LINK_INPUT_CLASS; - ssp_node.dma_node.time_slot_index = mconfig->time_slot; - ssp_node.dma_node.i2s_instance = mconfig->vbus_id; - node_id.node.vindex = ssp_node.val; - break; - - case SKL_DEVICE_DMIC: - node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS; - node_id.node.vindex = mconfig->vbus_id + - (mconfig->time_slot); - break; - - case SKL_DEVICE_HDALINK: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_HDA_LINK_OUTPUT_CLASS : - SKL_DMA_HDA_LINK_INPUT_CLASS; - node_id.node.vindex = params->link_dma_id; - break; - - case SKL_DEVICE_HDAHOST: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_HDA_HOST_OUTPUT_CLASS : - SKL_DMA_HDA_HOST_INPUT_CLASS; - node_id.node.vindex = params->host_dma_id; - break; - - default: - node_id.val = 0xFFFFFFFF; - break; - } - - return node_id.val; -} - -static void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - u32 dma_io_buf; - struct skl_module_res *res; - int res_idx = mconfig->res_idx; - - cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); - - if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { - cpr_mconfig->cpr_feature_mask = 0; - return; - } - - if (skl->nr_modules) { - res = &mconfig->module->resources[mconfig->res_idx]; - cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size; - goto skip_buf_size_calc; - } else { - res = &mconfig->module->resources[res_idx]; - } - - switch (mconfig->hw_conn_type) { - case SKL_CONN_SOURCE: - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - dma_io_buf = res->ibs; - else - dma_io_buf = res->obs; - break; - - case SKL_CONN_SINK: - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - dma_io_buf = res->obs; - else - dma_io_buf = res->ibs; - break; - - default: - dev_warn(skl->dev, "wrong connection type: %d\n", - mconfig->hw_conn_type); - return; - } - - cpr_mconfig->gtw_cfg.dma_buffer_size = - mconfig->dma_buffer_size * dma_io_buf; - - /* fallback to 2ms default value */ - if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { - if (mconfig->hw_conn_type == SKL_CONN_SOURCE) - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs; - else - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs; - } - -skip_buf_size_calc: - cpr_mconfig->cpr_feature_mask = 0; - cpr_mconfig->gtw_cfg.config_length = 0; - - skl_copy_copier_caps(mconfig, cpr_mconfig); -} - -#define DMA_CONTROL_ID 5 -#define DMA_I2S_BLOB_SIZE 21 - -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id) -{ - struct skl_dma_control *dma_ctrl; - struct skl_ipc_large_config_msg msg = {0}; - int err = 0; - - - /* - * if blob size zero, then return - */ - if (caps_size == 0) - return 0; - - msg.large_param_id = DMA_CONTROL_ID; - msg.param_data_size = sizeof(struct skl_dma_control) + caps_size; - - dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL); - if (dma_ctrl == NULL) - return -ENOMEM; - - dma_ctrl->node_id = node_id; - - /* - * NHLT blob may contain additional configs along with i2s blob. - * firmware expects only the i2s blob size as the config_length. - * So fix to i2s blob size. - * size in dwords. - */ - dma_ctrl->config_length = DMA_I2S_BLOB_SIZE; - - memcpy(dma_ctrl->config_data, caps, caps_size); - - err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); - - kfree(dma_ctrl); - return err; -} -EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); - -static void skl_setup_out_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_audio_data_format *out_fmt) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *format = &fmt->outputs[0].fmt; - - out_fmt->number_of_channels = (u8)format->channels; - out_fmt->s_freq = format->s_freq; - out_fmt->bit_depth = format->bit_depth; - out_fmt->valid_bit_depth = format->valid_bit_depth; - out_fmt->ch_cfg = format->ch_cfg; - - out_fmt->channel_map = format->ch_map; - out_fmt->interleaving = format->interleaving_style; - out_fmt->sample_type = format->sample_type; - - dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", - out_fmt->number_of_channels, format->s_freq, format->bit_depth); -} - -/* - * DSP needs SRC module for frequency conversion, SRC takes base module - * configuration and the target frequency as extra parameter passed as src - * config - */ -static void skl_set_src_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_src_module_cfg *src_mconfig) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - - skl_set_base_module_format(skl, mconfig, - (struct skl_base_cfg *)src_mconfig); - - src_mconfig->src_cfg = fmt->s_freq; -} - -/* - * DSP needs updown module to do channel conversion. updown module take base - * module configuration and channel configuration - * It also take coefficients and now we have defaults applied here - */ -static void skl_set_updown_mixer_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_up_down_mixer_cfg *mixer_mconfig) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - - skl_set_base_module_format(skl, mconfig, - (struct skl_base_cfg *)mixer_mconfig); - mixer_mconfig->out_ch_cfg = fmt->ch_cfg; - mixer_mconfig->ch_map = fmt->ch_map; -} - -/* - * 'copier' is DSP internal module which copies data from Host DMA (HDA host - * dma) or link (hda link, SSP, PDM) - * Here we calculate the copier module parameters, like PCM format, output - * format, gateway settings - * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg - */ -static void skl_set_copier_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; - struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; - - skl_set_base_module_format(skl, mconfig, base_cfg); - - skl_setup_out_format(skl, mconfig, out_fmt); - skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); -} - -/* - * Mic select module allows selecting one or many input channels, thus - * acting as a demux. - * - * Mic select module take base module configuration and out-format - * configuration - */ -static void skl_set_base_outfmt_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_outfmt_cfg *base_outfmt_mcfg) -{ - struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; - struct skl_base_cfg *base_cfg = - (struct skl_base_cfg *)base_outfmt_mcfg; - - skl_set_base_module_format(skl, mconfig, base_cfg); - skl_setup_out_format(skl, mconfig, out_fmt); -} - -static u16 skl_get_module_param_size(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_module_res *res; - struct skl_module *module = mconfig->module; - u16 param_size; - - switch (mconfig->m_type) { - case SKL_MODULE_TYPE_COPIER: - param_size = sizeof(struct skl_cpr_cfg); - param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; - return param_size; - - case SKL_MODULE_TYPE_SRCINT: - return sizeof(struct skl_src_module_cfg); - - case SKL_MODULE_TYPE_UPDWMIX: - return sizeof(struct skl_up_down_mixer_cfg); - - case SKL_MODULE_TYPE_BASE_OUTFMT: - case SKL_MODULE_TYPE_MIC_SELECT: - return sizeof(struct skl_base_outfmt_cfg); - - case SKL_MODULE_TYPE_MIXER: - case SKL_MODULE_TYPE_KPB: - return sizeof(struct skl_base_cfg); - - case SKL_MODULE_TYPE_ALGO: - default: - res = &module->resources[mconfig->res_idx]; - - param_size = sizeof(struct skl_base_cfg) + sizeof(struct skl_base_cfg_ext); - param_size += (res->nr_input_pins + res->nr_output_pins) * - sizeof(struct skl_pin_format); - param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; - - return param_size; - } - - return 0; -} - -/* - * DSP firmware supports various modules like copier, SRC, updown etc. - * These modules required various parameters to be calculated and sent for - * the module initialization to DSP. By default a generic module needs only - * base module format configuration - */ - -static int skl_set_module_format(struct skl_dev *skl, - struct skl_module_cfg *module_config, - u16 *module_config_size, - void **param_data) -{ - u16 param_size; - - param_size = skl_get_module_param_size(skl, module_config); - - *param_data = kzalloc(param_size, GFP_KERNEL); - if (NULL == *param_data) - return -ENOMEM; - - *module_config_size = param_size; - - switch (module_config->m_type) { - case SKL_MODULE_TYPE_COPIER: - skl_set_copier_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_SRCINT: - skl_set_src_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_UPDWMIX: - skl_set_updown_mixer_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_BASE_OUTFMT: - case SKL_MODULE_TYPE_MIC_SELECT: - skl_set_base_outfmt_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_MIXER: - case SKL_MODULE_TYPE_KPB: - skl_set_base_module_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_ALGO: - default: - skl_set_base_module_format(skl, module_config, *param_data); - skl_set_base_ext_module_format(skl, module_config, - *param_data + - sizeof(struct skl_base_cfg)); - break; - } - - dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", - module_config->m_type, module_config->id.module_id, - param_size); - print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, - *param_data, param_size, false); - return 0; -} - -static int skl_get_queue_index(struct skl_module_pin *mpin, - struct skl_module_inst_id id, int max) -{ - int i; - - for (i = 0; i < max; i++) { - if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id) - return i; - } - - return -EINVAL; -} - -/* - * Allocates queue for each module. - * if dynamic, the pin_index is allocated 0 to max_pin. - * In static, the pin_index is fixed based on module_id and instance id - */ -static int skl_alloc_queue(struct skl_module_pin *mpin, - struct skl_module_cfg *tgt_cfg, int max) -{ - int i; - struct skl_module_inst_id id = tgt_cfg->id; - /* - * if pin in dynamic, find first free pin - * otherwise find match module and instance id pin as topology will - * ensure a unique pin is assigned to this so no need to - * allocate/free - */ - for (i = 0; i < max; i++) { - if (mpin[i].is_dynamic) { - if (!mpin[i].in_use && - mpin[i].pin_state == SKL_PIN_UNBIND) { - - mpin[i].in_use = true; - mpin[i].id.module_id = id.module_id; - mpin[i].id.instance_id = id.instance_id; - mpin[i].id.pvt_id = id.pvt_id; - mpin[i].tgt_mcfg = tgt_cfg; - return i; - } - } else { - if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id && - mpin[i].pin_state == SKL_PIN_UNBIND) { - - mpin[i].tgt_mcfg = tgt_cfg; - return i; - } - } - } - - return -EINVAL; -} - -static void skl_free_queue(struct skl_module_pin *mpin, int q_index) -{ - if (mpin[q_index].is_dynamic) { - mpin[q_index].in_use = false; - mpin[q_index].id.module_id = 0; - mpin[q_index].id.instance_id = 0; - mpin[q_index].id.pvt_id = 0; - } - mpin[q_index].pin_state = SKL_PIN_UNBIND; - mpin[q_index].tgt_mcfg = NULL; -} - -/* Module state will be set to unint, if all the out pin state is UNBIND */ - -static void skl_clear_module_state(struct skl_module_pin *mpin, int max, - struct skl_module_cfg *mcfg) -{ - int i; - bool found = false; - - for (i = 0; i < max; i++) { - if (mpin[i].pin_state == SKL_PIN_UNBIND) - continue; - found = true; - break; - } - - if (!found) - mcfg->m_state = SKL_MODULE_INIT_DONE; - return; -} - -/* - * A module needs to be instanataited in DSP. A mdoule is present in a - * collection of module referred as a PIPE. - * We first calculate the module format, based on module type and then - * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper - */ -int skl_init_module(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - u16 module_config_size = 0; - void *param_data = NULL; - int ret; - struct skl_ipc_init_instance_msg msg; - - dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, - mconfig->id.module_id, mconfig->id.pvt_id); - - if (mconfig->pipe->state != SKL_PIPE_CREATED) { - dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", - mconfig->pipe->state, mconfig->pipe->ppl_id); - return -EIO; - } - - ret = skl_set_module_format(skl, mconfig, - &module_config_size, ¶m_data); - if (ret < 0) { - dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); - return ret; - } - - msg.module_id = mconfig->id.module_id; - msg.instance_id = mconfig->id.pvt_id; - msg.ppl_instance_id = mconfig->pipe->ppl_id; - msg.param_data_size = module_config_size; - msg.core_id = mconfig->core_id; - msg.domain = mconfig->domain; - - ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); - if (ret < 0) { - dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); - kfree(param_data); - return ret; - } - mconfig->m_state = SKL_MODULE_INIT_DONE; - kfree(param_data); - return ret; -} - -static void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg - *src_module, struct skl_module_cfg *dst_module) -{ - dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", - __func__, src_module->id.module_id, src_module->id.pvt_id); - dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, - dst_module->id.module_id, dst_module->id.pvt_id); - - dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", - src_module->m_state, dst_module->m_state); -} - -/* - * On module freeup, we need to unbind the module with modules - * it is already bind. - * Find the pin allocated and unbind then using bind_unbind IPC - */ -int skl_unbind_modules(struct skl_dev *skl, - struct skl_module_cfg *src_mcfg, - struct skl_module_cfg *dst_mcfg) -{ - int ret; - struct skl_ipc_bind_unbind_msg msg; - struct skl_module_inst_id src_id = src_mcfg->id; - struct skl_module_inst_id dst_id = dst_mcfg->id; - int in_max = dst_mcfg->module->max_input_pins; - int out_max = src_mcfg->module->max_output_pins; - int src_index, dst_index, src_pin_state, dst_pin_state; - - skl_dump_bind_info(skl, src_mcfg, dst_mcfg); - - /* get src queue index */ - src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); - if (src_index < 0) - return 0; - - msg.src_queue = src_index; - - /* get dst queue index */ - dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); - if (dst_index < 0) - return 0; - - msg.dst_queue = dst_index; - - src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; - dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; - - if (src_pin_state != SKL_PIN_BIND_DONE || - dst_pin_state != SKL_PIN_BIND_DONE) - return 0; - - msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.pvt_id; - msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.pvt_id; - msg.bind = false; - - ret = skl_ipc_bind_unbind(&skl->ipc, &msg); - if (!ret) { - /* free queue only if unbind is success */ - skl_free_queue(src_mcfg->m_out_pin, src_index); - skl_free_queue(dst_mcfg->m_in_pin, dst_index); - - /* - * check only if src module bind state, bind is - * always from src -> sink - */ - skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); - } - - return ret; -} - -#define CPR_SINK_FMT_PARAM_ID 2 - -/* - * Once a module is instantiated it need to be 'bind' with other modules in - * the pipeline. For binding we need to find the module pins which are bind - * together - * This function finds the pins and then sends bund_unbind IPC message to - * DSP using IPC helper - */ -int skl_bind_modules(struct skl_dev *skl, - struct skl_module_cfg *src_mcfg, - struct skl_module_cfg *dst_mcfg) -{ - int ret = 0; - struct skl_ipc_bind_unbind_msg msg; - int in_max = dst_mcfg->module->max_input_pins; - int out_max = src_mcfg->module->max_output_pins; - int src_index, dst_index; - struct skl_module_fmt *format; - struct skl_cpr_pin_fmt pin_fmt; - struct skl_module *module; - struct skl_module_iface *fmt; - - skl_dump_bind_info(skl, src_mcfg, dst_mcfg); - - if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || - dst_mcfg->m_state < SKL_MODULE_INIT_DONE) - return 0; - - src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); - if (src_index < 0) - return -EINVAL; - - msg.src_queue = src_index; - dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); - if (dst_index < 0) { - skl_free_queue(src_mcfg->m_out_pin, src_index); - return -EINVAL; - } - - /* - * Copier module requires the separate large_config_set_ipc to - * configure the pins other than 0 - */ - if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) { - pin_fmt.sink_id = src_index; - module = src_mcfg->module; - fmt = &module->formats[src_mcfg->fmt_idx]; - - /* Input fmt is same as that of src module input cfg */ - format = &fmt->inputs[0].fmt; - fill_pin_params(&(pin_fmt.src_fmt), format); - - format = &fmt->outputs[src_index].fmt; - fill_pin_params(&(pin_fmt.dst_fmt), format); - ret = skl_set_module_params(skl, (void *)&pin_fmt, - sizeof(struct skl_cpr_pin_fmt), - CPR_SINK_FMT_PARAM_ID, src_mcfg); - - if (ret < 0) - goto out; - } - - msg.dst_queue = dst_index; - - dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", - msg.src_queue, msg.dst_queue); - - msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.pvt_id; - msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.pvt_id; - msg.bind = true; - - ret = skl_ipc_bind_unbind(&skl->ipc, &msg); - - if (!ret) { - src_mcfg->m_state = SKL_MODULE_BIND_DONE; - src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; - dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; - return ret; - } -out: - /* error case , if IPC fails, clear the queue index */ - skl_free_queue(src_mcfg->m_out_pin, src_index); - skl_free_queue(dst_mcfg->m_in_pin, dst_index); - - return ret; -} - -static int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, - enum skl_ipc_pipeline_state state) -{ - dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); - - return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); -} - -/* - * A pipeline is a collection of modules. Before a module in instantiated a - * pipeline needs to be created for it. - * This function creates pipeline, by sending create pipeline IPC messages - * to FW - */ -int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); - - ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, - pipe->pipe_priority, pipe->ppl_id, - pipe->lp_mode); - if (ret < 0) { - dev_err(skl->dev, "Failed to create pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_CREATED; - - return 0; -} - -/* - * A pipeline needs to be deleted on cleanup. If a pipeline is running, - * then pause it first. Before actual deletion, pipeline should enter - * reset state. Finish the procedure by sending delete pipeline IPC. - * DSP will stop the DMA engines and release resources - */ -int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to delete it */ - if (pipe->state < SKL_PIPE_CREATED) - return 0; - - /* If pipe is started, do stop the pipe in FW. */ - if (pipe->state >= SKL_PIPE_STARTED) { - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_err(skl->dev, "Failed to stop pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - } - - /* reset pipe state before deletion */ - ret = skl_set_pipe_state(skl, pipe, PPL_RESET); - if (ret < 0) { - dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); - return ret; - } - - pipe->state = SKL_PIPE_RESET; - - ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); - if (ret < 0) { - dev_err(skl->dev, "Failed to delete pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_INVALID; - - return ret; -} - -/* - * A pipeline is also a scheduling entity in DSP which can be run, stopped - * For processing data the pipe need to be run by sending IPC set pipe state - * to DSP - */ -int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_CREATED) - return 0; - - /* Pipe has to be paused before it is started */ - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_err(skl->dev, "Failed to pause pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - - ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); - if (ret < 0) { - dev_err(skl->dev, "Failed to start pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_STARTED; - - return 0; -} - -/* - * Stop the pipeline by sending set pipe state IPC - * DSP doesnt implement stop so we always send pause message - */ -int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_PAUSED) - return 0; - - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_dbg(skl->dev, "Failed to stop pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - - return 0; -} - -/* - * Reset the pipeline by sending set pipe state IPC this will reset the DMA - * from the DSP side - */ -int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_PAUSED) - return 0; - - ret = skl_set_pipe_state(skl, pipe, PPL_RESET); - if (ret < 0) { - dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); - return ret; - } - - pipe->state = SKL_PIPE_RESET; - - return 0; -} - -/* Algo parameter set helper function */ -int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg) -{ - struct skl_ipc_large_config_msg msg; - - msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.pvt_id; - msg.param_data_size = size; - msg.large_param_id = param_id; - - return skl_ipc_set_large_config(&skl->ipc, &msg, params); -} - -int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg) -{ - struct skl_ipc_large_config_msg msg; - size_t bytes = size; - - msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.pvt_id; - msg.param_data_size = size; - msg.large_param_id = param_id; - - return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); -} diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c deleted file mode 100644 index e617b4c335a4..000000000000 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-nhlt.c - Intel SKL Platform NHLT parsing - * - * Copyright (C) 2015 Intel Corp - * Author: Sanjiv Kumar - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include -#include -#include "skl.h" -#include "skl-i2s.h" - -static void skl_nhlt_trim_space(char *trim) -{ - char *s = trim; - int cnt; - int i; - - cnt = 0; - for (i = 0; s[i]; i++) { - if (!isspace(s[i])) - s[cnt++] = s[i]; - } - - s[cnt] = '\0'; -} - -int skl_nhlt_update_topology_bin(struct skl_dev *skl) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct hdac_bus *bus = skl_to_bus(skl); - struct device *dev = bus->dev; - - dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n", - nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision); - - snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", - skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision, "-tplg.bin"); - - skl_nhlt_trim_space(skl->tplg_name); - - return 0; -} - -static ssize_t platform_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - char platform_id[32]; - - sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, - nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision); - - skl_nhlt_trim_space(platform_id); - return sysfs_emit(buf, "%s\n", platform_id); -} - -static DEVICE_ATTR_RO(platform_id); - -int skl_nhlt_create_sysfs(struct skl_dev *skl) -{ - struct device *dev = &skl->pci->dev; - - if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) - dev_warn(dev, "Error creating sysfs entry\n"); - - return 0; -} - -void skl_nhlt_remove_sysfs(struct skl_dev *skl) -{ - struct device *dev = &skl->pci->dev; - - if (skl->nhlt) - sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); -} - -/* - * Queries NHLT for all the fmt configuration for a particular endpoint and - * stores all possible rates supported in a rate table for the corresponding - * sclk/sclkfs. - */ -static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, - struct nhlt_fmt *fmt, u8 id) -{ - struct skl_i2s_config_blob_ext *i2s_config_ext; - struct skl_i2s_config_blob_legacy *i2s_config; - struct skl_clk_parent_src *parent; - struct skl_ssp_clk *sclk, *sclkfs; - struct nhlt_fmt_cfg *fmt_cfg; - struct wav_fmt_ext *wav_fmt; - unsigned long rate; - int rate_index = 0; - u16 channels, bps; - u8 clk_src; - int i, j; - u32 fs; - - sclk = &ssp_clks[SKL_SCLK_OFS]; - sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; - - if (fmt->fmt_count == 0) - return; - - fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - for (i = 0; i < fmt->fmt_count; i++) { - struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg; - bool present = false; - - wav_fmt = &saved_fmt_cfg->fmt_ext; - - channels = wav_fmt->fmt.channels; - bps = wav_fmt->fmt.bits_per_sample; - fs = wav_fmt->fmt.samples_per_sec; - - /* - * In case of TDM configuration on a ssp, there can - * be more than one blob in which channel masks are - * different for each usecase for a specific rate and bps. - * But the sclk rate will be generated for the total - * number of channels used for that endpoint. - * - * So for the given fs and bps, choose blob which has - * the superset of all channels for that endpoint and - * derive the rate. - */ - for (j = i; j < fmt->fmt_count; j++) { - struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg; - - wav_fmt = &tmp_fmt_cfg->fmt_ext; - if ((fs == wav_fmt->fmt.samples_per_sec) && - (bps == wav_fmt->fmt.bits_per_sample)) { - channels = max_t(u16, channels, - wav_fmt->fmt.channels); - saved_fmt_cfg = tmp_fmt_cfg; - } - /* Move to the next nhlt_fmt_cfg */ - tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps + - tmp_fmt_cfg->config.size); - } - - rate = channels * bps * fs; - - /* check if the rate is added already to the given SSP's sclk */ - for (j = 0; (j < SKL_MAX_CLK_RATES) && - (sclk[id].rate_cfg[j].rate != 0); j++) { - if (sclk[id].rate_cfg[j].rate == rate) { - present = true; - break; - } - } - - /* Fill rate and parent for sclk/sclkfs */ - if (!present) { - struct nhlt_fmt_cfg *first_fmt_cfg; - - first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - i2s_config_ext = (struct skl_i2s_config_blob_ext *) - first_fmt_cfg->config.caps; - - /* MCLK Divider Source Select */ - if (is_legacy_blob(i2s_config_ext->hdr.sig)) { - i2s_config = ext_to_legacy_blob(i2s_config_ext); - clk_src = get_clk_src(i2s_config->mclk, - SKL_MNDSS_DIV_CLK_SRC_MASK); - } else { - clk_src = get_clk_src(i2s_config_ext->mclk, - SKL_MNDSS_DIV_CLK_SRC_MASK); - } - - parent = skl_get_parent_clk(clk_src); - - /* Move to the next nhlt_fmt_cfg */ - fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + - fmt_cfg->config.size); - /* - * Do not copy the config data if there is no parent - * clock available for this clock source select - */ - if (!parent) - continue; - - sclk[id].rate_cfg[rate_index].rate = rate; - sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg; - sclkfs[id].rate_cfg[rate_index].rate = rate; - sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg; - sclk[id].parent_name = parent->name; - sclkfs[id].parent_name = parent->name; - - rate_index++; - } - } -} - -static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, - struct nhlt_fmt *fmt, u8 id) -{ - struct skl_i2s_config_blob_ext *i2s_config_ext; - struct skl_i2s_config_blob_legacy *i2s_config; - struct nhlt_fmt_cfg *fmt_cfg; - struct skl_clk_parent_src *parent; - u32 clkdiv, div_ratio; - u8 clk_src; - - fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps; - - /* MCLK Divider Source Select and divider */ - if (is_legacy_blob(i2s_config_ext->hdr.sig)) { - i2s_config = ext_to_legacy_blob(i2s_config_ext); - clk_src = get_clk_src(i2s_config->mclk, - SKL_MCLK_DIV_CLK_SRC_MASK); - clkdiv = i2s_config->mclk.mdivr & - SKL_MCLK_DIV_RATIO_MASK; - } else { - clk_src = get_clk_src(i2s_config_ext->mclk, - SKL_MCLK_DIV_CLK_SRC_MASK); - clkdiv = i2s_config_ext->mclk.mdivr[0] & - SKL_MCLK_DIV_RATIO_MASK; - } - - /* bypass divider */ - div_ratio = 1; - - if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) - /* Divider is 2 + clkdiv */ - div_ratio = clkdiv + 2; - - /* Calculate MCLK rate from source using div value */ - parent = skl_get_parent_clk(clk_src); - if (!parent) - return; - - mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; - mclk[id].rate_cfg[0].config = fmt_cfg; - mclk[id].parent_name = parent->name; -} - -void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct nhlt_endpoint *epnt; - struct nhlt_fmt *fmt; - int i; - u8 id; - - epnt = (struct nhlt_endpoint *)nhlt->desc; - for (i = 0; i < nhlt->endpoint_count; i++) { - if (epnt->linktype == NHLT_LINK_SSP) { - id = epnt->virtual_bus_id; - - fmt = (struct nhlt_fmt *)(epnt->config.caps - + epnt->config.size); - - skl_get_ssp_clks(skl, ssp_clks, fmt, id); - skl_get_mclk(skl, ssp_clks, fmt, id); - } - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); - } -} diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c deleted file mode 100644 index 613b27b8da13..000000000000 --- a/sound/soc/intel/skylake/skl-pcm.c +++ /dev/null @@ -1,1507 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include "skl.h" -#include "skl-topology.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" - -#define HDA_MONO 1 -#define HDA_STEREO 2 -#define HDA_QUAD 4 -#define HDA_MAX 8 - -static const struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START | - SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ - SNDRV_PCM_INFO_HAS_LINK_ATIME | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = AZX_MAX_BUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = AZX_MAX_BUF_SIZE / 2, - .periods_min = 2, - .periods_max = AZX_MAX_FRAG, - .fifo_size = 0, -}; - -static inline -struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) -{ - return substream->runtime->private_data; -} - -static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_stream *hstream = hdac_stream(stream); - struct hdac_bus *bus = hstream->bus; - return bus; -} - -static int skl_substream_alloc_pages(struct hdac_bus *bus, - struct snd_pcm_substream *substream, - size_t size) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - - hdac_stream(stream)->bufsize = 0; - hdac_stream(stream)->period_bytes = 0; - hdac_stream(stream)->format_val = 0; - - return 0; -} - -static void skl_set_pcm_constrains(struct hdac_bus *bus, - struct snd_pcm_runtime *runtime) -{ - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - - /* avoid wrap-around with wall-clock */ - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, - 20, 178000000); -} - -static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus) -{ - if (bus->ppcap) - return HDAC_EXT_STREAM_TYPE_HOST; - else - return HDAC_EXT_STREAM_TYPE_COUPLED; -} - -/* - * check if the stream opened is marked as ignore_suspend by machine, if so - * then enable suspend_active refcount - * - * The count supend_active does not need lock as it is used in open/close - * and suspend context - */ -static void skl_set_suspend_active(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai, bool enable) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_soc_dapm_widget *w; - struct skl_dev *skl = bus_to_skl(bus); - - w = snd_soc_dai_get_widget(dai, substream->stream); - - if (w->ignore_suspend && enable) - skl->supend_active++; - else if (w->ignore_suspend && !enable) - skl->supend_active--; -} - -int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - unsigned int format_val; - struct hdac_stream *hstream; - struct hdac_ext_stream *stream; - unsigned int bits; - int err; - - hstream = snd_hdac_get_stream(bus, params->stream, - params->host_dma_id + 1); - if (!hstream) - return -EINVAL; - - stream = stream_to_hdac_ext_stream(hstream); - snd_hdac_ext_stream_decouple(bus, stream, true); - - bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, - params->host_bps); - format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); - - dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", - format_val, params->s_freq, params->ch, params->format); - - snd_hdac_stream_reset(hdac_stream(stream)); - err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); - if (err < 0) - return err; - - err = snd_hdac_ext_host_stream_setup(stream, false); - if (err < 0) - return err; - - hdac_stream(stream)->prepared = 1; - - return 0; -} - -int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - unsigned int format_val; - struct hdac_stream *hstream; - struct hdac_ext_stream *stream; - struct hdac_ext_link *link; - unsigned char stream_tag; - unsigned int bits; - - hstream = snd_hdac_get_stream(bus, params->stream, - params->link_dma_id + 1); - if (!hstream) - return -EINVAL; - - stream = stream_to_hdac_ext_stream(hstream); - snd_hdac_ext_stream_decouple(bus, stream, true); - - bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, - params->link_bps); - format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); - - dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", - format_val, params->s_freq, params->ch, params->format); - - snd_hdac_ext_stream_reset(stream); - - snd_hdac_ext_stream_setup(stream, format_val); - - stream_tag = hstream->stream_tag; - if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_bus_link_set_stream_id(link, - stream_tag); - } - } - - stream->link_prepared = 1; - - return 0; -} - -static int skl_pcm_open(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *stream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct skl_dma_params *dma_params; - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - stream = snd_hdac_ext_stream_assign(bus, substream, - skl_get_host_stream_type(bus)); - if (stream == NULL) - return -EBUSY; - - skl_set_pcm_constrains(bus, runtime); - - /* - * disable WALLCLOCK timestamps for capture streams - * until we figure out how to handle digital inputs - */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ - runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; - } - - runtime->private_data = stream; - - dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); - if (!dma_params) - return -ENOMEM; - - dma_params->stream_tag = hdac_stream(stream)->stream_tag; - snd_soc_dai_set_dma_data(dai, substream, dma_params); - - dev_dbg(dai->dev, "stream tag set in dma params=%d\n", - dma_params->stream_tag); - skl_set_suspend_active(substream, dai, true); - snd_pcm_set_sync(substream); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (!mconfig) { - kfree(dma_params); - return -EINVAL; - } - - skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); - - return 0; -} - -static int skl_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - int ret; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - - /* - * In case of XRUN recovery or in the case when the application - * calls prepare another time, reset the FW pipe to clean state - */ - if (mconfig && - (substream->runtime->state == SNDRV_PCM_STATE_XRUN || - mconfig->pipe->state == SKL_PIPE_CREATED || - mconfig->pipe->state == SKL_PIPE_PAUSED)) { - - ret = skl_reset_pipe(skl, mconfig->pipe); - - if (ret < 0) - return ret; - - ret = skl_pcm_host_dma_prepare(dai->dev, - mconfig->pipe->p_params); - if (ret < 0) - return ret; - } - - return 0; -} - -static int skl_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct skl_pipe_params p_params = {0}; - struct skl_module_cfg *m_cfg; - int ret, dma_id; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - ret = skl_substream_alloc_pages(bus, substream, - params_buffer_bytes(params)); - if (ret < 0) - return ret; - - dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - - dma_id = hdac_stream(stream)->stream_tag - 1; - dev_dbg(dai->dev, "dma_id=%d\n", dma_id); - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.host_dma_id = dma_id; - p_params.stream = substream->stream; - p_params.format = params_format(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - p_params.host_bps = dai->driver->playback.sig_bits; - else - p_params.host_bps = dai->driver->capture.sig_bits; - - - m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); - if (m_cfg) - skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); - - return 0; -} - -static void skl_pcm_close(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct skl_dma_params *dma_params = NULL; - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_cfg *mconfig; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus)); - - dma_params = snd_soc_dai_get_dma_data(dai, substream); - /* - * now we should set this to NULL as we are freeing by the - * dma_params - */ - snd_soc_dai_set_dma_data(dai, substream, NULL); - skl_set_suspend_active(substream, dai, false); - - /* - * check if close is for "Reference Pin" and set back the - * CGCTL.MISCBDCGE if disabled by driver - */ - if (!strncmp(dai->name, "Reference Pin", 13) && - skl->miscbdcg_disabled) { - skl->enable_miscbdcge(dai->dev, true); - skl->miscbdcg_disabled = false; - } - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (mconfig) - skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); - - kfree(dma_params); -} - -static int skl_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - int ret; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - - if (mconfig) { - ret = skl_reset_pipe(skl, mconfig->pipe); - if (ret < 0) - dev_err(dai->dev, "%s:Reset failed ret =%d", - __func__, ret); - } - - snd_hdac_stream_cleanup(hdac_stream(stream)); - hdac_stream(stream)->prepared = 0; - - return 0; -} - -static int skl_be_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct skl_pipe_params p_params = {0}; - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.stream = substream->stream; - - return skl_tplg_be_update_params(dai, &p_params); -} - -static int skl_decoupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream; - int start; - unsigned long cookie; - struct hdac_stream *hstr; - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = 1; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = 0; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - if (start) { - snd_hdac_stream_start(hdac_stream(stream)); - snd_hdac_stream_timecounter_init(hstr, 0); - } else { - snd_hdac_stream_stop(hdac_stream(stream)); - } - - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} - -static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_stream *hstream = hdac_stream(stream); - struct snd_soc_dapm_widget *w; - int ret; - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (!mconfig) - return -EIO; - - w = snd_soc_dai_get_widget(dai, substream->stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - if (!w->ignore_suspend) { - /* - * enable DMA Resume enable bit for the stream, set the - * dpib & lpib position to resume before starting the - * DMA - */ - snd_hdac_stream_drsm_enable(bus, true, hstream->index); - snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib); - snd_hdac_stream_set_lpib(hstream, hstream->lpib); - } - fallthrough; - - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /* - * Start HOST DMA and Start FE Pipe.This is to make sure that - * there are no underrun/overrun in the case when the FE - * pipeline is started but there is a delay in starting the - * DMA channel on the host. - */ - ret = skl_decoupled_trigger(substream, cmd); - if (ret < 0) - return ret; - return skl_run_pipe(skl, mconfig->pipe); - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - /* - * Stop FE Pipe first and stop DMA. This is to make sure that - * there are no underrun/overrun in the case if there is a delay - * between the two operations. - */ - ret = skl_stop_pipe(skl, mconfig->pipe); - if (ret < 0) - return ret; - - ret = skl_decoupled_trigger(substream, cmd); - if (ret < 0) - return ret; - - if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { - /* save the dpib and lpib positions */ - hstream->dpib = readl(bus->remap_addr + - AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hstream->index)); - - hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream); - - snd_hdac_ext_stream_decouple(bus, stream, false); - } - break; - - default: - return -EINVAL; - } - - return 0; -} - - -static int skl_link_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *link_dev; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_pipe_params p_params = {0}; - struct hdac_ext_link *link; - int stream_tag; - - link_dev = snd_hdac_ext_stream_assign(bus, substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!link_dev) - return -EBUSY; - - snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - - link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); - if (!link) - return -EINVAL; - - stream_tag = hdac_stream(link_dev)->stream_tag; - - /* set the hdac_stream in the codec dai */ - snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream); - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.stream = substream->stream; - p_params.link_dma_id = stream_tag - 1; - p_params.link_index = link->index; - p_params.format = params_format(params); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - p_params.link_bps = codec_dai->driver->playback.sig_bits; - else - p_params.link_bps = codec_dai->driver->capture.sig_bits; - - return skl_tplg_be_update_params(dai, &p_params); -} - -static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig = NULL; - - /* In case of XRUN recovery, reset the FW pipe to clean state */ - mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig && !mconfig->pipe->passthru && - (substream->runtime->state == SNDRV_PCM_STATE_XRUN)) - skl_reset_pipe(skl, mconfig->pipe); - - return 0; -} - -static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - - dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_start(link_dev); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - snd_hdac_ext_stream_clear(link_dev); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) - snd_hdac_ext_stream_decouple(bus, stream, false); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int skl_link_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - struct hdac_ext_link *link; - unsigned char stream_tag; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - link_dev->link_prepared = 0; - - link = snd_hdac_ext_bus_get_hlink_by_name(bus, snd_soc_rtd_to_codec(rtd, 0)->component->name); - if (!link) - return -EINVAL; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag); - } - - snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); - return 0; -} - -static const struct snd_soc_dai_ops skl_pcm_dai_ops = { - .startup = skl_pcm_open, - .shutdown = skl_pcm_close, - .prepare = skl_pcm_prepare, - .hw_params = skl_pcm_hw_params, - .hw_free = skl_pcm_hw_free, - .trigger = skl_pcm_trigger, -}; - -static const struct snd_soc_dai_ops skl_dmic_dai_ops = { - .hw_params = skl_be_hw_params, -}; - -static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = { - .hw_params = skl_be_hw_params, -}; - -static const struct snd_soc_dai_ops skl_link_dai_ops = { - .prepare = skl_link_pcm_prepare, - .hw_params = skl_link_hw_params, - .hw_free = skl_link_hw_free, - .trigger = skl_link_pcm_trigger, -}; - -static struct snd_soc_dai_driver skl_fe_dai[] = { -{ - .name = "System Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "System Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, - .capture = { - .stream_name = "System Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "System Pin2", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Headset Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Echoref Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "Echoreference Capture", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Reference Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "Reference Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "Deepbuffer Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Deepbuffer Playback", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "LowLatency Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Low Latency Playback", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "DMIC Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "DMIC Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI1 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI1 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI2 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI2 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI3 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI3 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -}; - -/* BE CPU Dais */ -static struct snd_soc_dai_driver skl_platform_dai[] = { -{ - .name = "SSP0 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp0 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp0 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP1 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp1 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp1 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP2 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp2 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp2 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP3 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp3 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp3 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP4 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp4 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp4 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP5 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp5 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp5 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "iDisp1 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp1 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "iDisp2 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp2 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| - SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "iDisp3 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp3 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| - SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "DMIC01 Pin", - .ops = &skl_dmic_dai_ops, - .capture = { - .stream_name = "DMIC01 Rx", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "DMIC16k Pin", - .ops = &skl_dmic_dai_ops, - .capture = { - .stream_name = "DMIC16k Rx", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "Analog CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Analog CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Analog CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Alt Analog CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Alt Analog CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Alt Analog CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Digital CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Digital CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Digital CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -}; - -int skl_dai_load(struct snd_soc_component *cmp, int index, - struct snd_soc_dai_driver *dai_drv, - struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) -{ - dai_drv->ops = &skl_pcm_dai_ops; - - return 0; -} - -static int skl_platform_soc_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link *dai_link = rtd->dai_link; - - dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "In %s:%s\n", __func__, - dai_link->cpus->dai_name); - - snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); - - return 0; -} - -static int skl_coupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream; - struct snd_pcm_substream *s; - bool start; - int sbits = 0; - unsigned long cookie; - struct hdac_stream *hstr; - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = true; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = false; - break; - - default: - return -EINVAL; - } - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - stream = get_hdac_ext_stream(s); - sbits |= 1 << hdac_stream(stream)->index; - snd_pcm_trigger_done(s, substream); - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - /* first, set SYNC bits of corresponding streams */ - snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - stream = get_hdac_ext_stream(s); - if (start) - snd_hdac_stream_start(hdac_stream(stream)); - else - snd_hdac_stream_stop(hdac_stream(stream)); - } - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - snd_hdac_stream_sync(hstr, start, sbits); - - spin_lock_irqsave(&bus->reg_lock, cookie); - - /* reset SYNC bits */ - snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); - if (start) - snd_hdac_stream_timecounter_init(hstr, sbits); - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} - -static int skl_platform_soc_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - - if (!bus->ppcap) - return skl_coupled_trigger(substream, cmd); - - return 0; -} - -static snd_pcm_uframes_t skl_platform_soc_pointer( - struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); - struct hdac_bus *bus = get_bus_ctx(substream); - unsigned int pos; - - /* - * Use DPIB for Playback stream as the periodic DMA Position-in- - * Buffer Writes may be scheduled at the same time or later than - * the MSI and does not guarantee to reflect the Position of the - * last buffer that was transferred. Whereas DPIB register in - * HAD space reflects the actual data that is transferred. - * Use the position buffer for capture, as DPIB write gets - * completed earlier than the actual data written to the DDR. - * - * For capture stream following workaround is required to fix the - * incorrect position reporting. - * - * 1. Wait for 20us before reading the DMA position in buffer once - * the interrupt is generated for stream completion as update happens - * on the HDA frame boundary i.e. 20.833uSec. - * 2. Read DPIB register to flush the DMA position value. This dummy - * read is required to flush DMA position value. - * 3. Read the DMA Position-in-Buffer. This value now will be equal to - * or greater than period boundary. - */ - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hdac_stream(hstream)->index)); - } else { - udelay(20); - readl(bus->remap_addr + - AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hdac_stream(hstream)->index)); - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); - } - - if (pos >= hdac_stream(hstream)->bufsize) - pos = 0; - - return bytes_to_frames(substream->runtime, pos); -} - -static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, - u64 nsec) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - u64 codec_frames, codec_nsecs; - - if (!codec_dai->driver->ops->delay) - return nsec; - - codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); - codec_nsecs = div_u64(codec_frames * 1000000000LL, - substream->runtime->rate); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - return nsec + codec_nsecs; - - return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; -} - -static int skl_platform_soc_get_time_info( - struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct timespec64 *system_ts, struct timespec64 *audio_ts, - struct snd_pcm_audio_tstamp_config *audio_tstamp_config, - struct snd_pcm_audio_tstamp_report *audio_tstamp_report) -{ - struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); - struct hdac_stream *hstr = hdac_stream(sstream); - u64 nsec; - - if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && - (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { - - snd_pcm_gettime(substream->runtime, system_ts); - - nsec = timecounter_read(&hstr->tc); - if (audio_tstamp_config->report_delay) - nsec = skl_adjust_codec_delay(substream, nsec); - - *audio_ts = ns_to_timespec64(nsec); - - audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; - audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ - audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ - - } else { - audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; - } - - return 0; -} - -#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) - -static int skl_platform_soc_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_pcm *pcm = rtd->pcm; - unsigned int size; - struct skl_dev *skl = bus_to_skl(bus); - - if (dai->driver->playback.channels_min || - dai->driver->capture.channels_min) { - /* buffer pre-allocation */ - size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; - if (size > MAX_PREALLOC_SIZE) - size = MAX_PREALLOC_SIZE; - snd_pcm_set_managed_buffer_all(pcm, - SNDRV_DMA_TYPE_DEV_SG, - &skl->pci->dev, - size, MAX_PREALLOC_SIZE); - } - - return 0; -} - -static int skl_get_module_info(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_module_inst_id *pin_id; - guid_t *uuid_mod, *uuid_tplg; - struct skl_module *skl_module; - struct uuid_module *module; - int i, ret = -EIO; - - uuid_mod = (guid_t *)mconfig->guid; - - if (list_empty(&skl->uuid_list)) { - dev_err(skl->dev, "Module list is empty\n"); - return -EIO; - } - - for (i = 0; i < skl->nr_modules; i++) { - skl_module = skl->modules[i]; - uuid_tplg = &skl_module->uuid; - if (guid_equal(uuid_mod, uuid_tplg)) { - mconfig->module = skl_module; - ret = 0; - break; - } - } - - if (skl->nr_modules && ret) - return ret; - - ret = -EIO; - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - mconfig->id.module_id = module->id; - mconfig->module->loadable = module->is_loadable; - ret = 0; - } - - for (i = 0; i < MAX_IN_QUEUE; i++) { - pin_id = &mconfig->m_in_pin[i].id; - if (guid_equal(&pin_id->mod_uuid, &module->uuid)) - pin_id->module_id = module->id; - } - - for (i = 0; i < MAX_OUT_QUEUE; i++) { - pin_id = &mconfig->m_out_pin[i].id; - if (guid_equal(&pin_id->mod_uuid, &module->uuid)) - pin_id->module_id = module->id; - } - } - - return ret; -} - -static int skl_populate_modules(struct skl_dev *skl) -{ - struct skl_pipeline *p; - struct skl_pipe_module *m; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - int ret = 0; - - list_for_each_entry(p, &skl->ppl_list, node) { - list_for_each_entry(m, &p->pipe->w_list, node) { - w = m->w; - mconfig = w->priv; - - ret = skl_get_module_info(skl, mconfig); - if (ret < 0) { - dev_err(skl->dev, - "query module info failed\n"); - return ret; - } - - skl_tplg_add_moduleid_in_bind_params(skl, w); - } - } - - return ret; -} - -static int skl_platform_soc_probe(struct snd_soc_component *component) -{ - struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl_dev *skl = bus_to_skl(bus); - const struct skl_dsp_ops *ops; - int ret; - - ret = pm_runtime_resume_and_get(component->dev); - if (ret < 0 && ret != -EACCES) - return ret; - - if (bus->ppcap) { - skl->component = component; - - /* init debugfs */ - skl->debugfs = skl_debugfs_init(skl); - - ret = skl_tplg_init(component, bus); - if (ret < 0) { - dev_err(component->dev, "Failed to init topology!\n"); - return ret; - } - - /* load the firmwares, since all is set */ - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) - return -EIO; - - /* - * Disable dynamic clock and power gating during firmware - * and library download - */ - skl->enable_miscbdcge(component->dev, false); - skl->clock_power_gating(component->dev, false); - - ret = ops->init_fw(component->dev, skl); - skl->enable_miscbdcge(component->dev, true); - skl->clock_power_gating(component->dev, true); - if (ret < 0) { - dev_err(component->dev, "Failed to boot first fw: %d\n", ret); - return ret; - } - skl_populate_modules(skl); - skl->update_d0i3c = skl_update_d0i3c; - - if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl, - skl->cfg.astate_cfg->count, - skl->cfg.astate_cfg); - } - } - pm_runtime_mark_last_busy(component->dev); - pm_runtime_put_autosuspend(component->dev); - - return 0; -} - -static void skl_platform_soc_remove(struct snd_soc_component *component) -{ - struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl_dev *skl = bus_to_skl(bus); - - skl_tplg_exit(component, bus); - - skl_debugfs_exit(skl); -} - -static const struct snd_soc_component_driver skl_component = { - .name = "pcm", - .probe = skl_platform_soc_probe, - .remove = skl_platform_soc_remove, - .open = skl_platform_soc_open, - .trigger = skl_platform_soc_trigger, - .pointer = skl_platform_soc_pointer, - .get_time_info = skl_platform_soc_get_time_info, - .pcm_construct = skl_platform_soc_new, - .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ -}; - -int skl_platform_register(struct device *dev) -{ - int ret; - struct snd_soc_dai_driver *dais; - int num_dais = ARRAY_SIZE(skl_platform_dai); - struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl_dev *skl = bus_to_skl(bus); - - skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), - GFP_KERNEL); - if (!skl->dais) { - ret = -ENOMEM; - goto err; - } - - if (!skl->use_tplg_pcm) { - dais = krealloc(skl->dais, sizeof(skl_fe_dai) + - sizeof(skl_platform_dai), GFP_KERNEL); - if (!dais) { - kfree(skl->dais); - ret = -ENOMEM; - goto err; - } - - skl->dais = dais; - memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai, - sizeof(skl_fe_dai)); - num_dais += ARRAY_SIZE(skl_fe_dai); - } - - ret = devm_snd_soc_register_component(dev, &skl_component, - skl->dais, num_dais); - if (ret) { - kfree(skl->dais); - dev_err(dev, "soc component registration failed %d\n", ret); - } -err: - return ret; -} - -int skl_platform_unregister(struct device *dev) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_deferred_bind *modules, *tmp; - - list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { - list_del(&modules->node); - kfree(modules); - } - - kfree(skl->dais); - - return 0; -} diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c deleted file mode 100644 index 50e93c3707e8..000000000000 --- a/sound/soc/intel/skylake/skl-ssp-clk.c +++ /dev/null @@ -1,428 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2015-17 Intel Corporation - -/* - * skl-ssp-clk.c - ASoC skylake ssp clock driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include "skl.h" -#include "skl-ssp-clk.h" -#include "skl-topology.h" - -#define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw) - -struct skl_clk_parent { - struct clk_hw *hw; - struct clk_lookup *lookup; -}; - -struct skl_clk { - struct clk_hw hw; - struct clk_lookup *lookup; - unsigned long rate; - struct skl_clk_pdata *pdata; - u32 id; -}; - -struct skl_clk_data { - struct skl_clk_parent parent[SKL_MAX_CLK_SRC]; - struct skl_clk *clk[SKL_MAX_CLK_CNT]; - u8 avail_clk_cnt; -}; - -static int skl_get_clk_type(u32 index) -{ - switch (index) { - case 0 ... (SKL_SCLK_OFS - 1): - return SKL_MCLK; - - case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1): - return SKL_SCLK; - - case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1): - return SKL_SCLK_FS; - - default: - return -EINVAL; - } -} - -static int skl_get_vbus_id(u32 index, u8 clk_type) -{ - switch (clk_type) { - case SKL_MCLK: - return index; - - case SKL_SCLK: - return index - SKL_SCLK_OFS; - - case SKL_SCLK_FS: - return index - SKL_SCLKFS_OFS; - - default: - return -EINVAL; - } -} - -static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type) -{ - struct nhlt_fmt_cfg *fmt_cfg; - union skl_clk_ctrl_ipc *ipc; - struct wav_fmt *wfmt; - - if (!rcfg) - return; - - ipc = &rcfg->dma_ctl_ipc; - if (clk_type == SKL_SCLK_FS) { - fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config; - wfmt = &fmt_cfg->fmt_ext.fmt; - - /* Remove TLV Header size */ - ipc->sclk_fs.hdr.size = sizeof(struct skl_dmactrl_sclkfs_cfg) - - sizeof(struct skl_tlv_hdr); - ipc->sclk_fs.sampling_frequency = wfmt->samples_per_sec; - ipc->sclk_fs.bit_depth = wfmt->bits_per_sample; - ipc->sclk_fs.valid_bit_depth = - fmt_cfg->fmt_ext.sample.valid_bits_per_sample; - ipc->sclk_fs.number_of_channels = wfmt->channels; - } else { - ipc->mclk.hdr.type = DMA_CLK_CONTROLS; - /* Remove TLV Header size */ - ipc->mclk.hdr.size = sizeof(struct skl_dmactrl_mclk_cfg) - - sizeof(struct skl_tlv_hdr); - } -} - -/* Sends dma control IPC to turn the clock ON/OFF */ -static int skl_send_clk_dma_control(struct skl_dev *skl, - struct skl_clk_rate_cfg_table *rcfg, - u32 vbus_id, u8 clk_type, - bool enable) -{ - struct nhlt_specific_cfg *sp_cfg; - u32 i2s_config_size, node_id = 0; - struct nhlt_fmt_cfg *fmt_cfg; - union skl_clk_ctrl_ipc *ipc; - void *i2s_config = NULL; - u8 *data, size; - int ret; - - if (!rcfg) - return -EIO; - - ipc = &rcfg->dma_ctl_ipc; - fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config; - sp_cfg = &fmt_cfg->config; - - if (clk_type == SKL_SCLK_FS) { - ipc->sclk_fs.hdr.type = - enable ? DMA_TRANSMITION_START : DMA_TRANSMITION_STOP; - data = (u8 *)&ipc->sclk_fs; - size = sizeof(struct skl_dmactrl_sclkfs_cfg); - } else { - /* 1 to enable mclk, 0 to enable sclk */ - if (clk_type == SKL_SCLK) - ipc->mclk.mclk = 0; - else - ipc->mclk.mclk = 1; - - ipc->mclk.keep_running = enable; - ipc->mclk.warm_up_over = enable; - ipc->mclk.clk_stop_over = !enable; - data = (u8 *)&ipc->mclk; - size = sizeof(struct skl_dmactrl_mclk_cfg); - } - - i2s_config_size = sp_cfg->size + size; - i2s_config = kzalloc(i2s_config_size, GFP_KERNEL); - if (!i2s_config) - return -ENOMEM; - - /* copy blob */ - memcpy(i2s_config, sp_cfg->caps, sp_cfg->size); - - /* copy additional dma controls information */ - memcpy(i2s_config + sp_cfg->size, data, size); - - node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4)); - ret = skl_dsp_set_dma_control(skl, (u32 *)i2s_config, - i2s_config_size, node_id); - kfree(i2s_config); - - return ret; -} - -static struct skl_clk_rate_cfg_table *skl_get_rate_cfg( - struct skl_clk_rate_cfg_table *rcfg, - unsigned long rate) -{ - int i; - - for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) { - if (rcfg[i].rate == rate) - return &rcfg[i]; - } - - return NULL; -} - -static int skl_clk_change_status(struct skl_clk *clkdev, - bool enable) -{ - struct skl_clk_rate_cfg_table *rcfg; - int vbus_id, clk_type; - - clk_type = skl_get_clk_type(clkdev->id); - if (clk_type < 0) - return clk_type; - - vbus_id = skl_get_vbus_id(clkdev->id, clk_type); - if (vbus_id < 0) - return vbus_id; - - rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, - clkdev->rate); - if (!rcfg) - return -EINVAL; - - return skl_send_clk_dma_control(clkdev->pdata->pvt_data, rcfg, - vbus_id, clk_type, enable); -} - -static int skl_clk_prepare(struct clk_hw *hw) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - return skl_clk_change_status(clkdev, true); -} - -static void skl_clk_unprepare(struct clk_hw *hw) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - skl_clk_change_status(clkdev, false); -} - -static int skl_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - struct skl_clk_rate_cfg_table *rcfg; - int clk_type; - - if (!rate) - return -EINVAL; - - rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, - rate); - if (!rcfg) - return -EINVAL; - - clk_type = skl_get_clk_type(clkdev->id); - if (clk_type < 0) - return clk_type; - - skl_fill_clk_ipc(rcfg, clk_type); - clkdev->rate = rate; - - return 0; -} - -static unsigned long skl_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - if (clkdev->rate) - return clkdev->rate; - - return 0; -} - -/* Not supported by clk driver. Implemented to satisfy clk fw */ -static long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - return rate; -} - -/* - * prepare/unprepare are used instead of enable/disable as IPC will be sent - * in non-atomic context. - */ -static const struct clk_ops skl_clk_ops = { - .prepare = skl_clk_prepare, - .unprepare = skl_clk_unprepare, - .set_rate = skl_clk_set_rate, - .round_rate = skl_clk_round_rate, - .recalc_rate = skl_clk_recalc_rate, -}; - -static void unregister_parent_src_clk(struct skl_clk_parent *pclk, - unsigned int id) -{ - while (id--) { - clkdev_drop(pclk[id].lookup); - clk_hw_unregister_fixed_rate(pclk[id].hw); - } -} - -static void unregister_src_clk(struct skl_clk_data *dclk) -{ - while (dclk->avail_clk_cnt--) - clkdev_drop(dclk->clk[dclk->avail_clk_cnt]->lookup); -} - -static int skl_register_parent_clks(struct device *dev, - struct skl_clk_parent *parent, - struct skl_clk_parent_src *pclk) -{ - int i, ret; - - for (i = 0; i < SKL_MAX_CLK_SRC; i++) { - - /* Register Parent clock */ - parent[i].hw = clk_hw_register_fixed_rate(dev, pclk[i].name, - pclk[i].parent_name, 0, pclk[i].rate); - if (IS_ERR(parent[i].hw)) { - ret = PTR_ERR(parent[i].hw); - goto err; - } - - parent[i].lookup = clkdev_hw_create(parent[i].hw, pclk[i].name, - NULL); - if (!parent[i].lookup) { - clk_hw_unregister_fixed_rate(parent[i].hw); - ret = -ENOMEM; - goto err; - } - } - - return 0; -err: - unregister_parent_src_clk(parent, i); - return ret; -} - -/* Assign fmt_config to clk_data */ -static struct skl_clk *register_skl_clk(struct device *dev, - struct skl_ssp_clk *clk, - struct skl_clk_pdata *clk_pdata, int id) -{ - struct clk_init_data init; - struct skl_clk *clkdev; - int ret; - - clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL); - if (!clkdev) - return ERR_PTR(-ENOMEM); - - init.name = clk->name; - init.ops = &skl_clk_ops; - init.flags = CLK_SET_RATE_GATE; - init.parent_names = &clk->parent_name; - init.num_parents = 1; - clkdev->hw.init = &init; - clkdev->pdata = clk_pdata; - - clkdev->id = id; - ret = devm_clk_hw_register(dev, &clkdev->hw); - if (ret) { - clkdev = ERR_PTR(ret); - return clkdev; - } - - clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL); - if (!clkdev->lookup) - clkdev = ERR_PTR(-ENOMEM); - - return clkdev; -} - -static int skl_clk_dev_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device *parent_dev = dev->parent; - struct skl_clk_parent_src *parent_clks; - struct skl_clk_pdata *clk_pdata; - struct skl_clk_data *data; - struct skl_ssp_clk *clks; - int ret, i; - - clk_pdata = dev_get_platdata(&pdev->dev); - parent_clks = clk_pdata->parent_clks; - clks = clk_pdata->ssp_clks; - if (!parent_clks || !clks) - return -EIO; - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* Register Parent clock */ - ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks); - if (ret < 0) - return ret; - - for (i = 0; i < clk_pdata->num_clks; i++) { - /* - * Only register valid clocks - * i.e. for which nhlt entry is present. - */ - if (clks[i].rate_cfg[0].rate == 0) - continue; - - data->clk[data->avail_clk_cnt] = register_skl_clk(dev, - &clks[i], clk_pdata, i); - - if (IS_ERR(data->clk[data->avail_clk_cnt])) { - ret = PTR_ERR(data->clk[data->avail_clk_cnt]); - goto err_unreg_skl_clk; - } - - data->avail_clk_cnt++; - } - - platform_set_drvdata(pdev, data); - - return 0; - -err_unreg_skl_clk: - unregister_src_clk(data); - unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); - - return ret; -} - -static void skl_clk_dev_remove(struct platform_device *pdev) -{ - struct skl_clk_data *data; - - data = platform_get_drvdata(pdev); - unregister_src_clk(data); - unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); -} - -static struct platform_driver skl_clk_driver = { - .driver = { - .name = "skl-ssp-clk", - }, - .probe = skl_clk_dev_probe, - .remove_new = skl_clk_dev_remove, -}; - -module_platform_driver(skl_clk_driver); - -MODULE_DESCRIPTION("Skylake clock driver"); -MODULE_AUTHOR("Jaikrishna Nemallapudi "); -MODULE_AUTHOR("Subhransu S. Prusty "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl-ssp-clk"); diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h deleted file mode 100644 index b7852c7f277b..000000000000 --- a/sound/soc/intel/skylake/skl-ssp-clk.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl-ssp-clk.h - Skylake ssp clock information and ipc structure - * - * Copyright (C) 2017 Intel Corp - * Author: Jaikrishna Nemallapudi - * Author: Subhransu S. Prusty - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef SOUND_SOC_SKL_SSP_CLK_H -#define SOUND_SOC_SKL_SSP_CLK_H - -#define SKL_MAX_SSP 6 -/* xtal/cardinal/pll, parent of ssp clocks and mclk */ -#define SKL_MAX_CLK_SRC 3 -#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */ - -#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES) - -/* Max number of configurations supported for each clock */ -#define SKL_MAX_CLK_RATES 10 - -#define SKL_SCLK_OFS SKL_MAX_SSP -#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP) - -enum skl_clk_type { - SKL_MCLK, - SKL_SCLK, - SKL_SCLK_FS, -}; - -enum skl_clk_src_type { - SKL_XTAL, - SKL_CARDINAL, - SKL_PLL, -}; - -struct skl_clk_parent_src { - u8 clk_id; - const char *name; - unsigned long rate; - const char *parent_name; -}; - -struct skl_tlv_hdr { - u32 type; - u32 size; -}; - -struct skl_dmactrl_mclk_cfg { - struct skl_tlv_hdr hdr; - /* DMA Clk TLV params */ - u32 clk_warm_up:16; - u32 mclk:1; - u32 warm_up_over:1; - u32 rsvd0:14; - u32 clk_stop_delay:16; - u32 keep_running:1; - u32 clk_stop_over:1; - u32 rsvd1:14; -}; - -struct skl_dmactrl_sclkfs_cfg { - struct skl_tlv_hdr hdr; - /* DMA SClk&FS TLV params */ - u32 sampling_frequency; - u32 bit_depth; - u32 channel_map; - u32 channel_config; - u32 interleaving_style; - u32 number_of_channels : 8; - u32 valid_bit_depth : 8; - u32 sample_type : 8; - u32 reserved : 8; -}; - -union skl_clk_ctrl_ipc { - struct skl_dmactrl_mclk_cfg mclk; - struct skl_dmactrl_sclkfs_cfg sclk_fs; -}; - -struct skl_clk_rate_cfg_table { - unsigned long rate; - union skl_clk_ctrl_ipc dma_ctl_ipc; - void *config; -}; - -/* - * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store - * all possible clocks ssp can generate for that platform. - */ -struct skl_ssp_clk { - const char *name; - const char *parent_name; - struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES]; -}; - -struct skl_clk_pdata { - struct skl_clk_parent_src *parent_clks; - int num_clks; - struct skl_ssp_clk *ssp_clks; - void *pvt_data; -}; - -#endif /* SOUND_SOC_SKL_SSP_CLK_H */ diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c deleted file mode 100644 index b0204ea00f07..000000000000 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-cldma.c - Code Loader DMA handler - * - * Copyright (C) 2015, Intel Corporation. - * Author: Subhransu S. Prusty - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -static void skl_cldma_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); -} - -void skl_cldma_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); -} - -static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable) -{ - unsigned char val; - int timeout; - - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable)); - - udelay(3); - timeout = 300; - do { - /* waiting for hardware to report that the stream Run bit set */ - val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) & - CL_SD_CTL_RUN_MASK; - if (enable && val) - break; - else if (!enable && !val) - break; - udelay(3); - } while (--timeout); - - if (timeout == 0) - dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable); -} - -static void skl_cldma_stream_clear(struct sst_dsp *ctx) -{ - /* make sure Run bit is cleared before setting stream register */ - skl_cldma_stream_run(ctx, 0); - - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); -} - -/* Code loader helper APIs */ -static void skl_cldma_setup_bdle(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp, int size, int with_ioc) -{ - __le32 *bdl = *bdlp; - int remaining = ctx->cl_dev.bufsize; - int offset = 0; - - ctx->cl_dev.frags = 0; - while (remaining > 0) { - phys_addr_t addr; - int chunk; - - addr = snd_sgbuf_get_addr(dmab_data, offset); - bdl[0] = cpu_to_le32(lower_32_bits(addr)); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size); - bdl[2] = cpu_to_le32(chunk); - - remaining -= chunk; - bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01); - - bdl += 4; - offset += chunk; - ctx->cl_dev.frags++; - } -} - -/* - * Setup controller - * Configure the registers to update the dma buffer address and - * enable interrupts. - * Note: Using the channel 1 for transfer - */ -static void skl_cldma_setup_controller(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_bdl, unsigned int max_size, - u32 count) -{ - skl_cldma_stream_clear(ctx); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, - CL_SD_BDLPLBA(dmab_bdl->addr)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, - CL_SD_BDLPUBA(dmab_bdl->addr)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); -} - -static void skl_cldma_setup_spb(struct sst_dsp *ctx, - unsigned int size, bool enable) -{ - if (enable) - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - CL_SPBFIFO_SPBFCCTL_SPIBE(1)); - - sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); -} - -static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - CL_SPBFIFO_SPBFCCTL_SPIBE(0)); - - sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); -} - -static void skl_cldma_cleanup(struct sst_dsp *ctx) -{ - skl_cldma_cleanup_spb(ctx); - skl_cldma_stream_clear(ctx); - - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); -} - -int skl_cldma_wait_interruptible(struct sst_dsp *ctx) -{ - int ret = 0; - - if (!wait_event_timeout(ctx->cl_dev.wait_queue, - ctx->cl_dev.wait_condition, - msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { - dev_err(ctx->dev, "%s: Wait timeout\n", __func__); - ret = -EIO; - goto cleanup; - } - - dev_dbg(ctx->dev, "%s: Event wake\n", __func__); - if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { - dev_err(ctx->dev, "%s: DMA Error\n", __func__); - ret = -EIO; - } - -cleanup: - ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; - return ret; -} - -static void skl_cldma_stop(struct sst_dsp *ctx) -{ - skl_cldma_stream_run(ctx, false); -} - -static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, - const void *curr_pos, bool intr_enable, bool trigger) -{ - dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); - dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", - ctx->cl_dev.dma_buffer_offset, trigger); - dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); - - /* - * Check if the size exceeds buffer boundary. If it exceeds - * max_buffer size, then copy till buffer size and then copy - * remaining buffer from the start of ring buffer. - */ - if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) { - unsigned int size_b = ctx->cl_dev.bufsize - - ctx->cl_dev.dma_buffer_offset; - memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, - curr_pos, size_b); - size -= size_b; - curr_pos += size_b; - ctx->cl_dev.dma_buffer_offset = 0; - } - - memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, - curr_pos, size); - - if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) - ctx->cl_dev.dma_buffer_offset = 0; - else - ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; - - ctx->cl_dev.wait_condition = false; - - if (intr_enable) - skl_cldma_int_enable(ctx); - - ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); - if (trigger) - ctx->cl_dev.ops.cl_trigger(ctx, true); -} - -/* - * The CL dma doesn't have any way to update the transfer status until a BDL - * buffer is fully transferred - * - * So Copying is divided in two parts. - * 1. Interrupt on buffer done where the size to be transferred is more than - * ring buffer size. - * 2. Polling on fw register to identify if data left to transferred doesn't - * fill the ring buffer. Caller takes care of polling the required status - * register to identify the transfer status. - * 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till - * bytes_left is 0. - * if wait flag is not set, doesn't wait for BDL interrupt. after ccopying - * the first chunk return the no of bytes_left to be copied. - */ -static int -skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, - u32 total_size, bool wait) -{ - int ret; - bool start = true; - unsigned int excess_bytes; - u32 size; - unsigned int bytes_left = total_size; - const void *curr_pos = bin; - - if (total_size <= 0) - return -EINVAL; - - dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); - - while (bytes_left) { - if (bytes_left > ctx->cl_dev.bufsize) { - - /* - * dma transfers only till the write pointer as - * updated in spib - */ - if (ctx->cl_dev.curr_spib_pos == 0) - ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; - - size = ctx->cl_dev.bufsize; - skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); - - if (wait) { - start = false; - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) { - skl_cldma_stop(ctx); - return ret; - } - } - } else { - skl_cldma_int_disable(ctx); - - if ((ctx->cl_dev.curr_spib_pos + bytes_left) - <= ctx->cl_dev.bufsize) { - ctx->cl_dev.curr_spib_pos += bytes_left; - } else { - excess_bytes = bytes_left - - (ctx->cl_dev.bufsize - - ctx->cl_dev.curr_spib_pos); - ctx->cl_dev.curr_spib_pos = excess_bytes; - } - - size = bytes_left; - skl_cldma_fill_buffer(ctx, size, - curr_pos, false, start); - } - bytes_left -= size; - curr_pos = curr_pos + size; - if (!wait) - return bytes_left; - } - - return bytes_left; -} - -void skl_cldma_process_intr(struct sst_dsp *ctx) -{ - u8 cl_dma_intr_status; - - cl_dma_intr_status = - sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); - - if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) - ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; - else - ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; - - ctx->cl_dev.wait_condition = true; - wake_up(&ctx->cl_dev.wait_queue); -} - -int skl_cldma_prepare(struct sst_dsp *ctx) -{ - int ret; - __le32 *bdl; - - ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; - - /* Allocate cl ops */ - ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; - ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; - ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; - ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; - ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run; - ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; - ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; - ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; - - /* Allocate buffer*/ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize, - &ctx->cl_dev.dmab_data); - if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); - return ret; - } - - /* Setup Code loader BDL */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl); - if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret); - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); - return ret; - } - bdl = (__le32 *)ctx->cl_dev.dmab_bdl.area; - - /* Allocate BDLs */ - ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, - &bdl, ctx->cl_dev.bufsize, 1); - ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, - ctx->cl_dev.bufsize, ctx->cl_dev.frags); - - ctx->cl_dev.curr_spib_pos = 0; - ctx->cl_dev.dma_buffer_offset = 0; - init_waitqueue_head(&ctx->cl_dev.wait_queue); - - return ret; -} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h deleted file mode 100644 index d5e285a69baa..000000000000 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ /dev/null @@ -1,243 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Code Loader DMA support - * - * Copyright (C) 2015, Intel Corporation. - */ - -#ifndef SKL_SST_CLDMA_H_ -#define SKL_SST_CLDMA_H_ - -#define FW_CL_STREAM_NUMBER 0x1 - -#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 -#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) - -#define SKL_ADSPIC_CL_DMA 0x2 -#define SKL_ADSPIS_CL_DMA 0x2 -#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ -#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ - -/* Intel HD Audio Code Loader DMA Registers */ - -#define HDA_ADSP_LOADER_BASE 0x80 - -/* Stream Registers */ -#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) -#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) -#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) -#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) -#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) -#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) -#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) -#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) -#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) -#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) -#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) - -/* CL: Software Position Based FIFO Capability Registers */ -#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) -#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) -#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) -#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) -#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) - -/* CL: Stream Descriptor x Control */ - -/* Stream Reset */ -#define CL_SD_CTL_SRST_SHIFT 0 -#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) -#define CL_SD_CTL_SRST(x) \ - ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) - -/* Stream Run */ -#define CL_SD_CTL_RUN_SHIFT 1 -#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) -#define CL_SD_CTL_RUN(x) \ - ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) - -/* Interrupt On Completion Enable */ -#define CL_SD_CTL_IOCE_SHIFT 2 -#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) -#define CL_SD_CTL_IOCE(x) \ - ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) - -/* FIFO Error Interrupt Enable */ -#define CL_SD_CTL_FEIE_SHIFT 3 -#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) -#define CL_SD_CTL_FEIE(x) \ - ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) - -/* Descriptor Error Interrupt Enable */ -#define CL_SD_CTL_DEIE_SHIFT 4 -#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) -#define CL_SD_CTL_DEIE(x) \ - ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) - -/* FIFO Limit Change */ -#define CL_SD_CTL_FIFOLC_SHIFT 5 -#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) -#define CL_SD_CTL_FIFOLC(x) \ - ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) - -/* Stripe Control */ -#define CL_SD_CTL_STRIPE_SHIFT 16 -#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) -#define CL_SD_CTL_STRIPE(x) \ - ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) - -/* Traffic Priority */ -#define CL_SD_CTL_TP_SHIFT 18 -#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) -#define CL_SD_CTL_TP(x) \ - ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) - -/* Bidirectional Direction Control */ -#define CL_SD_CTL_DIR_SHIFT 19 -#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) -#define CL_SD_CTL_DIR(x) \ - ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) - -/* Stream Number */ -#define CL_SD_CTL_STRM_SHIFT 20 -#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) -#define CL_SD_CTL_STRM(x) \ - ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) - -/* CL: Stream Descriptor x Status */ - -/* Buffer Completion Interrupt Status */ -#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) - -/* FIFO Error */ -#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) - -/* Descriptor Error */ -#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) - -/* FIFO Ready */ -#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) - - -/* CL: Stream Descriptor x Last Valid Index */ -#define CL_SD_LVI_SHIFT 0 -#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) -#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) - -/* CL: Stream Descriptor x FIFO Eviction Watermark */ -#define CL_SD_FIFOW_SHIFT 0 -#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) -#define CL_SD_FIFOW(x) \ - ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) - -/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ - -/* Protect Bits */ -#define CL_SD_BDLPLBA_PROT_SHIFT 0 -#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) -#define CL_SD_BDLPLBA_PROT(x) \ - ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) - -/* Buffer Descriptor List Lower Base Address */ -#define CL_SD_BDLPLBA_SHIFT 7 -#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) -#define CL_SD_BDLPLBA(x) \ - ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) - -/* Buffer Descriptor List Upper Base Address */ -#define CL_SD_BDLPUBA_SHIFT 0 -#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) -#define CL_SD_BDLPUBA(x) \ - ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) - -/* - * Code Loader - Software Position Based FIFO - * Capability Registers x Software Position Based FIFO Header - */ - -/* Next Capability Pointer */ -#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 -#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) -#define CL_SPBFIFO_SPBFCH_PTR(x) \ - ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) - -/* Capability Identifier */ -#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 -#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) -#define CL_SPBFIFO_SPBFCH_ID(x) \ - ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) - -/* Capability Version */ -#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 -#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) -#define CL_SPBFIFO_SPBFCH_VER(x) \ - ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) - -/* Software Position in Buffer Enable */ -#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 -#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) -#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ - ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) - -/* SST IPC SKL defines */ -#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ -#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) - -enum skl_cl_dma_wake_states { - SKL_CL_DMA_STATUS_NONE = 0, - SKL_CL_DMA_BUF_COMPLETE, - SKL_CL_DMA_ERR, /* TODO: Expand the error states */ -}; - -struct sst_dsp; - -struct skl_cl_dev_ops { - void (*cl_setup_bdle)(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp, int size, int with_ioc); - void (*cl_setup_controller)(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_bdl, - unsigned int max_size, u32 page_count); - void (*cl_setup_spb)(struct sst_dsp *ctx, - unsigned int size, bool enable); - void (*cl_cleanup_spb)(struct sst_dsp *ctx); - void (*cl_trigger)(struct sst_dsp *ctx, bool enable); - void (*cl_cleanup_controller)(struct sst_dsp *ctx); - int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, - const void *bin, u32 size, bool wait); - void (*cl_stop_dma)(struct sst_dsp *ctx); -}; - -/** - * skl_cl_dev - holds information for code loader dma transfer - * - * @dmab_data: buffer pointer - * @dmab_bdl: buffer descriptor list - * @bufsize: ring buffer size - * @frags: Last valid buffer descriptor index in the BDL - * @curr_spib_pos: Current position in ring buffer - * @dma_buffer_offset: dma buffer offset - * @ops: operations supported on CL dma - * @wait_queue: wait queue to wake for wake event - * @wake_status: DMA wake status - * @wait_condition: condition to wait on wait queue - * @cl_dma_lock: for synchronized access to cldma - */ -struct skl_cl_dev { - struct snd_dma_buffer dmab_data; - struct snd_dma_buffer dmab_bdl; - - unsigned int bufsize; - unsigned int frags; - - unsigned int curr_spib_pos; - unsigned int dma_buffer_offset; - struct skl_cl_dev_ops ops; - - wait_queue_head_t wait_queue; - int wake_status; - bool wait_condition; -}; - -#endif /* SKL_SST_CLDMA_H_ */ diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c deleted file mode 100644 index 4ae3eae0d1fd..000000000000 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ /dev/null @@ -1,462 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-dsp.c - SKL SST library generic function - * - * Copyright (C) 2014-15, Intel Corporation. - * Author:Rafal Redzimski - * Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include - -#include "../common/sst-dsp.h" -#include "../common/sst-ipc.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -/* various timeout values */ -#define SKL_DSP_PU_TO 50 -#define SKL_DSP_PD_TO 50 -#define SKL_DSP_RESET_TO 50 - -void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) -{ - mutex_lock(&ctx->mutex); - ctx->sst_state = state; - mutex_unlock(&ctx->mutex); -} - -/* - * Initialize core power state and usage count. To be called after - * successful first boot. Hence core 0 will be running and other cores - * will be reset - */ -void skl_dsp_init_core_state(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - int i; - - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; - skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1; - - for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) { - skl->cores.state[i] = SKL_DSP_RESET; - skl->cores.usage_count[i] = 0; - } -} - -/* Get the mask for all enabled cores */ -unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask, en_cores_mask; - u32 val; - - core_mask = SKL_DSP_CORES_MASK(skl->cores.count); - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); - - /* Cores having CPA bit set */ - en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >> - SKL_ADSPCS_CPA_SHIFT; - - /* And cores having CRST bit cleared */ - en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >> - SKL_ADSPCS_CRST_SHIFT; - - /* And cores having CSTALL bit cleared */ - en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >> - SKL_ADSPCS_CSTALL_SHIFT; - en_cores_mask &= core_mask; - - dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask); - - return en_cores_mask; -} - -static int -skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask), - SKL_ADSPCS_CRST_MASK(core_mask)); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), - SKL_ADSPCS_CRST_MASK(core_mask), - SKL_DSP_RESET_TO, - "Set reset"); - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CRST_MASK(core_mask)) != - SKL_ADSPCS_CRST_MASK(core_mask)) { - dev_err(ctx->dev, "Set reset state failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_unset_reset_state( - struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - dev_dbg(ctx->dev, "In %s\n", __func__); - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), 0); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), - 0, - SKL_DSP_RESET_TO, - "Unset reset"); - - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CRST_MASK(core_mask)) != 0) { - dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -static bool -is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) -{ - int val; - bool is_enable; - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); - - is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) && - (val & SKL_ADSPCS_SPA_MASK(core_mask)) && - !(val & SKL_ADSPCS_CRST_MASK(core_mask)) && - !(val & SKL_ADSPCS_CSTALL_MASK(core_mask))); - - dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n", - is_enable, core_mask); - - return is_enable; -} - -static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* stall core */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CSTALL_MASK(core_mask), - SKL_ADSPCS_CSTALL_MASK(core_mask)); - - /* set reset state */ - return skl_dsp_core_set_reset_state(ctx, core_mask); -} - -int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* unset reset state */ - ret = skl_dsp_core_unset_reset_state(ctx, core_mask); - if (ret < 0) - return ret; - - /* run core */ - dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask); - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CSTALL_MASK(core_mask), 0); - - if (!is_skl_dsp_core_enable(ctx, core_mask)) { - skl_dsp_reset_core(ctx, core_mask); - dev_err(ctx->dev, "DSP start core failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_SPA_MASK(core_mask), - SKL_ADSPCS_SPA_MASK(core_mask)); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CPA_MASK(core_mask), - SKL_ADSPCS_CPA_MASK(core_mask), - SKL_DSP_PU_TO, - "Power up"); - - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CPA_MASK(core_mask)) != - SKL_ADSPCS_CPA_MASK(core_mask)) { - dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_SPA_MASK(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CPA_MASK(core_mask), - 0, - SKL_DSP_PD_TO, - "Power down"); -} - -int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* power up */ - ret = skl_dsp_core_power_up(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n", - core_mask); - return ret; - } - - return skl_dsp_start_core(ctx, core_mask); -} - -int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - ret = skl_dsp_reset_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n", - core_mask); - return ret; - } - - /* power down core*/ - ret = skl_dsp_core_power_down(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n", - core_mask, ret); - return ret; - } - - if (is_skl_dsp_core_enable(ctx, core_mask)) { - dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n", - core_mask, ret); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_boot(struct sst_dsp *ctx) -{ - int ret; - - if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) { - ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret); - return ret; - } - - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret); - return ret; - } - } else { - ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret); - return ret; - } - ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK); - } - - return ret; -} - -irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) -{ - struct sst_dsp *ctx = dev_id; - u32 val; - irqreturn_t result = IRQ_NONE; - - spin_lock(&ctx->spinlock); - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); - ctx->intr_status = val; - - if (val == 0xffffffff) { - spin_unlock(&ctx->spinlock); - return IRQ_NONE; - } - - if (val & SKL_ADSPIS_IPC) { - skl_ipc_int_disable(ctx); - result = IRQ_WAKE_THREAD; - } - - if (val & SKL_ADSPIS_CL_DMA) { - skl_cldma_int_disable(ctx); - result = IRQ_WAKE_THREAD; - } - - spin_unlock(&ctx->spinlock); - - return result; -} -/* - * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context - * within the dapm mutex. Hence no separate lock is used. - */ -int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - if (core_id >= skl->cores.count) { - dev_err(ctx->dev, "invalid core id: %d\n", core_id); - return -EINVAL; - } - - skl->cores.usage_count[core_id]++; - - if (skl->cores.state[core_id] == SKL_DSP_RESET) { - ret = ctx->fw_ops.set_state_D0(ctx, core_id); - if (ret < 0) { - dev_err(ctx->dev, "unable to get core%d\n", core_id); - goto out; - } - } - -out: - dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", - core_id, skl->cores.state[core_id], - skl->cores.usage_count[core_id]); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_dsp_get_core); - -int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - if (core_id >= skl->cores.count) { - dev_err(ctx->dev, "invalid core id: %d\n", core_id); - return -EINVAL; - } - - if ((--skl->cores.usage_count[core_id] == 0) && - (skl->cores.state[core_id] != SKL_DSP_RESET)) { - ret = ctx->fw_ops.set_state_D3(ctx, core_id); - if (ret < 0) { - dev_err(ctx->dev, "unable to put core %d: %d\n", - core_id, ret); - skl->cores.usage_count[core_id]++; - } - } - - dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", - core_id, skl->cores.state[core_id], - skl->cores.usage_count[core_id]); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_dsp_put_core); - -int skl_dsp_wake(struct sst_dsp *ctx) -{ - return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID); -} -EXPORT_SYMBOL_GPL(skl_dsp_wake); - -int skl_dsp_sleep(struct sst_dsp *ctx) -{ - return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID); -} -EXPORT_SYMBOL_GPL(skl_dsp_sleep); - -struct sst_dsp *skl_dsp_ctx_init(struct device *dev, - struct sst_dsp_device *sst_dev, int irq) -{ - int ret; - struct sst_dsp *sst; - - sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); - if (sst == NULL) - return NULL; - - spin_lock_init(&sst->spinlock); - mutex_init(&sst->mutex); - sst->dev = dev; - sst->sst_dev = sst_dev; - sst->irq = irq; - sst->ops = sst_dev->ops; - sst->thread_context = sst_dev->thread_context; - - /* Initialise SST Audio DSP */ - if (sst->ops->init) { - ret = sst->ops->init(sst); - if (ret < 0) - return NULL; - } - - return sst; -} - -int skl_dsp_acquire_irq(struct sst_dsp *sst) -{ - struct sst_dsp_device *sst_dev = sst->sst_dev; - int ret; - - /* Register the ISR */ - ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, - sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); - if (ret) - dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", - sst->irq); - - return ret; -} - -void skl_dsp_free(struct sst_dsp *dsp) -{ - skl_ipc_int_disable(dsp); - - free_irq(dsp->irq, dsp); - skl_ipc_op_int_disable(dsp); - skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); -} -EXPORT_SYMBOL_GPL(skl_dsp_free); - -bool is_skl_dsp_running(struct sst_dsp *ctx) -{ - return (ctx->sst_state == SKL_DSP_RUNNING); -} -EXPORT_SYMBOL_GPL(is_skl_dsp_running); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h deleted file mode 100644 index 1df9ef422f61..000000000000 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Skylake SST DSP Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ - -#ifndef __SKL_SST_DSP_H__ -#define __SKL_SST_DSP_H__ - -#include -#include -#include -#include -#include "skl-sst-cldma.h" - -struct sst_dsp; -struct sst_dsp_device; -struct skl_lib_info; -struct skl_dev; - -/* Intel HD Audio General DSP Registers */ -#define SKL_ADSP_GEN_BASE 0x0 -#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) -#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08) -#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C) -#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10) -#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14) - -/* Intel HD Audio Inter-Processor Communication Registers */ -#define SKL_ADSP_IPC_BASE 0x40 -#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00) -#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04) -#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08) -#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C) -#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10) - -/* HIPCI */ -#define SKL_ADSP_REG_HIPCI_BUSY BIT(31) - -/* HIPCIE */ -#define SKL_ADSP_REG_HIPCIE_DONE BIT(30) - -/* HIPCCTL */ -#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1) -#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0) - -/* HIPCT */ -#define SKL_ADSP_REG_HIPCT_BUSY BIT(31) - -/* FW base IDs */ -#define SKL_INSTANCE_ID 0 -#define SKL_BASE_FW_MODULE_ID 0 - -/* Intel HD Audio SRAM Window 1 */ -#define SKL_ADSP_SRAM1_BASE 0xA000 - -#define SKL_ADSP_MMIO_LEN 0x10000 - -#define SKL_ADSP_W0_STAT_SZ 0x1000 - -#define SKL_ADSP_W0_UP_SZ 0x1000 - -#define SKL_ADSP_W1_SZ 0x1000 - -#define SKL_FW_STS_MASK 0xf - -#define SKL_FW_INIT 0x1 -#define SKL_FW_RFW_START 0xf -#define BXT_FW_ROM_INIT_RETRY 3 -#define BXT_INIT_TIMEOUT 300 - -#define SKL_ADSPIC_IPC 1 -#define SKL_ADSPIS_IPC 1 - -/* Core ID of core0 */ -#define SKL_DSP_CORE0_ID 0 - -/* Mask for a given core index, c = 0.. number of supported cores - 1 */ -#define SKL_DSP_CORE_MASK(c) BIT(c) - -/* - * Core 0 mask = SKL_DSP_CORE_MASK(0); Defined separately - * since Core0 is primary core and it is used often - */ -#define SKL_DSP_CORE0_MASK BIT(0) - -/* - * Mask for a given number of cores - * nc = number of supported cores - */ -#define SKL_DSP_CORES_MASK(nc) GENMASK((nc - 1), 0) - -/* ADSPCS - Audio DSP Control & Status */ - -/* - * Core Reset - asserted high - * CRST Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CRST_SHIFT 0 -#define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT) - -/* - * Core run/stall - when set to '1' core is stalled - * CSTALL Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CSTALL_SHIFT 8 -#define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT) - -/* - * Set Power Active - when set to '1' turn cores on - * SPA Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_SPA_SHIFT 16 -#define SKL_ADSPCS_SPA_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT) - -/* - * Current Power Active - power status of cores, set by hardware - * CPA Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CPA_SHIFT 24 -#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) - -/* DSP Core state */ -enum skl_dsp_states { - SKL_DSP_RUNNING = 1, - /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ - SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/ - SKL_DSP_RESET, -}; - -/* D0i3 substates */ -enum skl_dsp_d0i3_states { - SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ - SKL_DSP_D0I3_NON_STREAMING = 0, - SKL_DSP_D0I3_STREAMING = 1, -}; - -struct skl_dsp_fw_ops { - int (*load_fw)(struct sst_dsp *ctx); - /* FW module parser/loader */ - int (*load_library)(struct sst_dsp *ctx, - struct skl_lib_info *linfo, int lib_count); - int (*parse_fw)(struct sst_dsp *ctx); - int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); - int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); - int (*set_state_D0i3)(struct sst_dsp *ctx); - int (*set_state_D0i0)(struct sst_dsp *ctx); - unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); - int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); - int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); - -}; - -struct skl_dsp_loader_ops { - int stream_tag; - - int (*alloc_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab, size_t size); - int (*free_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab); - int (*prepare)(struct device *dev, unsigned int format, - unsigned int byte_size, - struct snd_dma_buffer *bufp); - int (*trigger)(struct device *dev, bool start, int stream_tag); - - int (*cleanup)(struct device *dev, struct snd_dma_buffer *dmab, - int stream_tag); -}; - -#define MAX_INSTANCE_BUFF 2 - -struct uuid_module { - guid_t uuid; - int id; - int is_loadable; - int max_instance; - u64 pvt_id[MAX_INSTANCE_BUFF]; - int *instance_id; - - struct list_head list; -}; - -struct skl_load_module_info { - u16 mod_id; - const struct firmware *fw; -}; - -struct skl_module_table { - struct skl_load_module_info *mod_info; - unsigned int usage_cnt; - struct list_head list; -}; - -void skl_cldma_process_intr(struct sst_dsp *ctx); -void skl_cldma_int_disable(struct sst_dsp *ctx); -int skl_cldma_prepare(struct sst_dsp *ctx); -int skl_cldma_wait_interruptible(struct sst_dsp *ctx); - -void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); -struct sst_dsp *skl_dsp_ctx_init(struct device *dev, - struct sst_dsp_device *sst_dev, int irq); -int skl_dsp_acquire_irq(struct sst_dsp *sst); -bool is_skl_dsp_running(struct sst_dsp *ctx); - -unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx); -void skl_dsp_init_core_state(struct sst_dsp *ctx); -int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx, - unsigned int core_mask); -int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask); - -irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); -int skl_dsp_wake(struct sst_dsp *ctx); -int skl_dsp_sleep(struct sst_dsp *ctx); -void skl_dsp_free(struct sst_dsp *dsp); - -int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id); -int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id); - -int skl_dsp_boot(struct sst_dsp *ctx); -int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int skl_sst_init_fw(struct device *dev, struct skl_dev *skl); -int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); - -int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, - unsigned int offset, int index); -int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id); -int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id); -int skl_get_pvt_instance_id_map(struct skl_dev *skl, - int module_id, int instance_id); -void skl_freeup_uuid_list(struct skl_dev *skl); - -int skl_dsp_strip_extended_manifest(struct firmware *fw); - -void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data); - -int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, - struct sst_dsp_device *skl_dev); -int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, - struct firmware *stripped_fw, - unsigned int hdr_offset, int index); -void skl_release_library(struct skl_lib_info *linfo, int lib_count); - -#endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c deleted file mode 100644 index fd9624ad5f72..000000000000 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ /dev/null @@ -1,1071 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-ipc.c - Intel skl IPC Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ -#include - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "sound/hdaudio_ext.h" - - -#define IPC_IXC_STATUS_BITS 24 - -/* Global Message - Generic */ -#define IPC_GLB_TYPE_SHIFT 24 -#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) -#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) - -/* Global Message - Reply */ -#define IPC_GLB_REPLY_STATUS_SHIFT 24 -#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) -#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) - -#define IPC_GLB_REPLY_TYPE_SHIFT 29 -#define IPC_GLB_REPLY_TYPE_MASK 0x1F -#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \ - & IPC_GLB_RPLY_TYPE_MASK) - -#define IPC_TIMEOUT_MSECS 3000 - -#define IPC_EMPTY_LIST_SIZE 8 - -#define IPC_MSG_TARGET_SHIFT 30 -#define IPC_MSG_TARGET_MASK 0x1 -#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ - << IPC_MSG_TARGET_SHIFT) - -#define IPC_MSG_DIR_SHIFT 29 -#define IPC_MSG_DIR_MASK 0x1 -#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ - << IPC_MSG_DIR_SHIFT) -/* Global Notification Message */ -#define IPC_GLB_NOTIFY_TYPE_SHIFT 16 -#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF -#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ - & IPC_GLB_NOTIFY_TYPE_MASK) - -#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 -#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F -#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ - & IPC_GLB_NOTIFY_MSG_TYPE_MASK) - -#define IPC_GLB_NOTIFY_RSP_SHIFT 29 -#define IPC_GLB_NOTIFY_RSP_MASK 0x1 -#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ - & IPC_GLB_NOTIFY_RSP_MASK) - -/* Pipeline operations */ - -/* Create pipeline message */ -#define IPC_PPL_MEM_SIZE_SHIFT 0 -#define IPC_PPL_MEM_SIZE_MASK 0x7FF -#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ - << IPC_PPL_MEM_SIZE_SHIFT) - -#define IPC_PPL_TYPE_SHIFT 11 -#define IPC_PPL_TYPE_MASK 0x1F -#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ - << IPC_PPL_TYPE_SHIFT) - -#define IPC_INSTANCE_ID_SHIFT 16 -#define IPC_INSTANCE_ID_MASK 0xFF -#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ - << IPC_INSTANCE_ID_SHIFT) - -#define IPC_PPL_LP_MODE_SHIFT 0 -#define IPC_PPL_LP_MODE_MASK 0x1 -#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ - << IPC_PPL_LP_MODE_SHIFT) - -/* Set pipeline state message */ -#define IPC_PPL_STATE_SHIFT 0 -#define IPC_PPL_STATE_MASK 0x1F -#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ - << IPC_PPL_STATE_SHIFT) - -/* Module operations primary register */ -#define IPC_MOD_ID_SHIFT 0 -#define IPC_MOD_ID_MASK 0xFFFF -#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ - << IPC_MOD_ID_SHIFT) - -#define IPC_MOD_INSTANCE_ID_SHIFT 16 -#define IPC_MOD_INSTANCE_ID_MASK 0xFF -#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ - << IPC_MOD_INSTANCE_ID_SHIFT) - -/* Init instance message extension register */ -#define IPC_PARAM_BLOCK_SIZE_SHIFT 0 -#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF -#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ - << IPC_PARAM_BLOCK_SIZE_SHIFT) - -#define IPC_PPL_INSTANCE_ID_SHIFT 16 -#define IPC_PPL_INSTANCE_ID_MASK 0xFF -#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ - << IPC_PPL_INSTANCE_ID_SHIFT) - -#define IPC_CORE_ID_SHIFT 24 -#define IPC_CORE_ID_MASK 0x1F -#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ - << IPC_CORE_ID_SHIFT) - -#define IPC_DOMAIN_SHIFT 28 -#define IPC_DOMAIN_MASK 0x1 -#define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \ - << IPC_DOMAIN_SHIFT) - -/* Bind/Unbind message extension register */ -#define IPC_DST_MOD_ID_SHIFT 0 -#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ - << IPC_DST_MOD_ID_SHIFT) - -#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 -#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ - << IPC_DST_MOD_INSTANCE_ID_SHIFT) - -#define IPC_DST_QUEUE_SHIFT 24 -#define IPC_DST_QUEUE_MASK 0x7 -#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ - << IPC_DST_QUEUE_SHIFT) - -#define IPC_SRC_QUEUE_SHIFT 27 -#define IPC_SRC_QUEUE_MASK 0x7 -#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ - << IPC_SRC_QUEUE_SHIFT) -/* Load Module count */ -#define IPC_LOAD_MODULE_SHIFT 0 -#define IPC_LOAD_MODULE_MASK 0xFF -#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ - << IPC_LOAD_MODULE_SHIFT) - -/* Save pipeline messgae extension register */ -#define IPC_DMA_ID_SHIFT 0 -#define IPC_DMA_ID_MASK 0x1F -#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ - << IPC_DMA_ID_SHIFT) -/* Large Config message extension register */ -#define IPC_DATA_OFFSET_SZ_SHIFT 0 -#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF -#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ - << IPC_DATA_OFFSET_SZ_SHIFT) -#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ - << IPC_DATA_OFFSET_SZ_SHIFT) - -#define IPC_LARGE_PARAM_ID_SHIFT 20 -#define IPC_LARGE_PARAM_ID_MASK 0xFF -#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ - << IPC_LARGE_PARAM_ID_SHIFT) - -#define IPC_FINAL_BLOCK_SHIFT 28 -#define IPC_FINAL_BLOCK_MASK 0x1 -#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ - << IPC_FINAL_BLOCK_SHIFT) - -#define IPC_INITIAL_BLOCK_SHIFT 29 -#define IPC_INITIAL_BLOCK_MASK 0x1 -#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ - << IPC_INITIAL_BLOCK_SHIFT) -#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ - << IPC_INITIAL_BLOCK_SHIFT) -/* Set D0ix IPC extension register */ -#define IPC_D0IX_WAKE_SHIFT 0 -#define IPC_D0IX_WAKE_MASK 0x1 -#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ - << IPC_D0IX_WAKE_SHIFT) - -#define IPC_D0IX_STREAMING_SHIFT 1 -#define IPC_D0IX_STREAMING_MASK 0x1 -#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ - << IPC_D0IX_STREAMING_SHIFT) - - -enum skl_ipc_msg_target { - IPC_FW_GEN_MSG = 0, - IPC_MOD_MSG = 1 -}; - -enum skl_ipc_msg_direction { - IPC_MSG_REQUEST = 0, - IPC_MSG_REPLY = 1 -}; - -/* Global Message Types */ -enum skl_ipc_glb_type { - IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ - IPC_GLB_LOAD_MULTIPLE_MODS = 15, - IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, - IPC_GLB_CREATE_PPL = 17, - IPC_GLB_DELETE_PPL = 18, - IPC_GLB_SET_PPL_STATE = 19, - IPC_GLB_GET_PPL_STATE = 20, - IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, - IPC_GLB_SAVE_PPL = 22, - IPC_GLB_RESTORE_PPL = 23, - IPC_GLB_LOAD_LIBRARY = 24, - IPC_GLB_NOTIFY = 26, - IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ -}; - -enum skl_ipc_glb_reply { - IPC_GLB_REPLY_SUCCESS = 0, - - IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, - IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, - - IPC_GLB_REPLY_BUSY = 3, - IPC_GLB_REPLY_PENDING = 4, - IPC_GLB_REPLY_FAILURE = 5, - IPC_GLB_REPLY_INVALID_REQUEST = 6, - - IPC_GLB_REPLY_OUT_OF_MEMORY = 7, - IPC_GLB_REPLY_OUT_OF_MIPS = 8, - - IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, - IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, - - IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, - IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, - IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, - - IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, - IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, - - IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, - IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, - IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, - IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, - IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, - IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, - - IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, - IPC_GLB_REPLY_PPL_NOT_EXIST = 161, - IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, - IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, - - IPC_MAX_STATUS = ((1<tx.data, tx_data, tx_size); -} - -static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) -{ - u32 hipci; - - hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); - return (hipci & SKL_ADSP_REG_HIPCI_BUSY); -} - -/* Lock to be held by caller */ -static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) -{ - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - - if (msg->tx.size) - sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, - header->extension); - sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, - header->primary | SKL_ADSP_REG_HIPCI_BUSY); -} - -int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) -{ - int ret; - - /* check D0i3 support */ - if (!dsp->fw_ops.set_state_D0i0) - return 0; - - /* Attempt D0i0 or D0i3 based on state */ - if (state) - ret = dsp->fw_ops.set_state_D0i0(dsp); - else - ret = dsp->fw_ops.set_state_D0i3(dsp); - - return ret; -} - -static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, - u64 ipc_header) -{ - struct ipc_message *msg = NULL; - struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); - - if (list_empty(&ipc->rx_list)) { - dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", - header->primary); - goto out; - } - - msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); - - list_del(&msg->list); -out: - return msg; - -} - -int skl_ipc_process_notification(struct sst_generic_ipc *ipc, - struct skl_ipc_header header) -{ - struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); - - if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { - - case IPC_GLB_NOTIFY_UNDERRUN: - dev_err(ipc->dev, "FW Underrun %x\n", header.primary); - break; - - case IPC_GLB_NOTIFY_RESOURCE_EVENT: - dev_err(ipc->dev, "MCPS Budget Violation: %x\n", - header.primary); - break; - - case IPC_GLB_NOTIFY_FW_READY: - skl->boot_complete = true; - wake_up(&skl->boot_wait); - break; - - case IPC_GLB_NOTIFY_PHRASE_DETECTED: - dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); - - /* - * Per HW recomendation, After phrase detection, - * clear the CGCTL.MISCBDCGE. - * - * This will be set back on stream closure - */ - skl->enable_miscbdcge(ipc->dev, false); - skl->miscbdcg_disabled = true; - break; - - default: - dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n", - header.primary); - break; - } - } - - return 0; -} - -struct skl_ipc_err_map { - const char *msg; - enum skl_ipc_glb_reply reply; - int err; -}; - -static struct skl_ipc_err_map skl_err_map[] = { - {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, - {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, - {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, - IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, - {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, - IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, -}; - -static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { - if (skl_err_map[i].reply == reply) - break; - } - - if (i == ARRAY_SIZE(skl_err_map)) { - dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", - reply, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - return -EINVAL; - } - - if (skl_err_map[i].err < 0) - dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", - skl_err_map[i].msg, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - else - dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", - skl_err_map[i].msg, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - - return skl_err_map[i].err; -} - -void skl_ipc_process_reply(struct sst_generic_ipc *ipc, - struct skl_ipc_header header) -{ - struct ipc_message *msg; - u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; - u64 *ipc_header = (u64 *)(&header); - struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); - unsigned long flags; - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - msg = skl_ipc_reply_get_msg(ipc, *ipc_header); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - if (msg == NULL) { - dev_dbg(ipc->dev, "ipc: rx list is empty\n"); - return; - } - - msg->rx.header = *ipc_header; - /* first process the header */ - if (reply == IPC_GLB_REPLY_SUCCESS) { - dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); - /* copy the rx data from the mailbox */ - sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size); - switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - case IPC_GLB_LOAD_MULTIPLE_MODS: - case IPC_GLB_LOAD_LIBRARY: - skl->mod_load_complete = true; - skl->mod_load_status = true; - wake_up(&skl->mod_load_wait); - break; - - default: - break; - - } - } else { - msg->errno = skl_ipc_set_reply_error_code(ipc, reply); - switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - case IPC_GLB_LOAD_MULTIPLE_MODS: - case IPC_GLB_LOAD_LIBRARY: - skl->mod_load_complete = true; - skl->mod_load_status = false; - wake_up(&skl->mod_load_wait); - break; - - default: - break; - - } - } - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - sst_ipc_tx_msg_reply_complete(ipc, msg); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); -} - -irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) -{ - struct sst_dsp *dsp = context; - struct skl_dev *skl = dsp->thread_context; - struct sst_generic_ipc *ipc = &skl->ipc; - struct skl_ipc_header header = {0}; - u32 hipcie, hipct, hipcte; - int ipc_irq = 0; - - if (dsp->intr_status & SKL_ADSPIS_CL_DMA) - skl_cldma_process_intr(dsp); - - /* Here we handle IPC interrupts only */ - if (!(dsp->intr_status & SKL_ADSPIS_IPC)) - return IRQ_NONE; - - hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); - hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); - hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); - - /* reply message from DSP */ - if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { - sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* clear DONE bit - tell DSP we have completed the operation */ - sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); - - ipc_irq = 1; - - /* unmask Done interrupt */ - sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); - } - - /* New message from DSP */ - if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { - header.primary = hipct; - header.extension = hipcte; - dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n", - header.primary); - dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n", - header.extension); - - if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { - /* Handle Immediate reply from DSP Core */ - skl_ipc_process_reply(ipc, header); - } else { - dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); - skl_ipc_process_notification(ipc, header); - } - /* clear busy interrupt */ - sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, - SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); - ipc_irq = 1; - } - - if (ipc_irq == 0) - return IRQ_NONE; - - skl_ipc_int_enable(dsp); - - /* continue to send any remaining messages... */ - schedule_work(&ipc->kwork); - - return IRQ_HANDLED; -} - -void skl_ipc_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); -} - -void skl_ipc_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_IPC, 0); -} - -void skl_ipc_op_int_enable(struct sst_dsp *ctx) -{ - /* enable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); - - /* Enable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); -} - -void skl_ipc_op_int_disable(struct sst_dsp *ctx) -{ - /* disable IPC DONE interrupt */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* Disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, 0); - -} - -bool skl_ipc_int_status(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read_unlocked(ctx, - SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; -} - -int skl_ipc_init(struct device *dev, struct skl_dev *skl) -{ - struct sst_generic_ipc *ipc; - int err; - - ipc = &skl->ipc; - ipc->dsp = skl->dsp; - ipc->dev = dev; - - ipc->tx_data_max_size = SKL_ADSP_W1_SZ; - ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; - - err = sst_ipc_init(ipc); - if (err) - return err; - - ipc->ops.tx_msg = skl_ipc_tx_msg; - ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; - ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; - - return 0; -} - -void skl_ipc_free(struct sst_generic_ipc *ipc) -{ - /* Disable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* Disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, 0); - - sst_ipc_fini(ipc); -} - -int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - header.primary |= IPC_PPL_TYPE(ppl_type); - header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); - - header.extension = IPC_PPL_LP_MODE(lp_mode); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); - -int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); - -int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, - u8 instance_id, enum skl_ipc_pipeline_state state) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); - header.primary |= IPC_INSTANCE_ID(instance_id); - header.primary |= IPC_PPL_STATE(state); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); - return ret; - } - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); - -int -skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - - header.extension = IPC_DMA_ID(dma_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); - -int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); - -int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, - u16 module_id, struct skl_ipc_dxstate_info *dx) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); - header.primary |= IPC_MOD_INSTANCE_ID(instance_id); - header.primary |= IPC_MOD_ID(module_id); - - request.header = *(u64 *)(&header); - request.data = dx; - request.size = sizeof(*dx); - - dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, - header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_dx); - -int skl_ipc_init_instance(struct sst_generic_ipc *ipc, - struct skl_ipc_init_instance_msg *msg, void *param_data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - u32 *buffer = (u32 *)param_data; - /* param_block_size must be in dwords */ - u16 param_block_size = msg->param_data_size / sizeof(u32); - - print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE, - 16, 4, buffer, param_block_size, false); - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_CORE_ID(msg->core_id); - header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); - header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); - header.extension |= IPC_DOMAIN(msg->domain); - - request.header = *(u64 *)(&header); - request.data = param_data; - request.size = msg->param_data_size; - - dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, - header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - - if (ret < 0) { - dev_err(ipc->dev, "ipc: init instance failed\n"); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_init_instance); - -int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, - struct skl_ipc_bind_unbind_msg *msg) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(bind_unbind); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DST_MOD_ID(msg->dst_module_id); - header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); - header.extension |= IPC_DST_QUEUE(msg->dst_queue); - header.extension |= IPC_SRC_QUEUE(msg->src_queue); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, - header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: bind/unbind failed\n"); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); - -/* - * In order to load a module we need to send IPC to initiate that. DMA will - * performed to load the module memory. The FW supports multiple module load - * at single shot, so we can send IPC with N modules represented by - * module_cnt - */ -int skl_ipc_load_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); - header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - - request.header = *(u64 *)(&header); - request.data = data; - request.size = sizeof(u16) * module_cnt; - - ret = sst_ipc_tx_message_nowait(ipc, request); - if (ret < 0) - dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_load_modules); - -int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, - void *data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); - header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - - request.header = *(u64 *)(&header); - request.data = data; - request.size = sizeof(u16) * module_cnt; - - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) - dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); - -int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret = 0; - size_t sz_remaining, tx_size, data_offset; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); - header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); - header.extension |= IPC_FINAL_BLOCK(0); - header.extension |= IPC_INITIAL_BLOCK(1); - - sz_remaining = msg->param_data_size; - data_offset = 0; - while (sz_remaining != 0) { - tx_size = sz_remaining > SKL_ADSP_W1_SZ - ? SKL_ADSP_W1_SZ : sz_remaining; - if (tx_size == sz_remaining) - header.extension |= IPC_FINAL_BLOCK(1); - - dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, - header.primary, header.extension); - dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", - (unsigned)data_offset, (unsigned)tx_size); - - request.header = *(u64 *)(&header); - request.data = ((char *)param) + data_offset; - request.size = tx_size; - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, - "ipc: set large config fail, err: %d\n", ret); - return ret; - } - sz_remaining -= tx_size; - data_offset = msg->param_data_size - sz_remaining; - - /* clear the fields */ - header.extension &= IPC_INITIAL_BLOCK_CLEAR; - header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; - /* fill the fields */ - header.extension |= IPC_INITIAL_BLOCK(0); - header.extension |= IPC_DATA_OFFSET_SZ(data_offset); - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); - -int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, - u32 **payload, size_t *bytes) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request, reply = {0}; - unsigned int *buf; - int ret; - - reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL); - if (!reply.data) - return -ENOMEM; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); - header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); - header.extension |= IPC_FINAL_BLOCK(1); - header.extension |= IPC_INITIAL_BLOCK(1); - - request.header = *(u64 *)&header; - request.data = *payload; - request.size = *bytes; - reply.size = SKL_ADSP_W1_SZ; - - ret = sst_ipc_tx_message_wait(ipc, request, &reply); - if (ret < 0) - dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); - - reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK; - buf = krealloc(reply.data, reply.size, GFP_KERNEL); - if (!buf) { - kfree(reply.data); - return -ENOMEM; - } - *payload = buf; - *bytes = reply.size; - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); - -int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id, bool wait) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret = 0; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); - header.primary |= IPC_MOD_INSTANCE_ID(table_id); - header.primary |= IPC_MOD_ID(dma_id); - request.header = *(u64 *)(&header); - - if (wait) - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - else - ret = sst_ipc_tx_message_nowait(ipc, request); - - if (ret < 0) - dev_err(ipc->dev, "ipc: load lib failed\n"); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); - -int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_D0IX_WAKE(msg->wake); - header.extension |= IPC_D0IX_STREAMING(msg->streaming); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, - header.primary, header.extension); - - /* - * Use the nopm IPC here as we dont want it checking for D0iX - */ - ret = sst_ipc_tx_message_nopm(ipc, request, NULL); - if (ret < 0) - dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h deleted file mode 100644 index aaaab3b3ec42..000000000000 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ /dev/null @@ -1,169 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel SKL IPC Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ - -#ifndef __SKL_IPC_H -#define __SKL_IPC_H - -#include -#include "../common/sst-ipc.h" -#include "skl-sst-dsp.h" - -struct sst_dsp; -struct sst_generic_ipc; - -enum skl_ipc_pipeline_state { - PPL_INVALID_STATE = 0, - PPL_UNINITIALIZED = 1, - PPL_RESET = 2, - PPL_PAUSED = 3, - PPL_RUNNING = 4, - PPL_ERROR_STOP = 5, - PPL_SAVED = 6, - PPL_RESTORED = 7 -}; - -struct skl_ipc_dxstate_info { - u32 core_mask; - u32 dx_mask; -}; - -struct skl_ipc_header { - u32 primary; - u32 extension; -}; - -struct skl_dsp_cores { - unsigned int count; - enum skl_dsp_states *state; - int *usage_count; -}; - -/** - * skl_d0i3_data: skl D0i3 counters data struct - * - * @streaming: Count of usecases that can attempt streaming D0i3 - * @non_streaming: Count of usecases that can attempt non-streaming D0i3 - * @non_d0i3: Count of usecases that cannot attempt D0i3 - * @state: current state - * @work: D0i3 worker thread - */ -struct skl_d0i3_data { - int streaming; - int non_streaming; - int non_d0i3; - enum skl_dsp_d0i3_states state; - struct delayed_work work; -}; - -#define SKL_LIB_NAME_LENGTH 128 -#define SKL_MAX_LIB 16 - -struct skl_lib_info { - char name[SKL_LIB_NAME_LENGTH]; - const struct firmware *fw; -}; - -struct skl_ipc_init_instance_msg { - u32 module_id; - u32 instance_id; - u16 param_data_size; - u8 ppl_instance_id; - u8 core_id; - u8 domain; -}; - -struct skl_ipc_bind_unbind_msg { - u32 module_id; - u32 instance_id; - u32 dst_module_id; - u32 dst_instance_id; - u8 src_queue; - u8 dst_queue; - bool bind; -}; - -struct skl_ipc_large_config_msg { - u32 module_id; - u32 instance_id; - u32 large_param_id; - u32 param_data_size; -}; - -struct skl_ipc_d0ix_msg { - u32 module_id; - u32 instance_id; - u8 streaming; - u8 wake; -}; - -#define SKL_IPC_BOOT_MSECS 3000 - -#define SKL_IPC_D3_MASK 0 -#define SKL_IPC_D0_MASK 3 - -irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); - -int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); - -int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); - -int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, - u8 instance_id, enum skl_ipc_pipeline_state state); - -int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, - u8 instance_id, int dma_id); - -int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); - -int skl_ipc_init_instance(struct sst_generic_ipc *ipc, - struct skl_ipc_init_instance_msg *msg, void *param_data); - -int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, - struct skl_ipc_bind_unbind_msg *msg); - -int skl_ipc_load_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data); - -int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data); - -int skl_ipc_set_dx(struct sst_generic_ipc *ipc, - u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); - -int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param); - -int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, - u32 **payload, size_t *bytes); - -int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id, bool wait); - -int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, - struct skl_ipc_d0ix_msg *msg); - -int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); - -void skl_ipc_int_enable(struct sst_dsp *ctx); -void skl_ipc_op_int_enable(struct sst_dsp *ctx); -void skl_ipc_op_int_disable(struct sst_dsp *ctx); -void skl_ipc_int_disable(struct sst_dsp *ctx); - -bool skl_ipc_int_status(struct sst_dsp *ctx); -void skl_ipc_free(struct sst_generic_ipc *ipc); -int skl_ipc_init(struct device *dev, struct skl_dev *skl); -void skl_clear_module_cnt(struct sst_dsp *ctx); - -void skl_ipc_process_reply(struct sst_generic_ipc *ipc, - struct skl_ipc_header header); -int skl_ipc_process_notification(struct sst_generic_ipc *ipc, - struct skl_ipc_header header); -void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, - size_t tx_size); -#endif /* __SKL_IPC_H */ diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c deleted file mode 100644 index b776c58dcf47..000000000000 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ /dev/null @@ -1,425 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-utils.c - SKL sst utils functions - * - * Copyright (C) 2016 Intel Corp - */ - -#include -#include -#include -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -#define DEFAULT_HASH_SHA256_LEN 32 - -/* FW Extended Manifest Header id = $AE1 */ -#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 - -union seg_flags { - u32 ul; - struct { - u32 contents : 1; - u32 alloc : 1; - u32 load : 1; - u32 read_only : 1; - u32 code : 1; - u32 data : 1; - u32 _rsvd0 : 2; - u32 type : 4; - u32 _rsvd1 : 4; - u32 length : 16; - } r; -} __packed; - -struct segment_desc { - union seg_flags flags; - u32 v_base_addr; - u32 file_offset; -}; - -struct module_type { - u32 load_type : 4; - u32 auto_start : 1; - u32 domain_ll : 1; - u32 domain_dp : 1; - u32 rsvd : 25; -} __packed; - -struct adsp_module_entry { - u32 struct_id; - u8 name[8]; - u8 uuid[16]; - struct module_type type; - u8 hash1[DEFAULT_HASH_SHA256_LEN]; - u32 entry_point; - u16 cfg_offset; - u16 cfg_count; - u32 affinity_mask; - u16 instance_max_count; - u16 instance_bss_size; - struct segment_desc segments[3]; -} __packed; - -struct adsp_fw_hdr { - u32 id; - u32 len; - u8 name[8]; - u32 preload_page_count; - u32 fw_image_flags; - u32 feature_mask; - u16 major; - u16 minor; - u16 hotfix; - u16 build; - u32 num_modules; - u32 hw_buf_base; - u32 hw_buf_length; - u32 load_offset; -} __packed; - -struct skl_ext_manifest_hdr { - u32 id; - u32 len; - u16 version_major; - u16 version_minor; - u32 entries; -}; - -static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) -{ - int pvt_id; - - for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) { - if (module->instance_id[pvt_id] == instance_id) - return pvt_id; - } - return -EINVAL; -} - -int skl_get_pvt_instance_id_map(struct skl_dev *skl, - int module_id, int instance_id) -{ - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (module->id == module_id) - return skl_get_pvtid_map(module, instance_id); - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map); - -static inline int skl_getid_32(struct uuid_module *module, u64 *val, - int word1_mask, int word2_mask) -{ - int index, max_inst, pvt_id; - u32 mask_val; - - max_inst = module->max_instance; - mask_val = (u32)(*val >> word1_mask); - - if (mask_val != 0xffffffff) { - index = ffz(mask_val); - pvt_id = index + word1_mask + word2_mask; - if (pvt_id <= (max_inst - 1)) { - *val |= 1ULL << (index + word1_mask); - return pvt_id; - } - } - - return -EINVAL; -} - -static inline int skl_pvtid_128(struct uuid_module *module) -{ - int j, i, word1_mask, word2_mask = 0, pvt_id; - - for (j = 0; j < MAX_INSTANCE_BUFF; j++) { - word1_mask = 0; - - for (i = 0; i < 2; i++) { - pvt_id = skl_getid_32(module, &module->pvt_id[j], - word1_mask, word2_mask); - if (pvt_id >= 0) - return pvt_id; - - word1_mask += 32; - if ((word1_mask + word2_mask) >= module->max_instance) - return -EINVAL; - } - - word2_mask += 64; - if (word2_mask >= module->max_instance) - return -EINVAL; - } - - return -EINVAL; -} - -/** - * skl_get_pvt_id: generate a private id for use as module id - * - * @skl: driver context - * @uuid_mod: module's uuid - * @instance_id: module's instance id - * - * This generates a 128 bit private unique id for a module TYPE so that - * module instance is unique - */ -int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id) -{ - struct uuid_module *module; - int pvt_id; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - - pvt_id = skl_pvtid_128(module); - if (pvt_id >= 0) { - module->instance_id[pvt_id] = instance_id; - - return pvt_id; - } - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_get_pvt_id); - -/** - * skl_put_pvt_id: free up the private id allocated - * - * @skl: driver context - * @uuid_mod: module's uuid - * @pvt_id: module pvt id - * - * This frees a 128 bit private unique id previously generated - */ -int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id) -{ - int i; - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - - if (*pvt_id != 0) - i = (*pvt_id) / 64; - else - i = 0; - - module->pvt_id[i] &= ~(1 << (*pvt_id)); - *pvt_id = -1; - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_put_pvt_id); - -/* - * Parse the firmware binary to get the UUID, module id - * and loadable flags - */ -int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, - unsigned int offset, int index) -{ - struct adsp_fw_hdr *adsp_hdr; - struct adsp_module_entry *mod_entry; - int i, num_entry, size; - const char *buf; - struct skl_dev *skl = ctx->thread_context; - struct uuid_module *module; - struct firmware stripped_fw; - unsigned int safe_file; - int ret; - - /* Get the FW pointer to derive ADSP header */ - stripped_fw.data = fw->data; - stripped_fw.size = fw->size; - - skl_dsp_strip_extended_manifest(&stripped_fw); - - buf = stripped_fw.data; - - /* check if we have enough space in file to move to header */ - safe_file = sizeof(*adsp_hdr) + offset; - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); - return -EINVAL; - } - - adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); - - /* check 1st module entry is in file */ - safe_file += adsp_hdr->len + sizeof(*mod_entry); - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No module entry\n"); - return -EINVAL; - } - - mod_entry = (struct adsp_module_entry *)(buf + offset + adsp_hdr->len); - - num_entry = adsp_hdr->num_modules; - - /* check all entries are in file */ - safe_file += num_entry * sizeof(*mod_entry); - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No modules\n"); - return -EINVAL; - } - - - /* - * Read the UUID(GUID) from FW Manifest. - * - * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX - * Populate the UUID table to store module_id and loadable flags - * for the module. - */ - - for (i = 0; i < num_entry; i++, mod_entry++) { - module = kzalloc(sizeof(*module), GFP_KERNEL); - if (!module) { - ret = -ENOMEM; - goto free_uuid_list; - } - - import_guid(&module->uuid, mod_entry->uuid); - - module->id = (i | (index << 12)); - module->is_loadable = mod_entry->type.load_type; - module->max_instance = mod_entry->instance_max_count; - size = sizeof(int) * mod_entry->instance_max_count; - module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); - if (!module->instance_id) { - ret = -ENOMEM; - kfree(module); - goto free_uuid_list; - } - - list_add_tail(&module->list, &skl->uuid_list); - - dev_dbg(ctx->dev, - "Adding uuid :%pUL mod id: %d Loadable: %d\n", - &module->uuid, module->id, module->is_loadable); - } - - return 0; - -free_uuid_list: - skl_freeup_uuid_list(skl); - return ret; -} - -void skl_freeup_uuid_list(struct skl_dev *skl) -{ - struct uuid_module *uuid, *_uuid; - - list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) { - list_del(&uuid->list); - kfree(uuid); - } -} - -/* - * some firmware binary contains some extended manifest. This needs - * to be stripped in that case before we load and use that image. - * - * Get the module id for the module by checking - * the table for the UUID for the module - */ -int skl_dsp_strip_extended_manifest(struct firmware *fw) -{ - struct skl_ext_manifest_hdr *hdr; - - /* check if fw file is greater than header we are looking */ - if (fw->size < sizeof(hdr)) { - pr_err("%s: Firmware file small, no hdr\n", __func__); - return -EINVAL; - } - - hdr = (struct skl_ext_manifest_hdr *)fw->data; - - if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { - fw->size -= hdr->len; - fw->data += hdr->len; - } - - return 0; -} - -int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, - struct sst_dsp_device *skl_dev) -{ - struct skl_dev *skl = *dsp; - struct sst_dsp *sst; - - skl->dev = dev; - skl_dev->thread_context = skl; - INIT_LIST_HEAD(&skl->uuid_list); - skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq); - if (!skl->dsp) { - dev_err(skl->dev, "%s: no device\n", __func__); - return -ENODEV; - } - - sst = skl->dsp; - sst->fw_name = fw_name; - sst->dsp_ops = dsp_ops; - init_waitqueue_head(&skl->mod_load_wait); - INIT_LIST_HEAD(&sst->module_list); - - skl->is_first_boot = true; - - return 0; -} - -int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, - struct firmware *stripped_fw, - unsigned int hdr_offset, int index) -{ - int ret; - struct sst_dsp *dsp = skl->dsp; - - if (linfo->fw == NULL) { - ret = request_firmware(&linfo->fw, linfo->name, - skl->dev); - if (ret < 0) { - dev_err(skl->dev, "Request lib %s failed:%d\n", - linfo->name, ret); - return ret; - } - } - - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index); - if (ret < 0) - return ret; - } - - stripped_fw->data = linfo->fw->data; - stripped_fw->size = linfo->fw->size; - skl_dsp_strip_extended_manifest(stripped_fw); - - return 0; -} - -void skl_release_library(struct skl_lib_info *linfo, int lib_count) -{ - int i; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - if (linfo[i].fw) { - release_firmware(linfo[i].fw); - linfo[i].fw = NULL; - } - } -} diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c deleted file mode 100644 index 39d027ac16ec..000000000000 --- a/sound/soc/intel/skylake/skl-sst.c +++ /dev/null @@ -1,599 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst.c - HDA DSP library functions for SKL platform - * - * Copyright (C) 2014-15, Intel Corporation. - * Author:Rafal Redzimski - * Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "../common/sst-ipc.h" -#include "skl.h" - -#define SKL_BASEFW_TIMEOUT 300 -#define SKL_INIT_TIMEOUT 1000 - -/* Intel HD Audio SRAM Window 0*/ -#define SKL_ADSP_SRAM0_BASE 0x8000 - -/* Firmware status window */ -#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE -#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) - -#define SKL_NUM_MODULES 1 - -static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) -{ - u32 cur_sts; - - cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; - - return (cur_sts == status); -} - -static int skl_transfer_firmware(struct sst_dsp *ctx, - const void *basefw, u32 base_fw_size) -{ - int ret = 0; - - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size, - true); - if (ret < 0) - return ret; - - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_FW_STATUS, - SKL_FW_STS_MASK, - SKL_FW_RFW_START, - SKL_BASEFW_TIMEOUT, - "Firmware boot"); - - ctx->cl_dev.ops.cl_stop_dma(ctx); - - return ret; -} - -#define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284 - -static int skl_load_base_firmware(struct sst_dsp *ctx) -{ - int ret = 0, i; - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - u32 reg; - - skl->boot_complete = false; - init_waitqueue_head(&skl->boot_wait); - - if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - return -EIO; - } - } - - /* prase uuids on first boot */ - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0); - if (ret < 0) { - dev_err(ctx->dev, "UUID parsing err: %d\n", ret); - release_firmware(ctx->fw); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - return ret; - } - } - - /* check for extended manifest */ - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - - skl_dsp_strip_extended_manifest(&stripped_fw); - - ret = skl_dsp_boot(ctx); - if (ret < 0) { - dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); - goto skl_load_base_firmware_failed; - } - - ret = skl_cldma_prepare(ctx); - if (ret < 0) { - dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret); - goto skl_load_base_firmware_failed; - } - - /* enable Interrupt */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - - /* check ROM Status */ - for (i = SKL_INIT_TIMEOUT; i > 0; --i) { - if (skl_check_fw_status(ctx, SKL_FW_INIT)) { - dev_dbg(ctx->dev, - "ROM loaded, we can continue with FW loading\n"); - break; - } - mdelay(1); - } - if (!i) { - reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); - dev_err(ctx->dev, - "Timeout waiting for ROM init done, reg:0x%x\n", reg); - ret = -EIO; - goto transfer_firmware_failed; - } - - ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size); - if (ret < 0) { - dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); - goto transfer_firmware_failed; - } else { - ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); - ret = -EIO; - goto transfer_firmware_failed; - } - - dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); - skl->fw_loaded = true; - } - return 0; -transfer_firmware_failed: - ctx->cl_dev.ops.cl_cleanup_controller(ctx); -skl_load_base_firmware_failed: - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - release_firmware(ctx->fw); - ctx->fw = NULL; - return ret; -} - -static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - /* If core0 is being turned on, we need to load the FW */ - if (core_id == SKL_DSP_CORE0_ID) { - ret = skl_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "unable to load firmware\n"); - return ret; - } - - /* load libs as they are also lost on D3 */ - if (skl->lib_count > 1) { - ret = ctx->fw_ops.load_library(ctx, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(ctx->dev, "reload libs failed: %d\n", - ret); - return ret; - } - - } - } - - /* - * If any core other than core 0 is being moved to D0, enable the - * core and send the set dx IPC for the core. - */ - if (core_id != SKL_DSP_CORE0_ID) { - ret = skl_dsp_enable_core(ctx, core_mask); - if (ret < 0) - return ret; - - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, - SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set dsp to D0:core id= %d\n", - core_id); - skl_dsp_disable_core(ctx, core_mask); - } - } - - skl->cores.state[core_id] = SKL_DSP_RUNNING; - - return 0; -} - -static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) - dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret); - - if (core_id == SKL_DSP_CORE0_ID) { - /* disable Interrupt */ - ctx->cl_dev.ops.cl_cleanup_controller(ctx); - skl_cldma_int_disable(ctx); - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - - ret = skl_dsp_disable_core(ctx, core_mask); - if (ret < 0) - return ret; - - skl->cores.state[core_id] = SKL_DSP_RESET; - return ret; -} - -static unsigned int skl_get_errorcode(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); -} - -/* - * since get/set_module are called from DAPM context, - * we don't need lock for usage count - */ -static int skl_get_module(struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return ++module->usage_cnt; - } - - return -EINVAL; -} - -static int skl_put_module(struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return --module->usage_cnt; - } - - return -EINVAL; -} - -static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx, - char *mod_name, int mod_id) -{ - const struct firmware *fw; - struct skl_module_table *skl_module; - unsigned int size; - int ret; - - ret = request_firmware(&fw, mod_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request Module %s failed :%d\n", - mod_name, ret); - return NULL; - } - - skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL); - if (skl_module == NULL) { - release_firmware(fw); - return NULL; - } - - size = sizeof(*skl_module->mod_info); - skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL); - if (skl_module->mod_info == NULL) { - release_firmware(fw); - return NULL; - } - - skl_module->mod_info->mod_id = mod_id; - skl_module->mod_info->fw = fw; - list_add(&skl_module->list, &ctx->module_list); - - return skl_module; -} - -/* get a module from it's unique ID */ -static struct skl_module_table *skl_module_get_from_id( - struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - if (list_empty(&ctx->module_list)) { - dev_err(ctx->dev, "Module list is empty\n"); - return NULL; - } - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return module; - } - - return NULL; -} - -static int skl_transfer_module(struct sst_dsp *ctx, const void *data, - u32 size, u16 mod_id, u8 table_id, bool is_module) -{ - int ret, bytes_left, curr_pos; - struct skl_dev *skl = ctx->thread_context; - skl->mod_load_complete = false; - - bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); - if (bytes_left < 0) - return bytes_left; - - /* check is_module flag to load module or library */ - if (is_module) - ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); - else - ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false); - - if (ret < 0) { - dev_err(ctx->dev, "Failed to Load %s with err %d\n", - is_module ? "module" : "lib", ret); - goto out; - } - - /* - * if bytes_left > 0 then wait for BDL complete interrupt and - * copy the next chunk till bytes_left is 0. if bytes_left is - * zero, then wait for load module IPC reply - */ - while (bytes_left > 0) { - curr_pos = size - bytes_left; - - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) - goto out; - - bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, - data + curr_pos, - bytes_left, false); - } - - ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0 || !skl->mod_load_status) { - dev_err(ctx->dev, "Module Load failed\n"); - ret = -EIO; - } - -out: - ctx->cl_dev.ops.cl_stop_dma(ctx); - - return ret; -} - -static int -skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) -{ - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - int ret, i; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, - SKL_ADSP_FW_BIN_HDR_OFFSET, i); - if (ret < 0) - goto load_library_failed; - ret = skl_transfer_module(ctx, stripped_fw.data, - stripped_fw.size, 0, i, false); - if (ret < 0) - goto load_library_failed; - } - - return 0; - -load_library_failed: - skl_release_library(linfo, lib_count); - return ret; -} - -static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) -{ - struct skl_module_table *module_entry = NULL; - int ret = 0; - char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ - - snprintf(mod_name, sizeof(mod_name), "intel/dsp_fw_%pUL.bin", guid); - - module_entry = skl_module_get_from_id(ctx, mod_id); - if (module_entry == NULL) { - module_entry = skl_fill_module_table(ctx, mod_name, mod_id); - if (module_entry == NULL) { - dev_err(ctx->dev, "Failed to Load module\n"); - return -EINVAL; - } - } - - if (!module_entry->usage_cnt) { - ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data, - module_entry->mod_info->fw->size, - mod_id, 0, true); - if (ret < 0) { - dev_err(ctx->dev, "Failed to Load module\n"); - return ret; - } - } - - ret = skl_get_module(ctx, mod_id); - - return ret; -} - -static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) -{ - int usage_cnt; - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - usage_cnt = skl_put_module(ctx, mod_id); - if (usage_cnt < 0) { - dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); - return -EIO; - } - - /* if module is used by others return, no need to unload */ - if (usage_cnt > 0) - return 0; - - ret = skl_ipc_unload_modules(&skl->ipc, - SKL_NUM_MODULES, &mod_id); - if (ret < 0) { - dev_err(ctx->dev, "Failed to UnLoad module\n"); - skl_get_module(ctx, mod_id); - return ret; - } - - return ret; -} - -void skl_clear_module_cnt(struct sst_dsp *ctx) -{ - struct skl_module_table *module; - - if (list_empty(&ctx->module_list)) - return; - - list_for_each_entry(module, &ctx->module_list, list) { - module->usage_cnt = 0; - } -} -EXPORT_SYMBOL_GPL(skl_clear_module_cnt); - -static void skl_clear_module_table(struct sst_dsp *ctx) -{ - struct skl_module_table *module, *tmp; - - if (list_empty(&ctx->module_list)) - return; - - list_for_each_entry_safe(module, tmp, &ctx->module_list, list) { - list_del(&module->list); - release_firmware(module->mod_info->fw); - } -} - -static const struct skl_dsp_fw_ops skl_fw_ops = { - .set_state_D0 = skl_set_dsp_D0, - .set_state_D3 = skl_set_dsp_D3, - .load_fw = skl_load_base_firmware, - .get_fw_errcode = skl_get_errorcode, - .load_library = skl_load_library, - .load_mod = skl_load_module, - .unload_mod = skl_unload_module, -}; - -static struct sst_ops skl_ops = { - .irq_handler = skl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = skl_dsp_free, -}; - -static struct sst_dsp_device skl_dev = { - .thread = skl_dsp_irq_thread_handler, - .ops = &skl_ops, -}; - -int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *skl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - skl = *dsp; - sst = skl->dsp; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE; - sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), - SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - - ret = skl_ipc_init(dev, skl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - sst->fw_ops = skl_fw_ops; - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(skl_sst_dsp_init); - -int skl_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = sst->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "Load base fw failed : %d\n", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - if (skl->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(dev, "Load Library failed : %x\n", ret); - return ret; - } - } - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(skl_sst_init_fw); - -void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - skl_clear_module_table(skl->dsp); - skl_freeup_uuid_list(skl); - skl_ipc_free(&skl->ipc); - skl->dsp->ops->free(skl->dsp); - if (skl->boot_complete) { - skl->dsp->cl_dev.ops.cl_cleanup_controller(skl->dsp); - skl_cldma_int_disable(skl->dsp); - } -} -EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Skylake IPC driver"); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c deleted file mode 100644 index 602ef4321122..000000000000 --- a/sound/soc/intel/skylake/skl-topology.c +++ /dev/null @@ -1,3605 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-topology.c - Implements Platform component ALSA controls/widget - * handlers. - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl-topology.h" -#include "skl.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -#define SKL_CH_FIXUP_MASK (1 << 0) -#define SKL_RATE_FIXUP_MASK (1 << 1) -#define SKL_FMT_FIXUP_MASK (1 << 2) -#define SKL_IN_DIR_BIT_MASK BIT(0) -#define SKL_PIN_COUNT_MASK GENMASK(7, 4) - -static const int mic_mono_list[] = { -0, 1, 2, 3, -}; -static const int mic_stereo_list[][SKL_CH_STEREO] = { -{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, -}; -static const int mic_trio_list[][SKL_CH_TRIO] = { -{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, -}; -static const int mic_quatro_list[][SKL_CH_QUATRO] = { -{0, 1, 2, 3}, -}; - -#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ - ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) - -void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3++; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming++; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming++; - break; - } -} - -void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3--; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming--; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming--; - break; - } -} - -/* - * SKL DSP driver modelling uses only few DAPM widgets so for rest we will - * ignore. This helpers checks if the SKL driver handles this widget type - */ -static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, - struct device *dev) -{ - if (w->dapm->dev != dev) - return false; - - switch (w->id) { - case snd_soc_dapm_dai_link: - case snd_soc_dapm_dai_in: - case snd_soc_dapm_aif_in: - case snd_soc_dapm_aif_out: - case snd_soc_dapm_dai_out: - case snd_soc_dapm_switch: - case snd_soc_dapm_output: - case snd_soc_dapm_mux: - - return false; - default: - return true; - } -} - -static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) -{ - struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; - - dev_dbg(skl->dev, "Dumping config\n"); - dev_dbg(skl->dev, "Input Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->inputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "Output Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->outputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); -} - -static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) -{ - int slot_map = 0xFFFFFFFF; - int start_slot = 0; - int i; - - for (i = 0; i < chs; i++) { - /* - * For 2 channels with starting slot as 0, slot map will - * look like 0xFFFFFF10. - */ - slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); - start_slot++; - } - fmt->ch_map = slot_map; -} - -static void skl_tplg_update_params(struct skl_module_fmt *fmt, - struct skl_pipe_params *params, int fixup) -{ - if (fixup & SKL_RATE_FIXUP_MASK) - fmt->s_freq = params->s_freq; - if (fixup & SKL_CH_FIXUP_MASK) { - fmt->channels = params->ch; - skl_tplg_update_chmap(fmt, fmt->channels); - } - if (fixup & SKL_FMT_FIXUP_MASK) { - fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); - - /* - * 16 bit is 16 bit container whereas 24 bit is in 32 bit - * container so update bit depth accordingly - */ - switch (fmt->valid_bit_depth) { - case SKL_DEPTH_16BIT: - fmt->bit_depth = fmt->valid_bit_depth; - break; - - default: - fmt->bit_depth = SKL_DEPTH_32BIT; - break; - } - } - -} - -/* - * A pipeline may have modules which impact the pcm parameters, like SRC, - * channel converter, format converter. - * We need to calculate the output params by applying the 'fixup' - * Topology will tell driver which type of fixup is to be applied by - * supplying the fixup mask, so based on that we calculate the output - * - * Now In FE the pcm hw_params is source/target format. Same is applicable - * for BE with its hw_params invoked. - * here based on FE, BE pipeline and direction we calculate the input and - * outfix and then apply that for a module - */ -static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, - struct skl_pipe_params *params, bool is_fe) -{ - int in_fixup, out_fixup; - struct skl_module_fmt *in_fmt, *out_fmt; - - /* Fixups will be applied to pin 0 only */ - in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt; - out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt; - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (is_fe) { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } else { - if (is_fe) { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } - - skl_tplg_update_params(in_fmt, params, in_fixup); - skl_tplg_update_params(out_fmt, params, out_fixup); -} - -/* - * A module needs input and output buffers, which are dependent upon pcm - * params, so once we have calculate params, we need buffer calculation as - * well. - */ -static void skl_tplg_update_buffer_size(struct skl_dev *skl, - struct skl_module_cfg *mcfg) -{ - int multiplier = 1; - struct skl_module_fmt *in_fmt, *out_fmt; - struct skl_module_res *res; - - /* Since fixups is applied to pin 0 only, ibs, obs needs - * change for pin 0 only - */ - res = &mcfg->module->resources[mcfg->res_idx]; - in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt; - out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt; - - if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) - multiplier = 5; - - res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * - in_fmt->channels * (in_fmt->bit_depth >> 3) * - multiplier; - - res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * - out_fmt->channels * (out_fmt->bit_depth >> 3) * - multiplier; -} - -static u8 skl_tplg_be_dev_type(int dev_type) -{ - int ret; - - switch (dev_type) { - case SKL_DEVICE_BT: - ret = NHLT_DEVICE_BT; - break; - - case SKL_DEVICE_DMIC: - ret = NHLT_DEVICE_DMIC; - break; - - case SKL_DEVICE_I2S: - ret = NHLT_DEVICE_I2S; - break; - - default: - ret = NHLT_DEVICE_INVALID; - break; - } - - return ret; -} - -static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - int link_type, dir; - u32 ch, s_freq, s_fmt, s_cont; - struct nhlt_specific_cfg *cfg; - u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); - int fmt_idx = m_cfg->fmt_idx; - struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; - - /* check if we already have blob */ - if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0) - return 0; - - dev_dbg(skl->dev, "Applying default cfg blob\n"); - switch (m_cfg->dev_type) { - case SKL_DEVICE_DMIC: - link_type = NHLT_LINK_DMIC; - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - break; - - case SKL_DEVICE_I2S: - link_type = NHLT_LINK_SSP; - if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { - dir = SNDRV_PCM_STREAM_PLAYBACK; - s_freq = m_iface->outputs[0].fmt.s_freq; - s_fmt = m_iface->outputs[0].fmt.valid_bit_depth; - s_cont = m_iface->outputs[0].fmt.bit_depth; - ch = m_iface->outputs[0].fmt.channels; - } else { - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - } - break; - - default: - return -EINVAL; - } - - /* update the blob based on virtual bus_id and default params */ - cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id, - link_type, s_fmt, s_cont, ch, - s_freq, dir, dev_type); - if (cfg) { - m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; - m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; - } else { - dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", - m_cfg->vbus_id, link_type, dir); - dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n", - ch, s_freq, s_fmt, s_cont); - return -EIO; - } - - return 0; -} - -static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - struct skl_pipe_params *params = m_cfg->pipe->p_params; - int p_conn_type = m_cfg->pipe->conn_type; - bool is_fe; - - if (!m_cfg->params_fixup) - return; - - dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); - - if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) - is_fe = true; - else - is_fe = false; - - skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(skl, m_cfg); - - dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); -} - -/* - * some modules can have multiple params set from user control and - * need to be set after module is initialized. If set_param flag is - * set module params will be done after module is initialised. - */ -static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - - if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_SET]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(skl, - (u32 *)bc->params, bc->size, - bc->param_id, mconfig); - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -/* - * some module param can set from user control and this is required as - * when module is initailzed. if module param is required in init it is - * identifed by set_param flag. if set_param flag is not set, then this - * parameter needs to set as part of module init. - */ -static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) -{ - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_module_cfg *mconfig = w->priv; - int i; - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (struct soc_bytes_ext *)k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params != SKL_PARAM_INIT) - continue; - - mconfig->formats_config[SKL_PARAM_INIT].caps = - (u32 *)bc->params; - mconfig->formats_config[SKL_PARAM_INIT].caps_size = - bc->size; - - break; - } - } - - return 0; -} - -static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, - struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) -{ - switch (mcfg->dev_type) { - case SKL_DEVICE_HDAHOST: - return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); - - case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); - } - - return 0; -} - -/* - * Inside a pipe instance, we can have various modules. These modules need - * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by - * skl_init_module() routine, so invoke that for all modules in a pipeline - */ -static int -skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) -{ - struct skl_pipe_module *w_module; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - u8 cfg_idx; - int ret = 0; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - w = w_module->w; - mconfig = w->priv; - - /* check if module ids are populated */ - if (mconfig->id.module_id < 0) { - dev_err(skl->dev, - "module %pUL id not populated\n", - (guid_t *)mconfig->guid); - return -EIO; - } - - cfg_idx = mconfig->pipe->cur_config_idx; - mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; - mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - - if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { - ret = skl->dsp->fw_ops.load_mod(skl->dsp, - mconfig->id.module_id, mconfig->guid); - if (ret < 0) - return ret; - } - - /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); - if (ret < 0) - return ret; - - /* update blob if blob is null for be with default value */ - skl_tplg_update_be_blob(w, skl); - - /* - * apply fix/conversion to module params based on - * FE/BE params - */ - skl_tplg_update_module_params(w, skl); - uuid_mod = (guid_t *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, - mconfig->id.instance_id); - if (mconfig->id.pvt_id < 0) - return ret; - skl_tplg_set_module_init_data(w); - - ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", - mconfig->core_id, ret); - return ret; - } - - ret = skl_init_module(skl, mconfig); - if (ret < 0) { - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - goto err; - } - - ret = skl_tplg_set_module_params(w, skl); - if (ret < 0) - goto err; - } - - return 0; -err: - skl_dsp_put_core(skl->dsp, mconfig->core_id); - return ret; -} - -static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, - struct skl_pipe *pipe) -{ - int ret = 0; - struct skl_pipe_module *w_module; - struct skl_module_cfg *mconfig; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - mconfig = w_module->w->priv; - uuid_mod = (guid_t *)mconfig->guid; - - if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) { - ret = skl->dsp->fw_ops.unload_mod(skl->dsp, - mconfig->id.module_id); - if (ret < 0) - return -EIO; - } - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - - ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - /* don't return; continue with other modules */ - dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", - mconfig->core_id, ret); - } - } - - /* no modules to unload in this path, so return */ - return ret; -} - -static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx) -{ - pipe->cur_config_idx = idx; - pipe->memory_pages = pipe->configs[idx].mem_pages; -} - -/* - * Here, we select pipe format based on the pipe type and pipe - * direction to determine the current config index for the pipeline. - * The config index is then used to select proper module resources. - * Intermediate pipes currently have a fixed format hence we select the - * 0th configuratation by default for such pipes. - */ -static int -skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - struct skl_pipe *pipe = mconfig->pipe; - struct skl_pipe_params *params = pipe->p_params; - struct skl_path_config *pconfig = &pipe->configs[0]; - struct skl_pipe_fmt *fmt = NULL; - bool in_fmt = false; - int i; - - if (pipe->nr_cfgs == 0) { - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) { - dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n", - pipe->ppl_id); - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && - pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || - (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && - pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) - in_fmt = true; - - for (i = 0; i < pipe->nr_cfgs; i++) { - pconfig = &pipe->configs[i]; - if (in_fmt) - fmt = &pconfig->in_fmt; - else - fmt = &pconfig->out_fmt; - - if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, - fmt->channels, fmt->freq, fmt->bps)) { - skl_tplg_set_pipe_config_idx(pipe, i); - dev_dbg(skl->dev, "Using pipe config: %d\n", i); - return 0; - } - } - - dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", - params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); - return -EINVAL; -} - -/* - * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we - * need create the pipeline. So we do following: - * - Create the pipeline - * - Initialize the modules in pipeline - * - finally bind all modules together - */ -static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret; - struct skl_module_cfg *mconfig = w->priv; - struct skl_pipe_module *w_module; - struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_cfg *src_module = NULL, *dst_module, *module; - struct skl_module_deferred_bind *modules; - - ret = skl_tplg_get_pipe_config(skl, mconfig); - if (ret < 0) - return ret; - - /* - * Create a list of modules for pipe. - * This list contains modules from source to sink - */ - ret = skl_create_pipeline(skl, mconfig->pipe); - if (ret < 0) - return ret; - - /* Init all pipe modules from source to sink */ - ret = skl_tplg_init_pipe_modules(skl, s_pipe); - if (ret < 0) - return ret; - - /* Bind modules from source to sink */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - dst_module = w_module->w->priv; - - if (src_module == NULL) { - src_module = dst_module; - continue; - } - - ret = skl_bind_modules(skl, src_module, dst_module); - if (ret < 0) - return ret; - - src_module = dst_module; - } - - /* - * When the destination module is initialized, check for these modules - * in deferred bind list. If found, bind them. - */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - if (list_empty(&skl->bind_list)) - break; - - list_for_each_entry(modules, &skl->bind_list, node) { - module = w_module->w->priv; - if (modules->dst == module) - skl_bind_modules(skl, modules->src, - modules->dst); - } - } - - return 0; -} - -static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, - int size, struct skl_module_cfg *mcfg) -{ - int i, pvt_id; - - if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { - struct skl_kpb_params *kpb_params = - (struct skl_kpb_params *)params; - struct skl_mod_inst_map *inst = kpb_params->u.map; - - for (i = 0; i < kpb_params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, - inst->inst_id); - if (pvt_id < 0) - return -EINVAL; - - inst->inst_id = pvt_id; - inst++; - } - } - - return 0; -} -/* - * Some modules require params to be set after the module is bound to - * all pins connected. - * - * The module provider initializes set_param flag for such modules and we - * send params after binding - */ -static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mcfg, struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - u32 *params; - - /* - * check all out/in pins are in bind state. - * if so set the module param - */ - for (i = 0; i < mcfg->module->max_output_pins; i++) { - if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - for (i = 0; i < mcfg->module->max_input_pins; i++) { - if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_BIND].set_params == - SKL_PARAM_BIND) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_BIND) { - params = kmemdup(bc->params, bc->max, GFP_KERNEL); - if (!params) - return -ENOMEM; - - skl_fill_sink_instance_id(skl, params, bc->max, - mconfig); - - ret = skl_set_module_params(skl, params, - bc->max, bc->param_id, mconfig); - kfree(params); - - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) -{ - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid, &module->uuid)) - return module->id; - } - - return -EINVAL; -} - -static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, - const struct snd_kcontrol_new *k) -{ - struct soc_bytes_ext *sb = (void *) k->private_value; - struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; - struct skl_kpb_params *uuid_params, *params; - struct hdac_bus *bus = skl_to_bus(skl); - int i, size, module_id; - - if (bc->set_params == SKL_PARAM_BIND && bc->max) { - uuid_params = (struct skl_kpb_params *)bc->params; - size = struct_size(params, u.map, uuid_params->num_modules); - - params = devm_kzalloc(bus->dev, size, GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->num_modules = uuid_params->num_modules; - - for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl, - &uuid_params->u.map_uuid[i].mod_uuid); - if (module_id < 0) { - devm_kfree(bus->dev, params); - return -EINVAL; - } - - params->u.map[i].mod_id = module_id; - params->u.map[i].inst_id = - uuid_params->u.map_uuid[i].inst_id; - } - - devm_kfree(bus->dev, bc->params); - bc->params = (char *)params; - bc->max = size; - } - - return 0; -} - -/* - * Retrieve the module id from UUID mentioned in the - * post bind params - */ -void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, - struct snd_soc_dapm_widget *w) -{ - struct skl_module_cfg *mconfig = w->priv; - int i; - - /* - * Post bind params are used for only for KPB - * to set copier instances to drain the data - * in fast mode - */ - if (mconfig->m_type != SKL_MODULE_TYPE_KPB) - return; - - for (i = 0; i < w->num_kcontrols; i++) - if ((w->kcontrol_news[i].access & - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && - (skl_tplg_find_moduleid_from_uuid(skl, - &w->kcontrol_news[i]) < 0)) - dev_err(skl->dev, - "%s: invalid kpb post bind params\n", - __func__); -} - -static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, - struct skl_module_cfg *src, struct skl_module_cfg *dst) -{ - struct skl_module_deferred_bind *m_list, *modules; - int i; - - /* only supported for module with static pin connection */ - for (i = 0; i < dst->module->max_input_pins; i++) { - struct skl_module_pin *pin = &dst->m_in_pin[i]; - - if (pin->is_dynamic) - continue; - - if ((pin->id.module_id == src->id.module_id) && - (pin->id.instance_id == src->id.instance_id)) { - - if (!list_empty(&skl->bind_list)) { - list_for_each_entry(modules, &skl->bind_list, node) { - if (modules->src == src && modules->dst == dst) - return 0; - } - } - - m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); - if (!m_list) - return -ENOMEM; - - m_list->src = src; - m_list->dst = dst; - - list_add(&m_list->node, &skl->bind_list); - } - } - - return 0; -} - -static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl_dev *skl, - struct snd_soc_dapm_widget *src_w, - struct skl_module_cfg *src_mconfig) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; - struct skl_module_cfg *sink_mconfig; - int ret; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (!p->connect) - continue; - - dev_dbg(skl->dev, - "%s: src widget=%s\n", __func__, w->name); - dev_dbg(skl->dev, - "%s: sink widget=%s\n", __func__, p->sink->name); - - next_sink = p->sink; - - if (!is_skl_dsp_widget_type(p->sink, skl->dev)) - return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); - - /* - * here we will check widgets in sink pipelines, so that - * can be any widgets type and we are only interested if - * they are ones used for SKL so check that first - */ - if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, skl->dev)) { - - sink = p->sink; - sink_mconfig = sink->priv; - - /* - * Modules other than PGA leaf can be connected - * directly or via switch to a module in another - * pipeline. EX: reference path - * when the path is enabled, the dst module that needs - * to be bound may not be initialized. if the module is - * not initialized, add these modules in the deferred - * bind list and when the dst module is initialised, - * bind this module to the dst_module in deferred list. - */ - if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) - && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { - - ret = skl_tplg_module_add_deferred_bind(skl, - src_mconfig, sink_mconfig); - - if (ret < 0) - return ret; - - } - - - if (src_mconfig->m_state == SKL_MODULE_UNINIT || - sink_mconfig->m_state == SKL_MODULE_UNINIT) - continue; - - /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(src_w, - src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, - sink_mconfig, skl); - - /* Start sinks pipe first */ - if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { - if (sink_mconfig->pipe->conn_type != - SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, - sink_mconfig->pipe); - if (ret) - return ret; - } - } - } - - if (!sink && next_sink) - return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); - - return 0; -} - -/* - * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA - * we need to do following: - * - Bind to sink pipeline - * Since the sink pipes can be running and we don't get mixer event on - * connect for already running mixer, we need to find the sink pipes - * here and bind to them. This way dynamic connect works. - * - Start sink pipeline, if not running - * - Then run current pipe - */ -static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig; - int ret = 0; - - src_mconfig = w->priv; - - /* - * find which sink it is connected to, bind with the sink, - * if sink is not started, start sink pipe first, then start - * this pipe - */ - ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); - if (ret) - return ret; - - /* Start source pipe last after starting all sinks */ - if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(skl, src_mconfig->pipe); - - return 0; -} - -static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( - struct snd_soc_dapm_widget *w, struct skl_dev *skl) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *src_w = NULL; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - src_w = p->source; - if (!p->connect) - continue; - - dev_dbg(skl->dev, "sink widget=%s\n", w->name); - dev_dbg(skl->dev, "src widget=%s\n", p->source->name); - - /* - * here we will check widgets in sink pipelines, so that can - * be any widgets type and we are only interested if they are - * ones used for SKL so check that first - */ - if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, skl->dev)) { - return p->source; - } - } - - if (src_w != NULL) - return skl_get_src_dsp_widget(src_w, skl); - - return NULL; -} - -/* - * in the Post-PMU event of mixer we need to do following: - * - Check if this pipe is running - * - if not, then - * - bind this pipeline to its source pipeline - * if source pipe is already running, this means it is a dynamic - * connection and we need to bind only to that pipe - * - start this pipeline - */ -static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret = 0; - struct snd_soc_dapm_widget *source, *sink; - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int src_pipe_started = 0; - - sink = w; - sink_mconfig = sink->priv; - - /* - * If source pipe is already started, that means source is driving - * one more sink before this sink got connected, Since source is - * started, bind this sink to source and start this pipe. - */ - source = skl_get_src_dsp_widget(w, skl); - if (source != NULL) { - src_mconfig = source->priv; - sink_mconfig = sink->priv; - src_pipe_started = 1; - - /* - * check pipe state, then no need to bind or start the - * pipe - */ - if (src_mconfig->pipe->state != SKL_PIPE_STARTED) - src_pipe_started = 0; - } - - if (src_pipe_started) { - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(source, src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); - - if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, sink_mconfig->pipe); - } - - return ret; -} - -/* - * in the Pre-PMD event of mixer we need to do following: - * - Stop the pipe - * - find the source connections and remove that from dapm_path_list - * - unbind with source pipelines if still connected - */ -static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, i; - - sink_mconfig = w->priv; - - /* Stop the pipe */ - ret = skl_stop_pipe(skl, sink_mconfig->pipe); - if (ret) - return ret; - - for (i = 0; i < sink_mconfig->module->max_input_pins; i++) { - if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { - src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; - if (!src_mconfig) - continue; - - ret = skl_unbind_modules(skl, - src_mconfig, sink_mconfig); - } - } - - return ret; -} - -/* - * in the Post-PMD event of mixer we need to do following: - * - Unbind the modules within the pipeline - * - Delete the pipeline (modules are not required to be explicitly - * deleted, pipeline delete is enough here - */ -static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *mconfig = w->priv; - struct skl_pipe_module *w_module; - struct skl_module_cfg *src_module = NULL, *dst_module; - struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_deferred_bind *modules, *tmp; - - if (s_pipe->state == SKL_PIPE_INVALID) - return -EINVAL; - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - if (list_empty(&skl->bind_list)) - break; - - src_module = w_module->w->priv; - - list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { - /* - * When the destination module is deleted, Unbind the - * modules from deferred bind list. - */ - if (modules->dst == src_module) { - skl_unbind_modules(skl, modules->src, - modules->dst); - } - - /* - * When the source module is deleted, remove this entry - * from the deferred bind list. - */ - if (modules->src == src_module) { - list_del(&modules->node); - modules->src = NULL; - modules->dst = NULL; - kfree(modules); - } - } - } - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - dst_module = w_module->w->priv; - - if (src_module == NULL) { - src_module = dst_module; - continue; - } - - skl_unbind_modules(skl, src_module, dst_module); - src_module = dst_module; - } - - skl_delete_pipe(skl, mconfig->pipe); - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - src_module = w_module->w->priv; - src_module->m_state = SKL_MODULE_UNINIT; - } - - return skl_tplg_unload_pipe_modules(skl, s_pipe); -} - -/* - * in the Post-PMD event of PGA we need to do following: - * - Stop the pipeline - * - In source pipe is connected, unbind with source pipelines - */ -static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, i; - - src_mconfig = w->priv; - - /* Stop the pipe since this is a mixin module */ - ret = skl_stop_pipe(skl, src_mconfig->pipe); - if (ret) - return ret; - - for (i = 0; i < src_mconfig->module->max_output_pins; i++) { - if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { - sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; - if (!sink_mconfig) - continue; - /* - * This is a connecter and if path is found that means - * unbind between source and sink has not happened yet - */ - ret = skl_unbind_modules(skl, src_mconfig, - sink_mconfig); - } - } - - return ret; -} - -/* - * In modelling, we assume there will be ONLY one mixer in a pipeline. If a - * second one is required that is created as another pipe entity. - * The mixer is responsible for pipe management and represent a pipeline - * instance - */ -static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl_dev *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMU: - return skl_tplg_mixer_dapm_post_pmu_event(w, skl); - - case SND_SOC_DAPM_PRE_PMD: - return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_mixer_dapm_post_pmd_event(w, skl); - } - - return 0; -} - -/* - * In modelling, we assumed rest of the modules in pipeline are PGA. But we - * are interested in last PGA (leaf PGA) in a pipeline to disconnect with - * the sink when it is running (two FE to one BE or one FE to two BE) - * scenarios - */ -static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) - -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl_dev *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_pga_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_pga_dapm_post_pmd_event(w, skl); - } - - return 0; -} - -static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - bool is_set) -{ - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct hdac_bus *bus = snd_soc_component_get_drvdata(component); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl; - struct skl_pipe *pipe = NULL; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 *pipe_id; - - if (!ec) - return -EINVAL; - - if (is_set && ucontrol->value.enumerated.item[0] > ec->items) - return -EINVAL; - - pipe_id = ec->dobj.private; - - list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == *pipe_id) { - pipe = ppl->pipe; - break; - } - } - if (!pipe) - return -EIO; - - if (is_set) - skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]); - else - ucontrol->value.enumerated.item[0] = pipe->cur_config_idx; - - return 0; -} - -static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); -} - -static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); -} - -static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); -} - -static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); -} - -static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, - unsigned int __user *data, unsigned int size) -{ - struct soc_bytes_ext *sb = - (struct soc_bytes_ext *)kcontrol->private_value; - struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct skl_dev *skl = get_skl_ctx(w->dapm->dev); - - if (w->power) - skl_get_module_params(skl, (u32 *)bc->params, - bc->size, bc->param_id, mconfig); - - /* decrement size for TLV header */ - size -= 2 * sizeof(u32); - - /* check size as we don't want to send kernel data */ - if (size > bc->max) - size = bc->max; - - if (bc->params) { - if (copy_to_user(data, &bc->param_id, sizeof(u32))) - return -EFAULT; - if (copy_to_user(data + 1, &size, sizeof(u32))) - return -EFAULT; - if (copy_to_user(data + 2, bc->params, size)) - return -EFAULT; - } - - return 0; -} - -#define SKL_PARAM_VENDOR_ID 0xff - -static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, - const unsigned int __user *data, unsigned int size) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct soc_bytes_ext *sb = - (struct soc_bytes_ext *)kcontrol->private_value; - struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; - struct skl_dev *skl = get_skl_ctx(w->dapm->dev); - - if (ac->params) { - if (size > ac->max) - return -EINVAL; - ac->size = size; - - if (copy_from_user(ac->params, data, size)) - return -EFAULT; - - if (w->power) - return skl_set_module_params(skl, - (u32 *)ac->params, ac->size, - ac->param_id, mconfig); - } - - return 0; -} - -static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 ch_type = *((u32 *)ec->dobj.private); - - if (mconfig->dmic_ch_type == ch_type) - ucontrol->value.enumerated.item[0] = - mconfig->dmic_ch_combo_index; - else - ucontrol->value.enumerated.item[0] = 0; - - return 0; -} - -static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, - struct skl_mic_sel_config *mic_cfg, struct device *dev) -{ - struct skl_specific_cfg *sp_cfg = - &mconfig->formats_config[SKL_PARAM_INIT]; - - sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); - sp_cfg->set_params = SKL_PARAM_SET; - sp_cfg->param_id = 0x00; - if (!sp_cfg->caps) { - sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); - if (!sp_cfg->caps) - return -ENOMEM; - } - - mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; - mic_cfg->flags = 0; - memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); - - return 0; -} - -static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct skl_mic_sel_config mic_cfg = {0}; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 ch_type = *((u32 *)ec->dobj.private); - const int *list; - u8 in_ch, out_ch, index; - - mconfig->dmic_ch_type = ch_type; - mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; - - /* enum control index 0 is INVALID, so no channels to be set */ - if (mconfig->dmic_ch_combo_index == 0) - return 0; - - /* No valid channel selection map for index 0, so offset by 1 */ - index = mconfig->dmic_ch_combo_index - 1; - - switch (ch_type) { - case SKL_CH_MONO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) - return -EINVAL; - - list = &mic_mono_list[index]; - break; - - case SKL_CH_STEREO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) - return -EINVAL; - - list = mic_stereo_list[index]; - break; - - case SKL_CH_TRIO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) - return -EINVAL; - - list = mic_trio_list[index]; - break; - - case SKL_CH_QUATRO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) - return -EINVAL; - - list = mic_quatro_list[index]; - break; - - default: - dev_err(w->dapm->dev, - "Invalid channel %d for mic_select module\n", - ch_type); - return -EINVAL; - - } - - /* channel type enum map to number of chanels for that type */ - for (out_ch = 0; out_ch < ch_type; out_ch++) { - in_ch = list[out_ch]; - mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; - } - - return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); -} - -/* - * Fill the dma id for host and link. In case of passthrough - * pipeline, this will both host and link in the same - * pipeline, so need to copy the link and host based on dev_type - */ -static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, - struct skl_pipe_params *params) -{ - struct skl_pipe *pipe = mcfg->pipe; - - if (pipe->passthru) { - switch (mcfg->dev_type) { - case SKL_DEVICE_HDALINK: - pipe->p_params->link_dma_id = params->link_dma_id; - pipe->p_params->link_index = params->link_index; - pipe->p_params->link_bps = params->link_bps; - break; - - case SKL_DEVICE_HDAHOST: - pipe->p_params->host_dma_id = params->host_dma_id; - pipe->p_params->host_bps = params->host_bps; - break; - - default: - break; - } - pipe->p_params->s_fmt = params->s_fmt; - pipe->p_params->ch = params->ch; - pipe->p_params->s_freq = params->s_freq; - pipe->p_params->stream = params->stream; - pipe->p_params->format = params->format; - - } else { - memcpy(pipe->p_params, params, sizeof(*params)); - } -} - -/* - * The FE params are passed by hw_params of the DAI. - * On hw_params, the params are stored in Gateway module of the FE and we - * need to calculate the format in DSP module configuration, that - * conversion is done here - */ -int skl_tplg_update_pipe_params(struct device *dev, - struct skl_module_cfg *mconfig, - struct skl_pipe_params *params) -{ - struct skl_module_res *res; - struct skl_dev *skl = get_skl_ctx(dev); - struct skl_module_fmt *format = NULL; - u8 cfg_idx = mconfig->pipe->cur_config_idx; - - res = &mconfig->module->resources[mconfig->res_idx]; - skl_tplg_fill_dma_id(mconfig, params); - mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; - mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - - if (skl->nr_modules) - return 0; - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) - format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt; - else - format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt; - - /* set the hw_params */ - format->s_freq = params->s_freq; - format->channels = params->ch; - format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); - - /* - * 16 bit is 16 bit container whereas 24 bit is in 32 bit - * container so update bit depth accordingly - */ - switch (format->valid_bit_depth) { - case SKL_DEPTH_16BIT: - format->bit_depth = format->valid_bit_depth; - break; - - case SKL_DEPTH_24BIT: - case SKL_DEPTH_32BIT: - format->bit_depth = SKL_DEPTH_32BIT; - break; - - default: - dev_err(dev, "Invalid bit depth %x for pipe\n", - format->valid_bit_depth); - return -EINVAL; - } - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - res->ibs = (format->s_freq / 1000) * - (format->channels) * - (format->bit_depth >> 3); - } else { - res->obs = (format->s_freq / 1000) * - (format->channels) * - (format->bit_depth >> 3); - } - - return 0; -} - -/* - * Query the module config for the FE DAI - * This is used to find the hw_params set for that DAI and apply to FE - * pipeline - */ -struct skl_module_cfg * -skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream); - struct snd_soc_dapm_path *p = NULL; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connect && p->sink->power && - !is_skl_dsp_widget_type(p->sink, dai->dev)) - continue; - - if (p->sink->priv) { - dev_dbg(dai->dev, "set params for %s\n", - p->sink->name); - return p->sink->priv; - } - } - } else { - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connect && p->source->power && - !is_skl_dsp_widget_type(p->source, dai->dev)) - continue; - - if (p->source->priv) { - dev_dbg(dai->dev, "set params for %s\n", - p->source->name); - return p->source->priv; - } - } - } - - return NULL; -} - -static struct skl_module_cfg *skl_get_mconfig_pb_cpr( - struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *p; - struct skl_module_cfg *mconfig = NULL; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { - if (p->connect && - (p->sink->id == snd_soc_dapm_aif_out) && - p->source->priv) { - mconfig = p->source->priv; - return mconfig; - } - mconfig = skl_get_mconfig_pb_cpr(dai, p->source); - if (mconfig) - return mconfig; - } - } - return mconfig; -} - -static struct skl_module_cfg *skl_get_mconfig_cap_cpr( - struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *p; - struct skl_module_cfg *mconfig = NULL; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { - if (p->connect && - (p->source->id == snd_soc_dapm_aif_in) && - p->sink->priv) { - mconfig = p->sink->priv; - return mconfig; - } - mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); - if (mconfig) - return mconfig; - } - } - return mconfig; -} - -struct skl_module_cfg * -skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream); - struct skl_module_cfg *mconfig; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - mconfig = skl_get_mconfig_pb_cpr(dai, w); - } else { - mconfig = skl_get_mconfig_cap_cpr(dai, w); - } - return mconfig; -} - -static u8 skl_tplg_be_link_type(int dev_type) -{ - int ret; - - switch (dev_type) { - case SKL_DEVICE_BT: - ret = NHLT_LINK_SSP; - break; - - case SKL_DEVICE_DMIC: - ret = NHLT_LINK_DMIC; - break; - - case SKL_DEVICE_I2S: - ret = NHLT_LINK_SSP; - break; - - case SKL_DEVICE_HDALINK: - ret = NHLT_LINK_HDA; - break; - - default: - ret = NHLT_LINK_INVALID; - break; - } - - return ret; -} - -/* - * Fill the BE gateway parameters - * The BE gateway expects a blob of parameters which are kept in the ACPI - * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. - * The port can have multiple settings so pick based on the pipeline - * parameters - */ -static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, - struct skl_module_cfg *mconfig, - struct skl_pipe_params *params) -{ - struct nhlt_specific_cfg *cfg; - struct skl_pipe *pipe = mconfig->pipe; - struct skl_pipe_params save = *pipe->p_params; - struct skl_pipe_fmt *pipe_fmt; - struct skl_dev *skl = get_skl_ctx(dai->dev); - int link_type = skl_tplg_be_link_type(mconfig->dev_type); - u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); - int ret; - - skl_tplg_fill_dma_id(mconfig, params); - - if (link_type == NHLT_LINK_HDA) - return 0; - - *pipe->p_params = *params; - ret = skl_tplg_get_pipe_config(skl, mconfig); - if (ret) - goto err; - - dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx); - if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) - pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt; - else - pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt; - - /* update the blob based on virtual bus_id*/ - cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt, - mconfig->vbus_id, link_type, - pipe_fmt->bps, params->s_cont, - pipe_fmt->channels, pipe_fmt->freq, - pipe->direction, dev_type); - if (cfg) { - mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; - mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; - } else { - dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n", - mconfig->vbus_id, link_type, params->stream, - params->ch, params->s_freq, params->s_fmt); - ret = -EINVAL; - goto err; - } - - return 0; - -err: - *pipe->p_params = save; - return ret; -} - -static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, - struct snd_soc_dapm_widget *w, - struct skl_pipe_params *params) -{ - struct snd_soc_dapm_path *p; - int ret = -EIO; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) && - p->source->priv) { - - ret = skl_tplg_be_fill_pipe_params(dai, - p->source->priv, params); - if (ret < 0) - return ret; - } else { - ret = skl_tplg_be_set_src_pipe_params(dai, - p->source, params); - if (ret < 0) - return ret; - } - } - - return ret; -} - -static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, - struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) -{ - struct snd_soc_dapm_path *p; - int ret = -EIO; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) && - p->sink->priv) { - - ret = skl_tplg_be_fill_pipe_params(dai, - p->sink->priv, params); - if (ret < 0) - return ret; - } else { - ret = skl_tplg_be_set_sink_pipe_params( - dai, p->sink, params); - if (ret < 0) - return ret; - } - } - - return ret; -} - -/* - * BE hw_params can be a source parameters (capture) or sink parameters - * (playback). Based on sink and source we need to either find the source - * list or the sink list and set the pipeline parameters - */ -int skl_tplg_be_update_params(struct snd_soc_dai *dai, - struct skl_pipe_params *params) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, params->stream); - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - return skl_tplg_be_set_src_pipe_params(dai, w, params); - } else { - return skl_tplg_be_set_sink_pipe_params(dai, w, params); - } -} - -static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { - {SKL_MIXER_EVENT, skl_tplg_mixer_event}, - {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, - {SKL_PGA_EVENT, skl_tplg_pga_event}, -}; - -static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { - {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, - skl_tplg_tlv_control_set}, -}; - -static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { - { - .id = SKL_CONTROL_TYPE_MIC_SELECT, - .get = skl_tplg_mic_control_get, - .put = skl_tplg_mic_control_set, - }, - { - .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT, - .get = skl_tplg_multi_config_get, - .put = skl_tplg_multi_config_set, - }, - { - .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC, - .get = skl_tplg_multi_config_get_dmic, - .put = skl_tplg_multi_config_set_dmic, - } -}; - -static int skl_tplg_fill_pipe_cfg(struct device *dev, - struct skl_pipe *pipe, u32 tkn, - u32 tkn_val, int conf_idx, int dir) -{ - struct skl_pipe_fmt *fmt; - struct skl_path_config *config; - - switch (dir) { - case SKL_DIR_IN: - fmt = &pipe->configs[conf_idx].in_fmt; - break; - - case SKL_DIR_OUT: - fmt = &pipe->configs[conf_idx].out_fmt; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - config = &pipe->configs[conf_idx]; - - switch (tkn) { - case SKL_TKN_U32_CFG_FREQ: - fmt->freq = tkn_val; - break; - - case SKL_TKN_U8_CFG_CHAN: - fmt->channels = tkn_val; - break; - - case SKL_TKN_U8_CFG_BPS: - fmt->bps = tkn_val; - break; - - case SKL_TKN_U32_PATH_MEM_PGS: - config->mem_pages = tkn_val; - break; - - default: - dev_err(dev, "Invalid token config: %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_fill_pipe_tkn(struct device *dev, - struct skl_pipe *pipe, u32 tkn, - u32 tkn_val) -{ - - switch (tkn) { - case SKL_TKN_U32_PIPE_CONN_TYPE: - pipe->conn_type = tkn_val; - break; - - case SKL_TKN_U32_PIPE_PRIORITY: - pipe->pipe_priority = tkn_val; - break; - - case SKL_TKN_U32_PIPE_MEM_PGS: - pipe->memory_pages = tkn_val; - break; - - case SKL_TKN_U32_PMODE: - pipe->lp_mode = tkn_val; - break; - - case SKL_TKN_U32_PIPE_DIRECTION: - pipe->direction = tkn_val; - break; - - case SKL_TKN_U32_NUM_CONFIGS: - pipe->nr_cfgs = tkn_val; - break; - - default: - dev_err(dev, "Token not handled %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -/* - * Add pipeline by parsing the relevant tokens - * Return an existing pipe if the pipe already exists. - */ -static int skl_tplg_add_pipe(struct device *dev, - struct skl_module_cfg *mconfig, struct skl_dev *skl, - struct snd_soc_tplg_vendor_value_elem *tkn_elem) -{ - struct skl_pipeline *ppl; - struct skl_pipe *pipe; - struct skl_pipe_params *params; - - list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == tkn_elem->value) { - mconfig->pipe = ppl->pipe; - return -EEXIST; - } - } - - ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); - if (!ppl) - return -ENOMEM; - - pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); - if (!pipe) - return -ENOMEM; - - params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - pipe->p_params = params; - pipe->ppl_id = tkn_elem->value; - INIT_LIST_HEAD(&pipe->w_list); - - ppl->pipe = pipe; - list_add(&ppl->node, &skl->ppl_list); - - mconfig->pipe = pipe; - mconfig->pipe->state = SKL_PIPE_INVALID; - - return 0; -} - -static int skl_tplg_get_uuid(struct device *dev, guid_t *guid, - struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) -{ - if (uuid_tkn->token == SKL_TKN_UUID) { - import_guid(guid, uuid_tkn->uuid); - return 0; - } - - dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token); - - return -EINVAL; -} - -static int skl_tplg_fill_pin(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_pin *m_pin, - int pin_index) -{ - int ret; - - switch (tkn_elem->token) { - case SKL_TKN_U32_PIN_MOD_ID: - m_pin[pin_index].id.module_id = tkn_elem->value; - break; - - case SKL_TKN_U32_PIN_INST_ID: - m_pin[pin_index].id.instance_id = tkn_elem->value; - break; - - case SKL_TKN_UUID: - ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid, - (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); - if (ret < 0) - return ret; - - break; - - default: - dev_err(dev, "%d Not a pin token\n", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - -/* - * Parse for pin config specific tokens to fill up the - * module private data - */ -static int skl_tplg_fill_pins_info(struct device *dev, - struct skl_module_cfg *mconfig, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - int dir, int pin_count) -{ - int ret; - struct skl_module_pin *m_pin; - - switch (dir) { - case SKL_DIR_IN: - m_pin = mconfig->m_in_pin; - break; - - case SKL_DIR_OUT: - m_pin = mconfig->m_out_pin; - break; - - default: - dev_err(dev, "Invalid direction value\n"); - return -EINVAL; - } - - ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count); - if (ret < 0) - return ret; - - m_pin[pin_count].in_use = false; - m_pin[pin_count].pin_state = SKL_PIN_UNBIND; - - return 0; -} - -/* - * Fill up input/output module config format based - * on the direction - */ -static int skl_tplg_fill_fmt(struct device *dev, - struct skl_module_fmt *dst_fmt, - u32 tkn, u32 value) -{ - switch (tkn) { - case SKL_TKN_U32_FMT_CH: - dst_fmt->channels = value; - break; - - case SKL_TKN_U32_FMT_FREQ: - dst_fmt->s_freq = value; - break; - - case SKL_TKN_U32_FMT_BIT_DEPTH: - dst_fmt->bit_depth = value; - break; - - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - dst_fmt->valid_bit_depth = value; - break; - - case SKL_TKN_U32_FMT_CH_CONFIG: - dst_fmt->ch_cfg = value; - break; - - case SKL_TKN_U32_FMT_INTERLEAVE: - dst_fmt->interleaving_style = value; - break; - - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - dst_fmt->sample_type = value; - break; - - case SKL_TKN_U32_FMT_CH_MAP: - dst_fmt->ch_map = value; - break; - - default: - dev_err(dev, "Invalid token %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_widget_fill_fmt(struct device *dev, - struct skl_module_iface *fmt, - u32 tkn, u32 val, u32 dir, int fmt_idx) -{ - struct skl_module_fmt *dst_fmt; - - if (!fmt) - return -EINVAL; - - switch (dir) { - case SKL_DIR_IN: - dst_fmt = &fmt->inputs[fmt_idx].fmt; - break; - - case SKL_DIR_OUT: - dst_fmt = &fmt->outputs[fmt_idx].fmt; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val); -} - -static void skl_tplg_fill_pin_dynamic_val( - struct skl_module_pin *mpin, u32 pin_count, u32 value) -{ - int i; - - for (i = 0; i < pin_count; i++) - mpin[i].is_dynamic = value; -} - -/* - * Resource table in the manifest has pin specific resources - * like pin and pin buffer size - */ -static int skl_tplg_manifest_pin_res_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_res *res, int pin_idx, int dir) -{ - struct skl_module_pin_resources *m_pin; - - switch (dir) { - case SKL_DIR_IN: - m_pin = &res->input[pin_idx]; - break; - - case SKL_DIR_OUT: - m_pin = &res->output[pin_idx]; - break; - - default: - dev_err(dev, "Invalid pin direction: %d\n", dir); - return -EINVAL; - } - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_RES_PIN_ID: - m_pin->pin_index = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_PIN_BUF: - m_pin->buf_size = tkn_elem->value; - break; - - default: - dev_err(dev, "Invalid token: %d\n", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - -/* - * Fill module specific resources from the manifest's resource - * table like CPS, DMA size, mem_pages. - */ -static int skl_tplg_fill_res_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_res *res, - int pin_idx, int dir) -{ - int ret, tkn_count = 0; - - if (!res) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_DMA_SIZE: - res->dma_buffer_size = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_CPC: - res->cpc = tkn_elem->value; - break; - - case SKL_TKN_U32_MEM_PAGES: - res->is_pages = tkn_elem->value; - break; - - case SKL_TKN_U32_OBS: - res->obs = tkn_elem->value; - break; - - case SKL_TKN_U32_IBS: - res->ibs = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_RES_PIN_ID: - case SKL_TKN_MM_U32_PIN_BUF: - ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, - pin_idx, dir); - if (ret < 0) - return ret; - break; - - case SKL_TKN_MM_U32_CPS: - case SKL_TKN_U32_MAX_MCPS: - /* ignore unused tokens */ - break; - - default: - dev_err(dev, "Not a res type token: %d", tkn_elem->token); - return -EINVAL; - - } - tkn_count++; - - return tkn_count; -} - -/* - * Parse tokens to fill up the module private data - */ -static int skl_tplg_get_token(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - int tkn_count = 0; - int ret; - static int is_pipe_exists; - static int pin_index, dir, conf_idx; - struct skl_module_iface *iface = NULL; - struct skl_module_res *res = NULL; - int res_idx = mconfig->res_idx; - int fmt_idx = mconfig->fmt_idx; - - /* - * If the manifest structure contains no modules, fill all - * the module data to 0th index. - * res_idx and fmt_idx are default set to 0. - */ - if (skl->nr_modules == 0) { - res = &mconfig->module->resources[res_idx]; - iface = &mconfig->module->formats[fmt_idx]; - } - - if (tkn_elem->token > SKL_TKN_MAX) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_U8_IN_QUEUE_COUNT: - mconfig->module->max_input_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_QUEUE_COUNT: - mconfig->module->max_output_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_DYN_IN_PIN: - if (!mconfig->m_in_pin) - mconfig->m_in_pin = - devm_kcalloc(dev, MAX_IN_QUEUE, - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_in_pin) - return -ENOMEM; - - skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE, - tkn_elem->value); - break; - - case SKL_TKN_U8_DYN_OUT_PIN: - if (!mconfig->m_out_pin) - mconfig->m_out_pin = - devm_kcalloc(dev, MAX_IN_QUEUE, - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_out_pin) - return -ENOMEM; - - skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE, - tkn_elem->value); - break; - - case SKL_TKN_U8_TIME_SLOT: - mconfig->time_slot = tkn_elem->value; - break; - - case SKL_TKN_U8_CORE_ID: - mconfig->core_id = tkn_elem->value; - break; - - case SKL_TKN_U8_MOD_TYPE: - mconfig->m_type = tkn_elem->value; - break; - - case SKL_TKN_U8_DEV_TYPE: - mconfig->dev_type = tkn_elem->value; - break; - - case SKL_TKN_U8_HW_CONN_TYPE: - mconfig->hw_conn_type = tkn_elem->value; - break; - - case SKL_TKN_U16_MOD_INST_ID: - mconfig->id.instance_id = - tkn_elem->value; - break; - - case SKL_TKN_U32_MEM_PAGES: - case SKL_TKN_U32_MAX_MCPS: - case SKL_TKN_U32_OBS: - case SKL_TKN_U32_IBS: - ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_VBUS_ID: - mconfig->vbus_id = tkn_elem->value; - break; - - case SKL_TKN_U32_PARAMS_FIXUP: - mconfig->params_fixup = tkn_elem->value; - break; - - case SKL_TKN_U32_CONVERTER: - mconfig->converter = tkn_elem->value; - break; - - case SKL_TKN_U32_D0I3_CAPS: - mconfig->d0i3_caps = tkn_elem->value; - break; - - case SKL_TKN_U32_PIPE_ID: - ret = skl_tplg_add_pipe(dev, - mconfig, skl, tkn_elem); - - if (ret < 0) { - if (ret == -EEXIST) { - is_pipe_exists = 1; - break; - } - return is_pipe_exists; - } - - break; - - case SKL_TKN_U32_PIPE_CONFIG_ID: - conf_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_PIPE_CONN_TYPE: - case SKL_TKN_U32_PIPE_PRIORITY: - case SKL_TKN_U32_PIPE_MEM_PGS: - case SKL_TKN_U32_PMODE: - case SKL_TKN_U32_PIPE_DIRECTION: - case SKL_TKN_U32_NUM_CONFIGS: - if (is_pipe_exists) { - ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, - tkn_elem->token, tkn_elem->value); - if (ret < 0) - return ret; - } - - break; - - case SKL_TKN_U32_PATH_MEM_PGS: - case SKL_TKN_U32_CFG_FREQ: - case SKL_TKN_U8_CFG_CHAN: - case SKL_TKN_U8_CFG_BPS: - if (mconfig->pipe->nr_cfgs) { - ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe, - tkn_elem->token, tkn_elem->value, - conf_idx, dir); - if (ret < 0) - return ret; - } - break; - - case SKL_TKN_CFG_MOD_RES_ID: - mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value; - break; - - case SKL_TKN_CFG_MOD_FMT_ID: - mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value; - break; - - /* - * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both - * direction and the pin count. The first four bits represent - * direction and next four the pin count. - */ - case SKL_TKN_U32_DIR_PIN_COUNT: - dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; - pin_index = (tkn_elem->value & - SKL_PIN_COUNT_MASK) >> 4; - - break; - - case SKL_TKN_U32_FMT_CH: - case SKL_TKN_U32_FMT_FREQ: - case SKL_TKN_U32_FMT_BIT_DEPTH: - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - case SKL_TKN_U32_FMT_CH_CONFIG: - case SKL_TKN_U32_FMT_INTERLEAVE: - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - case SKL_TKN_U32_FMT_CH_MAP: - ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token, - tkn_elem->value, dir, pin_index); - - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_PIN_MOD_ID: - case SKL_TKN_U32_PIN_INST_ID: - case SKL_TKN_UUID: - ret = skl_tplg_fill_pins_info(dev, - mconfig, tkn_elem, dir, - pin_index); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_FMT_CFG_IDX: - if (tkn_elem->value > SKL_MAX_PARAMS_TYPES) - return -EINVAL; - - mconfig->fmt_cfg_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_CAPS_SIZE: - mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size = - tkn_elem->value; - - break; - - case SKL_TKN_U32_CAPS_SET_PARAMS: - mconfig->formats_config[mconfig->fmt_cfg_idx].set_params = - tkn_elem->value; - break; - - case SKL_TKN_U32_CAPS_PARAMS_ID: - mconfig->formats_config[mconfig->fmt_cfg_idx].param_id = - tkn_elem->value; - break; - - case SKL_TKN_U32_PROC_DOMAIN: - mconfig->domain = - tkn_elem->value; - - break; - - case SKL_TKN_U32_DMA_BUF_SIZE: - mconfig->dma_buffer_size = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_PIN_TYPE: - case SKL_TKN_U8_OUT_PIN_TYPE: - case SKL_TKN_U8_CONN_TYPE: - break; - - default: - dev_err(dev, "Token %d not handled\n", - tkn_elem->token); - return -EINVAL; - } - - tkn_count++; - - return tkn_count; -} - -/* - * Parse the vendor array for specific tokens to construct - * module private data - */ -static int skl_tplg_get_tokens(struct device *dev, - char *pvt_data, struct skl_dev *skl, - struct skl_module_cfg *mconfig, int block_size) -{ - struct snd_soc_tplg_vendor_array *array; - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - int tkn_count = 0, ret; - int off = 0, tuple_size = 0; - bool is_module_guid = true; - - if (block_size <= 0) - return -EINVAL; - - while (tuple_size < block_size) { - array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); - - off += array->size; - - switch (array->type) { - case SND_SOC_TPLG_TUPLE_TYPE_STRING: - dev_warn(dev, "no string tokens expected for skl tplg\n"); - continue; - - case SND_SOC_TPLG_TUPLE_TYPE_UUID: - if (is_module_guid) { - ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid, - array->uuid); - is_module_guid = false; - } else { - ret = skl_tplg_get_token(dev, array->value, skl, - mconfig); - } - - if (ret < 0) - return ret; - - tuple_size += sizeof(*array->uuid); - - continue; - - default: - tkn_elem = array->value; - tkn_count = 0; - break; - } - - while (tkn_count <= (array->num_elems - 1)) { - ret = skl_tplg_get_token(dev, tkn_elem, - skl, mconfig); - - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - tkn_elem++; - } - - tuple_size += tkn_count * sizeof(*tkn_elem); - } - - return off; -} - -/* - * Every data block is preceded by a descriptor to read the number - * of data blocks, they type of the block and it's size - */ -static int skl_tplg_get_desc_blocks(struct device *dev, - struct snd_soc_tplg_vendor_array *array) -{ - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - - tkn_elem = array->value; - - switch (tkn_elem->token) { - case SKL_TKN_U8_NUM_BLOCKS: - case SKL_TKN_U8_BLOCK_TYPE: - case SKL_TKN_U16_BLOCK_SIZE: - return tkn_elem->value; - - default: - dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); - break; - } - - return -EINVAL; -} - -static int skl_tplg_get_caps_data(struct device *dev, char *data, - struct skl_module_cfg *mconfig) -{ - int idx = mconfig->fmt_cfg_idx; - - if (mconfig->formats_config[idx].caps_size > 0) { - mconfig->formats_config[idx].caps = - devm_kzalloc(dev, mconfig->formats_config[idx].caps_size, - GFP_KERNEL); - if (!mconfig->formats_config[idx].caps) - return -ENOMEM; - memcpy(mconfig->formats_config[idx].caps, data, - mconfig->formats_config[idx].caps_size); - } - - return mconfig->formats_config[idx].caps_size; -} - -/* - * Parse the private data for the token and corresponding value. - * The private data can have multiple data blocks. So, a data block - * is preceded by a descriptor for number of blocks and a descriptor - * for the type and size of the suceeding data block. - */ -static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl_dev *skl, struct device *dev, - struct skl_module_cfg *mconfig) -{ - struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size, block_type, off = 0; - char *data; - int ret; - - /* Read the NUM_DATA_BLOCKS descriptor */ - array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; - ret = skl_tplg_get_desc_blocks(dev, array); - if (ret < 0) - return ret; - num_blocks = ret; - - off += array->size; - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ - while (num_blocks > 0) { - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_type = ret; - off += array->size; - - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_size = ret; - off += array->size; - - data = (tplg_w->priv.data + off); - - if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_tokens(dev, data, - skl, mconfig, block_size); - } else { - ret = skl_tplg_get_caps_data(dev, data, mconfig); - } - - if (ret < 0) - return ret; - - --num_blocks; - off += ret; - } - - return 0; -} - -static void skl_clear_pin_config(struct snd_soc_component *component, - struct snd_soc_dapm_widget *w) -{ - int i; - struct skl_module_cfg *mconfig; - struct skl_pipe *pipe; - - if (!strncmp(w->dapm->component->name, component->name, - strlen(component->name))) { - mconfig = w->priv; - pipe = mconfig->pipe; - for (i = 0; i < mconfig->module->max_input_pins; i++) { - mconfig->m_in_pin[i].in_use = false; - mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; - } - for (i = 0; i < mconfig->module->max_output_pins; i++) { - mconfig->m_out_pin[i].in_use = false; - mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; - } - pipe->state = SKL_PIPE_INVALID; - mconfig->m_state = SKL_MODULE_UNINIT; - } -} - -void skl_cleanup_resources(struct skl_dev *skl) -{ - struct snd_soc_component *soc_component = skl->component; - struct snd_soc_dapm_widget *w; - struct snd_soc_card *card; - - if (soc_component == NULL) - return; - - card = soc_component->card; - if (!snd_soc_card_is_instantiated(card)) - return; - - list_for_each_entry(w, &card->widgets, list) { - if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) - skl_clear_pin_config(soc_component, w); - } - - skl_clear_module_cnt(skl->dsp); -} - -/* - * Topology core widget load callback - * - * This is used to save the private data for each widget which gives - * information to the driver about module and pipeline parameters which DSP - * FW expects like ids, resource values, formats etc - */ -static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, - struct snd_soc_dapm_widget *w, - struct snd_soc_tplg_dapm_widget *tplg_w) -{ - int ret; - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_cfg *mconfig; - - if (!tplg_w->priv.size) - goto bind_event; - - mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); - - if (!mconfig) - return -ENOMEM; - - if (skl->nr_modules == 0) { - mconfig->module = devm_kzalloc(bus->dev, - sizeof(*mconfig->module), GFP_KERNEL); - if (!mconfig->module) - return -ENOMEM; - } - - w->priv = mconfig; - - /* - * module binary can be loaded later, so set it to query when - * module is load for a use case - */ - mconfig->id.module_id = -1; - - /* To provide backward compatibility, set default as SKL_PARAM_INIT */ - mconfig->fmt_cfg_idx = SKL_PARAM_INIT; - - /* Parse private data for tuples */ - ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); - if (ret < 0) - return ret; - - skl_debug_init_module(skl->debugfs, w, mconfig); - -bind_event: - if (tplg_w->event_type == 0) { - dev_dbg(bus->dev, "ASoC: No event handler required\n"); - return 0; - } - - ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, - ARRAY_SIZE(skl_tplg_widget_ops), - tplg_w->event_type); - - if (ret) { - dev_err(bus->dev, "%s: No matching event handlers found for %d\n", - __func__, tplg_w->event_type); - return -EINVAL; - } - - return 0; -} - -static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, - struct snd_soc_tplg_bytes_control *bc) -{ - struct skl_algo_data *ac; - struct skl_dfw_algo_data *dfw_ac = - (struct skl_dfw_algo_data *)bc->priv.data; - - ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); - if (!ac) - return -ENOMEM; - - /* Fill private data */ - ac->max = dfw_ac->max; - ac->param_id = dfw_ac->param_id; - ac->set_params = dfw_ac->set_params; - ac->size = dfw_ac->max; - - if (ac->max) { - ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); - if (!ac->params) - return -ENOMEM; - - memcpy(ac->params, dfw_ac->params, ac->max); - } - - be->dobj.private = ac; - return 0; -} - -static int skl_init_enum_data(struct device *dev, struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) -{ - - void *data; - - if (ec->priv.size) { - data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); - if (!data) - return -ENOMEM; - memcpy(data, ec->priv.data, ec->priv.size); - se->dobj.private = data; - } - - return 0; - -} - -static int skl_tplg_control_load(struct snd_soc_component *cmpnt, - int index, - struct snd_kcontrol_new *kctl, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct soc_bytes_ext *sb; - struct snd_soc_tplg_bytes_control *tplg_bc; - struct snd_soc_tplg_enum_control *tplg_ec; - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct soc_enum *se; - - switch (hdr->ops.info) { - case SND_SOC_TPLG_CTL_BYTES: - tplg_bc = container_of(hdr, - struct snd_soc_tplg_bytes_control, hdr); - if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (struct soc_bytes_ext *)kctl->private_value; - if (tplg_bc->priv.size) - return skl_init_algo_data( - bus->dev, sb, tplg_bc); - } - break; - - case SND_SOC_TPLG_CTL_ENUM: - tplg_ec = container_of(hdr, - struct snd_soc_tplg_enum_control, hdr); - if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) { - se = (struct soc_enum *)kctl->private_value; - if (tplg_ec->priv.size) - skl_init_enum_data(bus->dev, se, tplg_ec); - } - - /* - * now that the control initializations are done, remove - * write permission for the DMIC configuration enums to - * avoid conflicts between NHLT settings and user interaction - */ - - if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC) - kctl->access = SNDRV_CTL_ELEM_ACCESS_READ; - - break; - - default: - dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n", - hdr->ops.get, hdr->ops.put, hdr->ops.info); - break; - } - - return 0; -} - -static int skl_tplg_fill_str_mfest_tkn(struct device *dev, - struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl_dev *skl) -{ - int tkn_count = 0; - static int ref_count; - - switch (str_elem->token) { - case SKL_TKN_STR_LIB_NAME: - if (ref_count > skl->lib_count - 1) { - ref_count = 0; - return -EINVAL; - } - - strncpy(skl->lib_info[ref_count].name, - str_elem->string, - ARRAY_SIZE(skl->lib_info[ref_count].name)); - ref_count++; - break; - - default: - dev_err(dev, "Not a string token %d\n", str_elem->token); - break; - } - tkn_count++; - - return tkn_count; -} - -static int skl_tplg_get_str_tkn(struct device *dev, - struct snd_soc_tplg_vendor_array *array, - struct skl_dev *skl) -{ - int tkn_count = 0, ret; - struct snd_soc_tplg_vendor_string_elem *str_elem; - - str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; - while (tkn_count < array->num_elems) { - ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); - str_elem++; - - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - } - - return tkn_count; -} - -static int skl_tplg_manifest_fill_fmt(struct device *dev, - struct skl_module_iface *fmt, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - u32 dir, int fmt_idx) -{ - struct skl_module_pin_fmt *dst_fmt; - struct skl_module_fmt *mod_fmt; - int ret; - - if (!fmt) - return -EINVAL; - - switch (dir) { - case SKL_DIR_IN: - dst_fmt = &fmt->inputs[fmt_idx]; - break; - - case SKL_DIR_OUT: - dst_fmt = &fmt->outputs[fmt_idx]; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - mod_fmt = &dst_fmt->fmt; - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_INTF_PIN_ID: - dst_fmt->id = tkn_elem->value; - break; - - default: - ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token, - tkn_elem->value); - if (ret < 0) - return ret; - break; - } - - return 0; -} - -static int skl_tplg_fill_mod_info(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module *mod) -{ - - if (!mod) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_U8_IN_PIN_TYPE: - mod->input_pin_type = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_PIN_TYPE: - mod->output_pin_type = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_QUEUE_COUNT: - mod->max_input_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_QUEUE_COUNT: - mod->max_output_pins = tkn_elem->value; - break; - - case SKL_TKN_MM_U8_NUM_RES: - mod->nr_resources = tkn_elem->value; - break; - - case SKL_TKN_MM_U8_NUM_INTF: - mod->nr_interfaces = tkn_elem->value; - break; - - default: - dev_err(dev, "Invalid mod info token %d", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - - -static int skl_tplg_get_int_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dev *skl) -{ - int tkn_count = 0, ret; - static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; - struct skl_module_res *res = NULL; - struct skl_module_iface *fmt = NULL; - struct skl_module *mod = NULL; - static struct skl_astate_param *astate_table; - static int astate_cfg_idx, count; - int i; - size_t size; - - if (skl->modules) { - mod = skl->modules[mod_idx]; - res = &mod->resources[res_val_idx]; - fmt = &mod->formats[intf_val_idx]; - } - - switch (tkn_elem->token) { - case SKL_TKN_U32_LIB_COUNT: - skl->lib_count = tkn_elem->value; - break; - - case SKL_TKN_U8_NUM_MOD: - skl->nr_modules = tkn_elem->value; - skl->modules = devm_kcalloc(dev, skl->nr_modules, - sizeof(*skl->modules), GFP_KERNEL); - if (!skl->modules) - return -ENOMEM; - - for (i = 0; i < skl->nr_modules; i++) { - skl->modules[i] = devm_kzalloc(dev, - sizeof(struct skl_module), GFP_KERNEL); - if (!skl->modules[i]) - return -ENOMEM; - } - break; - - case SKL_TKN_MM_U8_MOD_IDX: - mod_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_COUNT: - if (astate_table != NULL) { - dev_err(dev, "More than one entry for A-State count"); - return -EINVAL; - } - - if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { - dev_err(dev, "Invalid A-State count %d\n", - tkn_elem->value); - return -EINVAL; - } - - size = struct_size(skl->cfg.astate_cfg, astate_table, - tkn_elem->value); - skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); - if (!skl->cfg.astate_cfg) - return -ENOMEM; - - astate_table = skl->cfg.astate_cfg->astate_table; - count = skl->cfg.astate_cfg->count = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_IDX: - if (tkn_elem->value >= count) { - dev_err(dev, "Invalid A-State index %d\n", - tkn_elem->value); - return -EINVAL; - } - - astate_cfg_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_KCPS: - astate_table[astate_cfg_idx].kcps = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_CLK_SRC: - astate_table[astate_cfg_idx].clk_src = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_PIN_TYPE: - case SKL_TKN_U8_OUT_PIN_TYPE: - case SKL_TKN_U8_IN_QUEUE_COUNT: - case SKL_TKN_U8_OUT_QUEUE_COUNT: - case SKL_TKN_MM_U8_NUM_RES: - case SKL_TKN_MM_U8_NUM_INTF: - ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod); - if (ret < 0) - return ret; - break; - - case SKL_TKN_U32_DIR_PIN_COUNT: - dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; - pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4; - break; - - case SKL_TKN_MM_U32_RES_ID: - if (!res) - return -EINVAL; - - res->id = tkn_elem->value; - res_val_idx = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_FMT_ID: - if (!fmt) - return -EINVAL; - - fmt->fmt_idx = tkn_elem->value; - intf_val_idx = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_CPS: - case SKL_TKN_MM_U32_DMA_SIZE: - case SKL_TKN_MM_U32_CPC: - case SKL_TKN_U32_MEM_PAGES: - case SKL_TKN_U32_OBS: - case SKL_TKN_U32_IBS: - case SKL_TKN_MM_U32_RES_PIN_ID: - case SKL_TKN_MM_U32_PIN_BUF: - ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_MM_U32_NUM_IN_FMT: - if (!fmt) - return -EINVAL; - - res->nr_input_pins = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_NUM_OUT_FMT: - if (!fmt) - return -EINVAL; - - res->nr_output_pins = tkn_elem->value; - break; - - case SKL_TKN_U32_FMT_CH: - case SKL_TKN_U32_FMT_FREQ: - case SKL_TKN_U32_FMT_BIT_DEPTH: - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - case SKL_TKN_U32_FMT_CH_CONFIG: - case SKL_TKN_U32_FMT_INTERLEAVE: - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - case SKL_TKN_U32_FMT_CH_MAP: - case SKL_TKN_MM_U32_INTF_PIN_ID: - ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem, - dir, pin_idx); - if (ret < 0) - return ret; - break; - - default: - dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); - return -EINVAL; - } - tkn_count++; - - return tkn_count; -} - -/* - * Fill the manifest structure by parsing the tokens based on the - * type. - */ -static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl_dev *skl, - int block_size) -{ - int tkn_count = 0, ret; - int off = 0, tuple_size = 0; - u8 uuid_index = 0; - struct snd_soc_tplg_vendor_array *array; - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - - if (block_size <= 0) - return -EINVAL; - - while (tuple_size < block_size) { - array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); - off += array->size; - switch (array->type) { - case SND_SOC_TPLG_TUPLE_TYPE_STRING: - ret = skl_tplg_get_str_tkn(dev, array, skl); - - if (ret < 0) - return ret; - tkn_count = ret; - - tuple_size += tkn_count * - sizeof(struct snd_soc_tplg_vendor_string_elem); - continue; - - case SND_SOC_TPLG_TUPLE_TYPE_UUID: - if (array->uuid->token != SKL_TKN_UUID) { - dev_err(dev, "Not an UUID token: %d\n", - array->uuid->token); - return -EINVAL; - } - if (uuid_index >= skl->nr_modules) { - dev_err(dev, "Too many UUID tokens\n"); - return -EINVAL; - } - import_guid(&skl->modules[uuid_index++]->uuid, - array->uuid->uuid); - - tuple_size += sizeof(*array->uuid); - continue; - - default: - tkn_elem = array->value; - tkn_count = 0; - break; - } - - while (tkn_count <= array->num_elems - 1) { - ret = skl_tplg_get_int_tkn(dev, - tkn_elem, skl); - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - tkn_elem++; - } - tuple_size += (tkn_count * sizeof(*tkn_elem)); - tkn_count = 0; - } - - return off; -} - -/* - * Parse manifest private data for tokens. The private data block is - * preceded by descriptors for type and size of data block. - */ -static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl_dev *skl) -{ - struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size = 0, block_type, off = 0; - char *data; - int ret; - - /* Read the NUM_DATA_BLOCKS descriptor */ - array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; - ret = skl_tplg_get_desc_blocks(dev, array); - if (ret < 0) - return ret; - num_blocks = ret; - - off += array->size; - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ - while (num_blocks > 0) { - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_type = ret; - off += array->size; - - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_size = ret; - off += array->size; - - data = (manifest->priv.data + off); - - if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_manifest_tkn(dev, data, skl, - block_size); - - if (ret < 0) - return ret; - - --num_blocks; - } else { - return -EINVAL; - } - off += ret; - } - - return 0; -} - -static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, - struct snd_soc_tplg_manifest *manifest) -{ - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl_dev *skl = bus_to_skl(bus); - - /* proceed only if we have private data defined */ - if (manifest->priv.size == 0) - return 0; - - skl_tplg_get_manifest_data(manifest, bus->dev, skl); - - if (skl->lib_count > SKL_MAX_LIB) { - dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - skl->lib_count); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_complete(struct snd_soc_component *component) -{ - struct snd_soc_dobj *dobj; - struct snd_soc_acpi_mach *mach; - struct snd_ctl_elem_value *val; - int i; - - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (!val) - return -ENOMEM; - - mach = dev_get_platdata(component->card->dev); - list_for_each_entry(dobj, &component->dobj_list, list) { - struct snd_kcontrol *kcontrol = dobj->control.kcontrol; - struct soc_enum *se; - char **texts; - char chan_text[4]; - - if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol || - kcontrol->put != skl_tplg_multi_config_set_dmic) - continue; - - se = (struct soc_enum *)kcontrol->private_value; - texts = dobj->control.dtexts; - sprintf(chan_text, "c%d", mach->mach_params.dmic_num); - - for (i = 0; i < se->items; i++) { - if (strstr(texts[i], chan_text)) { - memset(val, 0, sizeof(*val)); - val->value.enumerated.item[0] = i; - kcontrol->put(kcontrol, val); - } - } - } - - kfree(val); - return 0; -} - -static const struct snd_soc_tplg_ops skl_tplg_ops = { - .widget_load = skl_tplg_widget_load, - .control_load = skl_tplg_control_load, - .bytes_ext_ops = skl_tlv_ops, - .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), - .io_ops = skl_tplg_kcontrol_ops, - .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), - .manifest = skl_manifest_load, - .dai_load = skl_dai_load, - .complete = skl_tplg_complete, -}; - -/* - * A pipe can have multiple modules, each of them will be a DAPM widget as - * well. While managing a pipeline we need to get the list of all the - * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() - * helps to get the SKL type widgets in that pipeline - */ -static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) -{ - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mcfg = NULL; - struct skl_pipe_module *p_module = NULL; - struct skl_pipe *pipe; - - list_for_each_entry(w, &component->card->widgets, list) { - if (is_skl_dsp_widget_type(w, component->dev) && w->priv) { - mcfg = w->priv; - pipe = mcfg->pipe; - - p_module = devm_kzalloc(component->dev, - sizeof(*p_module), GFP_KERNEL); - if (!p_module) - return -ENOMEM; - - p_module->w = w; - list_add_tail(&p_module->node, &pipe->w_list); - } - } - - return 0; -} - -static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) -{ - struct skl_pipe_module *w_module; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - bool host_found = false, link_found = false; - - list_for_each_entry(w_module, &pipe->w_list, node) { - w = w_module->w; - mconfig = w->priv; - - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - host_found = true; - else if (mconfig->dev_type != SKL_DEVICE_NONE) - link_found = true; - } - - if (host_found && link_found) - pipe->passthru = true; - else - pipe->passthru = false; -} - -/* - * SKL topology init routine - */ -int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) -{ - int ret; - const struct firmware *fw; - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl; - - ret = request_firmware(&fw, skl->tplg_name, bus->dev); - if (ret < 0) { - char alt_tplg_name[64]; - - snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin", - skl->mach->drv_name); - dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s", - skl->tplg_name, ret, alt_tplg_name); - - ret = request_firmware(&fw, alt_tplg_name, bus->dev); - if (!ret) - goto component_load; - - dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin", - alt_tplg_name, ret); - - ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); - if (ret < 0) { - dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", - "dfw_sst.bin", ret); - return ret; - } - } - -component_load: - ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw); - if (ret < 0) { - dev_err(bus->dev, "tplg component load failed%d\n", ret); - goto err; - } - - ret = skl_tplg_create_pipe_widget_list(component); - if (ret < 0) { - dev_err(bus->dev, "tplg create pipe widget list failed%d\n", - ret); - goto err; - } - - list_for_each_entry(ppl, &skl->ppl_list, node) - skl_tplg_set_pipe_type(skl, ppl->pipe); - -err: - release_firmware(fw); - return ret; -} - -void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl, *tmp; - - list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) - list_del(&ppl->node); - - /* clean up topology */ - snd_soc_tplg_component_remove(component); -} diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h deleted file mode 100644 index 30a0977af943..000000000000 --- a/sound/soc/intel/skylake/skl-topology.h +++ /dev/null @@ -1,524 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl_topology.h - Intel HDA Platform topology header file - * - * Copyright (C) 2014-15 Intel Corp - * Author: Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SKL_TOPOLOGY_H__ -#define __SKL_TOPOLOGY_H__ - -#include - -#include -#include -#include -#include "skl.h" - -#define BITS_PER_BYTE 8 -#define MAX_TS_GROUPS 8 -#define MAX_DMIC_TS_GROUPS 4 -#define MAX_FIXED_DMIC_PARAMS_SIZE 727 - -/* Maximum number of coefficients up down mixer module */ -#define UP_DOWN_MIXER_MAX_COEFF 8 - -#define MODULE_MAX_IN_PINS 8 -#define MODULE_MAX_OUT_PINS 8 - -#define SKL_MIC_CH_SUPPORT 4 -#define SKL_MIC_MAX_CH_SUPPORT 8 -#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF -#define SKL_MIC_SEL_SWITCH 0x3 - -#define SKL_OUTPUT_PIN 0 -#define SKL_INPUT_PIN 1 -#define SKL_MAX_PATH_CONFIGS 8 -#define SKL_MAX_MODULES_IN_PIPE 8 -#define SKL_MAX_MODULE_FORMATS 32 -#define SKL_MAX_MODULE_RESOURCES 32 - -enum skl_channel_index { - SKL_CHANNEL_LEFT = 0, - SKL_CHANNEL_RIGHT = 1, - SKL_CHANNEL_CENTER = 2, - SKL_CHANNEL_LEFT_SURROUND = 3, - SKL_CHANNEL_CENTER_SURROUND = 3, - SKL_CHANNEL_RIGHT_SURROUND = 4, - SKL_CHANNEL_LFE = 7, - SKL_CHANNEL_INVALID = 0xF, -}; - -enum skl_bitdepth { - SKL_DEPTH_8BIT = 8, - SKL_DEPTH_16BIT = 16, - SKL_DEPTH_24BIT = 24, - SKL_DEPTH_32BIT = 32, - SKL_DEPTH_INVALID -}; - - -enum skl_s_freq { - SKL_FS_8000 = 8000, - SKL_FS_11025 = 11025, - SKL_FS_12000 = 12000, - SKL_FS_16000 = 16000, - SKL_FS_22050 = 22050, - SKL_FS_24000 = 24000, - SKL_FS_32000 = 32000, - SKL_FS_44100 = 44100, - SKL_FS_48000 = 48000, - SKL_FS_64000 = 64000, - SKL_FS_88200 = 88200, - SKL_FS_96000 = 96000, - SKL_FS_128000 = 128000, - SKL_FS_176400 = 176400, - SKL_FS_192000 = 192000, - SKL_FS_INVALID -}; - -#define SKL_MAX_PARAMS_TYPES 4 - -enum skl_widget_type { - SKL_WIDGET_VMIXER = 1, - SKL_WIDGET_MIXER = 2, - SKL_WIDGET_PGA = 3, - SKL_WIDGET_MUX = 4 -}; - -struct skl_audio_data_format { - enum skl_s_freq s_freq; - enum skl_bitdepth bit_depth; - u32 channel_map; - enum skl_ch_cfg ch_cfg; - enum skl_interleaving interleaving; - u8 number_of_channels; - u8 valid_bit_depth; - u8 sample_type; - u8 reserved; -} __packed; - -struct skl_base_cfg { - u32 cpc; - u32 ibs; - u32 obs; - u32 is_pages; - struct skl_audio_data_format audio_fmt; -}; - -struct skl_cpr_gtw_cfg { - u32 node_id; - u32 dma_buffer_size; - u32 config_length; - /* not mandatory; required only for DMIC/I2S */ - struct { - u32 gtw_attrs; - u32 data[]; - } config_data; -} __packed; - -struct skl_dma_control { - u32 node_id; - u32 config_length; - u32 config_data[]; -} __packed; - -struct skl_cpr_cfg { - struct skl_base_cfg base_cfg; - struct skl_audio_data_format out_fmt; - u32 cpr_feature_mask; - struct skl_cpr_gtw_cfg gtw_cfg; -} __packed; - -struct skl_cpr_pin_fmt { - u32 sink_id; - struct skl_audio_data_format src_fmt; - struct skl_audio_data_format dst_fmt; -} __packed; - -struct skl_src_module_cfg { - struct skl_base_cfg base_cfg; - enum skl_s_freq src_cfg; -} __packed; - -struct skl_up_down_mixer_cfg { - struct skl_base_cfg base_cfg; - enum skl_ch_cfg out_ch_cfg; - /* This should be set to 1 if user coefficients are required */ - u32 coeff_sel; - /* Pass the user coeff in this array */ - s32 coeff[UP_DOWN_MIXER_MAX_COEFF]; - u32 ch_map; -} __packed; - -struct skl_pin_format { - u32 pin_idx; - u32 buf_size; - struct skl_audio_data_format audio_fmt; -} __packed; - -struct skl_base_cfg_ext { - u16 nr_input_pins; - u16 nr_output_pins; - u8 reserved[8]; - u32 priv_param_length; - /* Input pin formats followed by output ones. */ - struct skl_pin_format pins_fmt[]; -} __packed; - -struct skl_algo_cfg { - struct skl_base_cfg base_cfg; - char params[]; -} __packed; - -struct skl_base_outfmt_cfg { - struct skl_base_cfg base_cfg; - struct skl_audio_data_format out_fmt; -} __packed; - -enum skl_dma_type { - SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, - SKL_DMA_HDA_HOST_INPUT_CLASS = 1, - SKL_DMA_HDA_HOST_INOUT_CLASS = 2, - SKL_DMA_HDA_LINK_OUTPUT_CLASS = 8, - SKL_DMA_HDA_LINK_INPUT_CLASS = 9, - SKL_DMA_HDA_LINK_INOUT_CLASS = 0xA, - SKL_DMA_DMIC_LINK_INPUT_CLASS = 0xB, - SKL_DMA_I2S_LINK_OUTPUT_CLASS = 0xC, - SKL_DMA_I2S_LINK_INPUT_CLASS = 0xD, -}; - -union skl_ssp_dma_node { - u8 val; - struct { - u8 time_slot_index:4; - u8 i2s_instance:4; - } dma_node; -}; - -union skl_connector_node_id { - u32 val; - struct { - u32 vindex:8; - u32 dma_type:4; - u32 rsvd:20; - } node; -}; - -struct skl_module_fmt { - u32 channels; - u32 s_freq; - u32 bit_depth; - u32 valid_bit_depth; - u32 ch_cfg; - u32 interleaving_style; - u32 sample_type; - u32 ch_map; -}; - -struct skl_module_cfg; - -struct skl_mod_inst_map { - u16 mod_id; - u16 inst_id; -}; - -struct skl_uuid_inst_map { - u16 inst_id; - u16 reserved; - guid_t mod_uuid; -} __packed; - -struct skl_kpb_params { - u32 num_modules; - union { - DECLARE_FLEX_ARRAY(struct skl_mod_inst_map, map); - DECLARE_FLEX_ARRAY(struct skl_uuid_inst_map, map_uuid); - } u; -}; - -struct skl_module_inst_id { - guid_t mod_uuid; - int module_id; - u32 instance_id; - int pvt_id; -}; - -enum skl_module_pin_state { - SKL_PIN_UNBIND = 0, - SKL_PIN_BIND_DONE = 1, -}; - -struct skl_module_pin { - struct skl_module_inst_id id; - bool is_dynamic; - bool in_use; - enum skl_module_pin_state pin_state; - struct skl_module_cfg *tgt_mcfg; -}; - -struct skl_specific_cfg { - u32 set_params; - u32 param_id; - u32 caps_size; - u32 *caps; -}; - -enum skl_pipe_state { - SKL_PIPE_INVALID = 0, - SKL_PIPE_CREATED = 1, - SKL_PIPE_PAUSED = 2, - SKL_PIPE_STARTED = 3, - SKL_PIPE_RESET = 4 -}; - -struct skl_pipe_module { - struct snd_soc_dapm_widget *w; - struct list_head node; -}; - -struct skl_pipe_params { - u8 host_dma_id; - u8 link_dma_id; - u32 ch; - u32 s_freq; - u32 s_fmt; - u32 s_cont; - u8 linktype; - snd_pcm_format_t format; - int link_index; - int stream; - unsigned int host_bps; - unsigned int link_bps; -}; - -struct skl_pipe_fmt { - u32 freq; - u8 channels; - u8 bps; -}; - -struct skl_pipe_mcfg { - u8 res_idx; - u8 fmt_idx; -}; - -struct skl_path_config { - u8 mem_pages; - struct skl_pipe_fmt in_fmt; - struct skl_pipe_fmt out_fmt; -}; - -struct skl_pipe { - u8 ppl_id; - u8 pipe_priority; - u16 conn_type; - u32 memory_pages; - u8 lp_mode; - struct skl_pipe_params *p_params; - enum skl_pipe_state state; - u8 direction; - u8 cur_config_idx; - u8 nr_cfgs; - struct skl_path_config configs[SKL_MAX_PATH_CONFIGS]; - struct list_head w_list; - bool passthru; -}; - -enum skl_module_state { - SKL_MODULE_UNINIT = 0, - SKL_MODULE_INIT_DONE = 1, - SKL_MODULE_BIND_DONE = 2, -}; - -enum d0i3_capability { - SKL_D0I3_NONE = 0, - SKL_D0I3_STREAMING = 1, - SKL_D0I3_NON_STREAMING = 2, -}; - -struct skl_module_pin_fmt { - u8 id; - struct skl_module_fmt fmt; -}; - -struct skl_module_iface { - u8 fmt_idx; - u8 nr_in_fmt; - u8 nr_out_fmt; - struct skl_module_pin_fmt inputs[MAX_IN_QUEUE]; - struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE]; -}; - -struct skl_module_pin_resources { - u8 pin_index; - u32 buf_size; -}; - -struct skl_module_res { - u8 id; - u32 is_pages; - u32 ibs; - u32 obs; - u32 dma_buffer_size; - u32 cpc; - u8 nr_input_pins; - u8 nr_output_pins; - struct skl_module_pin_resources input[MAX_IN_QUEUE]; - struct skl_module_pin_resources output[MAX_OUT_QUEUE]; -}; - -struct skl_module { - guid_t uuid; - u8 loadable; - u8 input_pin_type; - u8 output_pin_type; - u8 max_input_pins; - u8 max_output_pins; - u8 nr_resources; - u8 nr_interfaces; - struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES]; - struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS]; -}; - -struct skl_module_cfg { - u8 guid[16]; - struct skl_module_inst_id id; - struct skl_module *module; - int res_idx; - int fmt_idx; - int fmt_cfg_idx; - u8 domain; - bool homogenous_inputs; - bool homogenous_outputs; - struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS]; - struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS]; - u8 max_in_queue; - u8 max_out_queue; - u8 in_queue_mask; - u8 out_queue_mask; - u8 in_queue; - u8 out_queue; - u8 is_loadable; - u8 core_id; - u8 dev_type; - u8 dma_id; - u8 time_slot; - u8 dmic_ch_combo_index; - u32 dmic_ch_type; - u32 params_fixup; - u32 converter; - u32 vbus_id; - u32 mem_pages; - enum d0i3_capability d0i3_caps; - u32 dma_buffer_size; /* in milli seconds */ - struct skl_module_pin *m_in_pin; - struct skl_module_pin *m_out_pin; - enum skl_module_type m_type; - enum skl_hw_conn_type hw_conn_type; - enum skl_module_state m_state; - struct skl_pipe *pipe; - struct skl_specific_cfg formats_config[SKL_MAX_PARAMS_TYPES]; - struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE]; -}; - -struct skl_algo_data { - u32 param_id; - u32 set_params; - u32 max; - u32 size; - char *params; -}; - -struct skl_pipeline { - struct skl_pipe *pipe; - struct list_head node; -}; - -struct skl_module_deferred_bind { - struct skl_module_cfg *src; - struct skl_module_cfg *dst; - struct list_head node; -}; - -struct skl_mic_sel_config { - u16 mic_switch; - u16 flags; - u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT]; -} __packed; - -enum skl_channel { - SKL_CH_MONO = 1, - SKL_CH_STEREO = 2, - SKL_CH_TRIO = 3, - SKL_CH_QUATRO = 4, -}; - -static inline struct skl_dev *get_skl_ctx(struct device *dev) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - - return bus_to_skl(bus); -} - -int skl_tplg_be_update_params(struct snd_soc_dai *dai, - struct skl_pipe_params *params); -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id); -void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, - struct skl_pipe_params *params, int stream); -int skl_tplg_init(struct snd_soc_component *component, - struct hdac_bus *bus); -void skl_tplg_exit(struct snd_soc_component *component, - struct hdac_bus *bus); -struct skl_module_cfg *skl_tplg_fe_get_cpr_module( - struct snd_soc_dai *dai, int stream); -int skl_tplg_update_pipe_params(struct device *dev, - struct skl_module_cfg *mconfig, struct skl_pipe_params *params); - -void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps); -void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps); - -int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_pause_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig); - -int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_mcfg, struct skl_module_cfg *dst_mcfg); - -int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_mcfg, struct skl_module_cfg *dst_mcfg); - -int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg); -int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg); - -struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, - int stream); -enum skl_bitdepth skl_get_bit_depth(int params); -int skl_pcm_host_dma_prepare(struct device *dev, - struct skl_pipe_params *params); -int skl_pcm_link_dma_prepare(struct device *dev, - struct skl_pipe_params *params); - -int skl_dai_load(struct snd_soc_component *cmp, int index, - struct snd_soc_dai_driver *dai_drv, - struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai); -void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, - struct snd_soc_dapm_widget *w); -#endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c deleted file mode 100644 index 117125187793..000000000000 --- a/sound/soc/intel/skylake/skl.c +++ /dev/null @@ -1,1177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl.c - Implementation of ASoC Intel SKL HD Audio driver - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP - * - * Derived mostly from Intel HDA driver with following copyrights: - * Copyright (c) 2004 Takashi Iwai - * PeiSen Hou - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) -#include "../../../soc/codecs/hdac_hda.h" -#endif -static int skl_pci_binding; -module_param_named(pci_binding, skl_pci_binding, int, 0444); -MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); - -/* - * initialize the PCI registers - */ -static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, - unsigned char mask, unsigned char val) -{ - unsigned char data; - - pci_read_config_byte(pci, reg, &data); - data &= ~mask; - data |= (val & mask); - pci_write_config_byte(pci, reg, data); -} - -static void skl_init_pci(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - - /* - * Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs. - * The PCI register TCSEL is defined in the Intel manuals. - */ - dev_dbg(bus->dev, "Clearing TCSEL\n"); - skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); -} - -static void update_pci_dword(struct pci_dev *pci, - unsigned int reg, u32 mask, u32 val) -{ - u32 data = 0; - - pci_read_config_dword(pci, reg, &data); - data &= ~mask; - data |= (val & mask); - pci_write_config_dword(pci, reg, data); -} - -/* - * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits - * - * @dev: device pointer - * @enable: enable/disable flag - */ -static void skl_enable_miscbdcge(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - u32 val; - - val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; - - update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); -} - -/** - * skl_clock_power_gating: Enable/Disable clock and power gating - * - * @dev: Device pointer - * @enable: Enable/Disable flag - */ -static void skl_clock_power_gating(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - u32 val; - - /* Update PDCGE bit of CGCTL register */ - val = enable ? AZX_CGCTL_ADSPDCGE : 0; - update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_ADSPDCGE, val); - - /* Update L1SEN bit of EM2 register */ - val = enable ? AZX_REG_VS_EM2_L1SEN : 0; - snd_hdac_chip_updatel(bus, VS_EM2, AZX_REG_VS_EM2_L1SEN, val); - - /* Update ADSPPGD bit of PGCTL register */ - val = enable ? 0 : AZX_PGCTL_ADSPPGD; - update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val); -} - -/* - * While performing reset, controller may not come back properly causing - * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset - * (init chip) and then again set CGCTL.MISCBDCGE to 1 - */ -static int skl_init_chip(struct hdac_bus *bus, bool full_reset) -{ - struct hdac_ext_link *hlink; - int ret; - - snd_hdac_set_codec_wakeup(bus, true); - skl_enable_miscbdcge(bus->dev, false); - ret = snd_hdac_bus_init_chip(bus, full_reset); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - skl_enable_miscbdcge(bus->dev, true); - snd_hdac_set_codec_wakeup(bus, false); - - return ret; -} - -void skl_update_d0i3c(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - u8 reg; - int timeout = 50; - - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - /* Do not write to D0I3C until command in progress bit is cleared */ - while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { - udelay(10); - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - } - - /* Highly unlikely. But if it happens, flag error explicitly */ - if (!timeout) { - dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); - return; - } - - if (enable) - reg = reg | AZX_REG_VS_D0I3C_I3; - else - reg = reg & (~AZX_REG_VS_D0I3C_I3); - - snd_hdac_chip_writeb(bus, VS_D0I3C, reg); - - timeout = 50; - /* Wait for cmd in progress to be cleared before exiting the function */ - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { - udelay(10); - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - } - - /* Highly unlikely. But if it happens, flag error explicitly */ - if (!timeout) { - dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); - return; - } - - dev_dbg(bus->dev, "D0I3C register = 0x%x\n", - snd_hdac_chip_readb(bus, VS_D0I3C)); -} - -/** - * skl_dum_set - set DUM bit in EM2 register - * @bus: HD-audio core bus - * - * Addresses incorrect position reporting for capture streams. - * Used on device power up. - */ -static void skl_dum_set(struct hdac_bus *bus) -{ - /* For the DUM bit to be set, CRST needs to be out of reset state */ - if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) { - skl_enable_miscbdcge(bus->dev, false); - snd_hdac_bus_exit_link_reset(bus); - skl_enable_miscbdcge(bus->dev, true); - } - - snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); -} - -/* called from IRQ */ -static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) -{ - snd_pcm_period_elapsed(hstr->substream); -} - -static irqreturn_t skl_interrupt(int irq, void *dev_id) -{ - struct hdac_bus *bus = dev_id; - u32 status; - - if (!pm_runtime_active(bus->dev)) - return IRQ_NONE; - - spin_lock(&bus->reg_lock); - - status = snd_hdac_chip_readl(bus, INTSTS); - if (status == 0 || status == 0xffffffff) { - spin_unlock(&bus->reg_lock); - return IRQ_NONE; - } - - /* clear rirb int */ - status = snd_hdac_chip_readb(bus, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) - snd_hdac_bus_update_rirb(bus); - snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); - } - - spin_unlock(&bus->reg_lock); - - return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; -} - -static irqreturn_t skl_threaded_handler(int irq, void *dev_id) -{ - struct hdac_bus *bus = dev_id; - u32 status; - - status = snd_hdac_chip_readl(bus, INTSTS); - - snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update); - - return IRQ_HANDLED; -} - -static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect) -{ - struct skl_dev *skl = bus_to_skl(bus); - int ret; - - ret = request_threaded_irq(skl->pci->irq, skl_interrupt, - skl_threaded_handler, - IRQF_SHARED, - KBUILD_MODNAME, bus); - if (ret) { - dev_err(bus->dev, - "unable to grab IRQ %d, disabling device\n", - skl->pci->irq); - return ret; - } - - bus->irq = skl->pci->irq; - pci_intx(skl->pci, 1); - - return 0; -} - -static int skl_suspend_late(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - - return skl_suspend_late_dsp(skl); -} - -#ifdef CONFIG_PM -static int _skl_suspend(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct pci_dev *pci = to_pci_dev(bus->dev); - int ret; - - snd_hdac_ext_bus_link_power_down_all(bus); - - ret = skl_suspend_dsp(skl); - if (ret < 0) - return ret; - - snd_hdac_bus_stop_chip(bus); - update_pci_dword(pci, AZX_PCIREG_PGCTL, - AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK); - skl_enable_miscbdcge(bus->dev, false); - snd_hdac_bus_enter_link_reset(bus); - skl_enable_miscbdcge(bus->dev, true); - skl_cleanup_resources(skl); - - return 0; -} - -static int _skl_resume(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - - skl_init_pci(skl); - skl_dum_set(bus); - skl_init_chip(bus, true); - - return skl_resume_dsp(skl); -} -#endif - -#ifdef CONFIG_PM_SLEEP -/* - * power management - */ -static int skl_suspend(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - int ret; - - /* - * Do not suspend if streams which are marked ignore suspend are - * running, we need to save the state for these and continue - */ - if (skl->supend_active) { - /* turn off the links and stop the CORB/RIRB DMA if it is On */ - snd_hdac_ext_bus_link_power_down_all(bus); - - if (bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); - - enable_irq_wake(bus->irq); - pci_save_state(pci); - } else { - ret = _skl_suspend(bus); - if (ret < 0) - return ret; - skl->fw_loaded = false; - } - - return 0; -} - -static int skl_resume(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - struct hdac_ext_link *hlink; - int ret; - - /* - * resume only when we are not in suspend active, otherwise need to - * restore the device - */ - if (skl->supend_active) { - pci_restore_state(pci); - snd_hdac_ext_bus_link_power_up_all(bus); - disable_irq_wake(bus->irq); - /* - * turn On the links which are On before active suspend - * and start the CORB/RIRB DMA if On before - * active suspend. - */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (hlink->ref_count) - snd_hdac_ext_bus_link_power_up(hlink); - } - - ret = 0; - if (bus->cmd_dma_state) - snd_hdac_bus_init_cmd_io(bus); - } else { - ret = _skl_resume(bus); - } - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM -static int skl_runtime_suspend(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - - dev_dbg(bus->dev, "in %s\n", __func__); - - return _skl_suspend(bus); -} - -static int skl_runtime_resume(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - - dev_dbg(bus->dev, "in %s\n", __func__); - - return _skl_resume(bus); -} -#endif /* CONFIG_PM */ - -static const struct dev_pm_ops skl_pm = { - SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) - SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) - .suspend_late = skl_suspend_late, -}; - -/* - * destructor - */ -static int skl_free(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - - skl->init_done = 0; /* to be sure */ - - snd_hdac_stop_streams_and_chip(bus); - - if (bus->irq >= 0) - free_irq(bus->irq, (void *)bus); - snd_hdac_bus_free_stream_pages(bus); - snd_hdac_ext_stream_free_all(bus); - snd_hdac_ext_link_free_all(bus); - - if (bus->remap_addr) - iounmap(bus->remap_addr); - - pci_release_regions(skl->pci); - pci_disable_device(skl->pci); - - snd_hdac_ext_bus_exit(bus); - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - snd_hdac_i915_exit(bus); - } - - return 0; -} - -/* - * For each ssp there are 3 clocks (mclk/sclk/sclkfs). - * e.g. for ssp0, clocks will be named as - * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs" - * So for skl+, there are 6 ssps, so 18 clocks will be created. - */ -static struct skl_ssp_clk skl_ssp_clks[] = { - {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"}, - {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"}, - {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"}, - {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"}, - {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"}, - {.name = "ssp2_sclkfs"}, - {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"}, - {.name = "ssp5_sclkfs"}, -}; - -static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl, - struct snd_soc_acpi_mach *machines) -{ - struct snd_soc_acpi_mach *mach; - - /* point to common table */ - mach = snd_soc_acpi_intel_hda_machines; - - /* all entries in the machine table use the same firmware */ - mach->fw_filename = machines->fw_filename; - - return mach; -} - -static int skl_find_machine(struct skl_dev *skl, void *driver_data) -{ - struct hdac_bus *bus = skl_to_bus(skl); - struct snd_soc_acpi_mach *mach = driver_data; - struct skl_machine_pdata *pdata; - - mach = snd_soc_acpi_find_machine(mach); - if (!mach) { - dev_dbg(bus->dev, "No matching I2S machine driver found\n"); - mach = skl_find_hda_machine(skl, driver_data); - if (!mach) { - dev_err(bus->dev, "No matching machine driver found\n"); - return -ENODEV; - } - } - - skl->mach = mach; - skl->fw_name = mach->fw_filename; - pdata = mach->pdata; - - if (pdata) { - skl->use_tplg_pcm = pdata->use_tplg_pcm; - mach->mach_params.dmic_num = - intel_nhlt_get_dmic_geo(&skl->pci->dev, - skl->nhlt); - } - - return 0; -} - -static int skl_machine_device_register(struct skl_dev *skl) -{ - struct snd_soc_acpi_mach *mach = skl->mach; - struct hdac_bus *bus = skl_to_bus(skl); - struct platform_device *pdev; - int ret; - - pdev = platform_device_alloc(mach->drv_name, -1); - if (pdev == NULL) { - dev_err(bus->dev, "platform device alloc failed\n"); - return -EIO; - } - - mach->mach_params.platform = dev_name(bus->dev); - mach->mach_params.codec_mask = bus->codec_mask; - - ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); - if (ret) { - dev_err(bus->dev, "failed to add machine device platform data\n"); - platform_device_put(pdev); - return ret; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(bus->dev, "failed to add machine device\n"); - platform_device_put(pdev); - return -EIO; - } - - - skl->i2s_dev = pdev; - - return 0; -} - -static void skl_machine_device_unregister(struct skl_dev *skl) -{ - if (skl->i2s_dev) - platform_device_unregister(skl->i2s_dev); -} - -static int skl_dmic_device_register(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - struct platform_device *pdev; - int ret; - - /* SKL has one dmic port, so allocate dmic device for this */ - pdev = platform_device_alloc("dmic-codec", -1); - if (!pdev) { - dev_err(bus->dev, "failed to allocate dmic device\n"); - return -ENOMEM; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(bus->dev, "failed to add dmic device: %d\n", ret); - platform_device_put(pdev); - return ret; - } - skl->dmic_dev = pdev; - - return 0; -} - -static void skl_dmic_device_unregister(struct skl_dev *skl) -{ - if (skl->dmic_dev) - platform_device_unregister(skl->dmic_dev); -} - -static struct skl_clk_parent_src skl_clk_src[] = { - { .clk_id = SKL_XTAL, .name = "xtal" }, - { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 }, - { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 }, -}; - -struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) { - if (skl_clk_src[i].clk_id == clk_id) - return &skl_clk_src[i]; - } - - return NULL; -} - -static void init_skl_xtal_rate(int pci_id) -{ - switch (pci_id) { - case PCI_DEVICE_ID_INTEL_HDA_SKL_LP: - case PCI_DEVICE_ID_INTEL_HDA_KBL_LP: - skl_clk_src[0].rate = 24000000; - return; - - default: - skl_clk_src[0].rate = 19200000; - return; - } -} - -static int skl_clock_device_register(struct skl_dev *skl) -{ - struct platform_device_info pdevinfo = {NULL}; - struct skl_clk_pdata *clk_pdata; - - if (!skl->nhlt) - return 0; - - clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata), - GFP_KERNEL); - if (!clk_pdata) - return -ENOMEM; - - init_skl_xtal_rate(skl->pci->device); - - clk_pdata->parent_clks = skl_clk_src; - clk_pdata->ssp_clks = skl_ssp_clks; - clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks); - - /* Query NHLT to fill the rates and parent */ - skl_get_clks(skl, clk_pdata->ssp_clks); - clk_pdata->pvt_data = skl; - - /* Register Platform device */ - pdevinfo.parent = &skl->pci->dev; - pdevinfo.id = -1; - pdevinfo.name = "skl-ssp-clk"; - pdevinfo.data = clk_pdata; - pdevinfo.size_data = sizeof(*clk_pdata); - skl->clk_dev = platform_device_register_full(&pdevinfo); - return PTR_ERR_OR_ZERO(skl->clk_dev); -} - -static void skl_clock_device_unregister(struct skl_dev *skl) -{ - if (skl->clk_dev) - platform_device_unregister(skl->clk_dev); -} - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - -#define IDISP_INTEL_VENDOR_ID 0x80860000 - -/* - * load the legacy codec driver - */ -static void load_codec_module(struct hda_codec *codec) -{ -#ifdef MODULE - char modalias[MODULE_NAME_LEN]; - const char *mod = NULL; - - snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); - mod = modalias; - dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); - request_module(mod); -#endif -} - -#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ - -static struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr) -{ - struct hda_codec *codec; - int ret; - - codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); - if (IS_ERR(codec)) { - dev_err(bus->dev, "device init failed for hdac device\n"); - return codec; - } - - codec->core.type = HDA_DEV_ASOC; - - ret = snd_hdac_device_register(&codec->core); - if (ret) { - dev_err(bus->dev, "failed to register hdac device\n"); - put_device(&codec->core.dev); - return ERR_PTR(ret); - } - - return codec; -} - -/* - * Probe the given codec address - */ -static int probe_codec(struct hdac_bus *bus, int addr) -{ - unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | - (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res = -1; -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - struct skl_dev *skl = bus_to_skl(bus); - struct hdac_hda_priv *hda_codec; -#endif - struct hda_codec *codec; - - mutex_lock(&bus->cmd_mutex); - snd_hdac_bus_send_cmd(bus, cmd); - snd_hdac_bus_get_response(bus, addr, &res); - mutex_unlock(&bus->cmd_mutex); - if (res == -1) - return -EIO; - dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), - GFP_KERNEL); - if (!hda_codec) - return -ENOMEM; - - codec = skl_codec_device_init(bus, addr); - if (IS_ERR(codec)) - return PTR_ERR(codec); - - hda_codec->codec = codec; - hda_codec->dev_index = addr; - dev_set_drvdata(&codec->core.dev, hda_codec); - - /* use legacy bus only for HDA codecs, idisp uses ext bus */ - if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { - codec->core.type = HDA_DEV_LEGACY; - load_codec_module(hda_codec->codec); - } - return 0; -#else - codec = skl_codec_device_init(bus, addr); - return PTR_ERR_OR_ZERO(codec); -#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ -} - -/* Codec initialization */ -static void skl_codec_create(struct hdac_bus *bus) -{ - int c, max_slots; - - max_slots = HDA_MAX_CODECS; - - /* First try to probe all given codec slots */ - for (c = 0; c < max_slots; c++) { - if ((bus->codec_mask & (1 << c))) { - if (probe_codec(bus, c) < 0) { - /* - * Some BIOSen give you wrong codec addresses - * that don't exist - */ - dev_warn(bus->dev, - "Codec #%d probe error; disabling it...\n", c); - bus->codec_mask &= ~(1 << c); - /* - * More badly, accessing to a non-existing - * codec often screws up the controller bus, - * and disturbs the further communications. - * Thus if an error occurs during probing, - * better to reset the controller bus to get - * back to the sanity state. - */ - snd_hdac_bus_stop_chip(bus); - skl_init_chip(bus, true); - } - } - } -} - -static void skl_probe_work(struct work_struct *work) -{ - struct skl_dev *skl = container_of(work, struct skl_dev, probe_work); - struct hdac_bus *bus = skl_to_bus(skl); - struct hdac_ext_link *hlink; - int err; - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - - skl_init_pci(skl); - skl_dum_set(bus); - - err = skl_init_chip(bus, true); - if (err < 0) { - dev_err(bus->dev, "Init chip failed with err: %d\n", err); - goto out_err; - } - - /* codec detection */ - if (!bus->codec_mask) - dev_info(bus->dev, "no hda codecs found!\n"); - - /* create codec instances */ - skl_codec_create(bus); - - /* register platform dai and controls */ - err = skl_platform_register(bus->dev); - if (err < 0) { - dev_err(bus->dev, "platform register failed: %d\n", err); - goto out_err; - } - - err = skl_machine_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "machine register failed: %d\n", err); - goto out_err; - } - - /* - * we are done probing so decrement link counts - */ - list_for_each_entry(hlink, &bus->hlink_list, list) - snd_hdac_ext_bus_link_put(bus, hlink); - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - - /* configure PM */ - pm_runtime_put_noidle(bus->dev); - pm_runtime_allow(bus->dev); - skl->init_done = 1; - - return; - -out_err: - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); -} - -/* - * constructor - */ -static int skl_create(struct pci_dev *pci, - struct skl_dev **rskl) -{ - struct hdac_ext_bus_ops *ext_ops = NULL; - struct skl_dev *skl; - struct hdac_bus *bus; - struct hda_bus *hbus; - int err; - - *rskl = NULL; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL); - if (!skl) { - pci_disable_device(pci); - return -ENOMEM; - } - - hbus = skl_to_hbus(skl); - bus = skl_to_bus(skl); - - INIT_LIST_HEAD(&skl->ppl_list); - INIT_LIST_HEAD(&skl->bind_list); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - ext_ops = snd_soc_hdac_hda_get_ops(); -#endif - snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops); - bus->use_posbuf = 1; - skl->pci = pci; - INIT_WORK(&skl->probe_work, skl_probe_work); - bus->bdl_pos_adj = 0; - - mutex_init(&hbus->prepare_mutex); - hbus->pci = pci; - hbus->mixer_assigned = -1; - hbus->modelname = "sklbus"; - - *rskl = skl; - - return 0; -} - -static int skl_first_init(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct pci_dev *pci = skl->pci; - int err; - unsigned short gcap; - int cp_streams, pb_streams, start_idx; - - err = pci_request_regions(pci, "Skylake HD audio"); - if (err < 0) - return err; - - bus->addr = pci_resource_start(pci, 0); - bus->remap_addr = pci_ioremap_bar(pci, 0); - if (bus->remap_addr == NULL) { - dev_err(bus->dev, "ioremap error\n"); - return -ENXIO; - } - - snd_hdac_bus_parse_capabilities(bus); - - /* check if PPCAP exists */ - if (!bus->ppcap) { - dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n"); - return -ENODEV; - } - - if (skl_acquire_irq(bus, 0) < 0) - return -EBUSY; - - pci_set_master(pci); - synchronize_irq(bus->irq); - - gcap = snd_hdac_chip_readw(bus, GCAP); - dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); - - /* read number of streams from GCAP register */ - cp_streams = (gcap >> 8) & 0x0f; - pb_streams = (gcap >> 12) & 0x0f; - - if (!pb_streams && !cp_streams) { - dev_err(bus->dev, "no streams found in GCAP definitions?\n"); - return -EIO; - } - - bus->num_streams = cp_streams + pb_streams; - - /* allow 64bit DMA address if supported by H/W */ - if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64))) - dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32)); - dma_set_max_seg_size(bus->dev, UINT_MAX); - - /* initialize streams */ - snd_hdac_ext_stream_init_all - (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); - start_idx = cp_streams; - snd_hdac_ext_stream_init_all - (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); - - err = snd_hdac_bus_alloc_stream_pages(bus); - if (err < 0) - return err; - - return 0; -} - -static int skl_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - struct skl_dev *skl; - struct hdac_bus *bus = NULL; - int err; - - switch (skl_pci_binding) { - case SND_SKL_PCI_BIND_AUTO: - err = snd_intel_dsp_driver_probe(pci); - if (err != SND_INTEL_DSP_DRIVER_ANY && - err != SND_INTEL_DSP_DRIVER_SST) - return -ENODEV; - break; - case SND_SKL_PCI_BIND_LEGACY: - dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n"); - return -ENODEV; - case SND_SKL_PCI_BIND_ASOC: - dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n"); - break; - default: - dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); - break; - } - - /* we use ext core ops, so provide NULL for ops here */ - err = skl_create(pci, &skl); - if (err < 0) - return err; - - bus = skl_to_bus(skl); - - err = skl_first_init(bus); - if (err < 0) { - dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); - goto out_free; - } - - skl->pci_id = pci->device; - - device_disable_async_suspend(bus->dev); - - skl->nhlt = intel_nhlt_init(bus->dev); - - if (skl->nhlt == NULL) { -#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - dev_err(bus->dev, "no nhlt info found\n"); - err = -ENODEV; - goto out_free; -#else - dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n"); -#endif - } else { - - err = skl_nhlt_create_sysfs(skl); - if (err < 0) { - dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); - goto out_nhlt_free; - } - - skl_nhlt_update_topology_bin(skl); - - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); - goto out_clk_free; - } - } - - pci_set_drvdata(skl->pci, bus); - - - err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) { - dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); - goto out_nhlt_free; - } - - err = skl_init_dsp(skl); - if (err < 0) { - dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_nhlt_free; - } - skl->enable_miscbdcge = skl_enable_miscbdcge; - skl->clock_power_gating = skl_clock_power_gating; - - if (bus->mlcap) - snd_hdac_ext_bus_get_ml_capabilities(bus); - - /* create device for soc dmic */ - err = skl_dmic_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); - goto out_dsp_free; - } - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_i915_init(bus); - if (err < 0) - goto out_dmic_unregister; - } - schedule_work(&skl->probe_work); - - return 0; - -out_dmic_unregister: - skl_dmic_device_unregister(skl); -out_dsp_free: - skl_free_dsp(skl); -out_clk_free: - skl_clock_device_unregister(skl); -out_nhlt_free: - if (skl->nhlt) - intel_nhlt_free(skl->nhlt); -out_free: - skl_free(bus); - - return err; -} - -static void skl_shutdown(struct pci_dev *pci) -{ - struct hdac_bus *bus = pci_get_drvdata(pci); - struct hdac_stream *s; - struct hdac_ext_stream *stream; - struct skl_dev *skl; - - if (!bus) - return; - - skl = bus_to_skl(bus); - - if (!skl->init_done) - return; - - snd_hdac_stop_streams(bus); - snd_hdac_ext_bus_link_power_down_all(bus); - skl_dsp_sleep(skl->dsp); - - list_for_each_entry(s, &bus->stream_list, list) { - stream = stream_to_hdac_ext_stream(s); - snd_hdac_ext_stream_decouple(bus, stream, false); - } - - snd_hdac_bus_stop_chip(bus); -} - -static void skl_remove(struct pci_dev *pci) -{ - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - - cancel_work_sync(&skl->probe_work); - - pm_runtime_get_noresume(&pci->dev); - - /* codec removal, invoke bus_device_remove */ - snd_hdac_ext_bus_device_remove(bus); - - skl_platform_unregister(&pci->dev); - skl_free_dsp(skl); - skl_machine_device_unregister(skl); - skl_dmic_device_unregister(skl); - skl_clock_device_unregister(skl); - skl_nhlt_remove_sysfs(skl); - if (skl->nhlt) - intel_nhlt_free(skl->nhlt); - skl_free(bus); -} - -/* PCI IDs */ -static const struct pci_device_id skl_ids[] = { -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) - { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) - { PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) - { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) - { PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) - { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) - { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) - { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) - { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) }, -#endif - { 0, } -}; -MODULE_DEVICE_TABLE(pci, skl_ids); - -/* pci_driver definition */ -static struct pci_driver skl_driver = { - .name = KBUILD_MODNAME, - .id_table = skl_ids, - .probe = skl_probe, - .remove = skl_remove, - .shutdown = skl_shutdown, - .driver = { - .pm = &skl_pm, - }, -}; -module_pci_driver(skl_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h deleted file mode 100644 index f55f8b3dbdc3..000000000000 --- a/sound/soc/intel/skylake/skl.h +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl.h - HD Audio skylake definitions. - * - * Copyright (C) 2015 Intel Corp - * Author: Jeeja KP - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SOUND_SOC_SKL_H -#define __SOUND_SOC_SKL_H - -#include -#include -#include -#include -#include "skl-ssp-clk.h" -#include "skl-sst-ipc.h" - -#define SKL_SUSPEND_DELAY 2000 - -#define SKL_MAX_ASTATE_CFG 3 - -#define AZX_PCIREG_PGCTL 0x44 -#define AZX_PGCTL_LSRMD_MASK (1 << 4) -#define AZX_PGCTL_ADSPPGD BIT(2) -#define AZX_PCIREG_CGCTL 0x48 -#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) -#define AZX_CGCTL_ADSPDCGE BIT(1) -/* D0I3C Register fields */ -#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ -#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ -#define SKL_MAX_DMACTRL_CFG 18 -#define DMA_CLK_CONTROLS 1 -#define DMA_TRANSMITION_START 2 -#define DMA_TRANSMITION_STOP 3 - -#define AZX_VS_EM2_DUM BIT(23) -#define AZX_REG_VS_EM2_L1SEN BIT(13) - -struct skl_debug; - -struct skl_astate_param { - u32 kcps; - u32 clk_src; -}; - -struct skl_astate_config { - u32 count; - struct skl_astate_param astate_table[]; -}; - -struct skl_fw_config { - struct skl_astate_config *astate_cfg; -}; - -struct skl_dev { - struct hda_bus hbus; - struct pci_dev *pci; - - unsigned int init_done:1; /* delayed init status */ - struct platform_device *dmic_dev; - struct platform_device *i2s_dev; - struct platform_device *clk_dev; - struct snd_soc_component *component; - struct snd_soc_dai_driver *dais; - - struct nhlt_acpi_table *nhlt; /* nhlt ptr */ - - struct list_head ppl_list; - struct list_head bind_list; - - const char *fw_name; - char tplg_name[64]; - unsigned short pci_id; - - int supend_active; - - struct work_struct probe_work; - - struct skl_debug *debugfs; - u8 nr_modules; - struct skl_module **modules; - bool use_tplg_pcm; - struct skl_fw_config cfg; - struct snd_soc_acpi_mach *mach; - - struct device *dev; - struct sst_dsp *dsp; - - /* boot */ - wait_queue_head_t boot_wait; - bool boot_complete; - - /* module load */ - wait_queue_head_t mod_load_wait; - bool mod_load_complete; - bool mod_load_status; - - /* IPC messaging */ - struct sst_generic_ipc ipc; - - /* callback for miscbdge */ - void (*enable_miscbdcge)(struct device *dev, bool enable); - /* Is CGCTL.MISCBDCGE disabled */ - bool miscbdcg_disabled; - - /* Populate module information */ - struct list_head uuid_list; - - /* Is firmware loaded */ - bool fw_loaded; - - /* first boot ? */ - bool is_first_boot; - - /* multi-core */ - struct skl_dsp_cores cores; - - /* library info */ - struct skl_lib_info lib_info[SKL_MAX_LIB]; - int lib_count; - - /* Callback to update D0i3C register */ - void (*update_d0i3c)(struct device *dev, bool enable); - - struct skl_d0i3_data d0i3; - - const struct skl_dsp_ops *dsp_ops; - - /* Callback to update dynamic clock and power gating registers */ - void (*clock_power_gating)(struct device *dev, bool enable); -}; - -#define skl_to_bus(s) (&(s)->hbus.core) -#define bus_to_skl(bus) container_of(bus, struct skl_dev, hbus.core) - -#define skl_to_hbus(s) (&(s)->hbus) -#define hbus_to_skl(hbus) container_of((hbus), struct skl_dev, (hbus)) - -/* to pass dai dma data */ -struct skl_dma_params { - u32 format; - u8 stream_tag; -}; - -struct skl_machine_pdata { - bool use_tplg_pcm; /* use dais and dai links from topology */ -}; - -struct skl_dsp_ops { - int id; - unsigned int num_cores; - struct skl_dsp_loader_ops (*loader_ops)(void); - int (*init)(struct device *dev, void __iomem *mmio_base, - int irq, const char *fw_name, - struct skl_dsp_loader_ops loader_ops, - struct skl_dev **skl_sst); - int (*init_fw)(struct device *dev, struct skl_dev *skl); - void (*cleanup)(struct device *dev, struct skl_dev *skl); -}; - -int skl_platform_unregister(struct device *dev); -int skl_platform_register(struct device *dev); - -int skl_nhlt_update_topology_bin(struct skl_dev *skl); -int skl_init_dsp(struct skl_dev *skl); -int skl_free_dsp(struct skl_dev *skl); -int skl_suspend_late_dsp(struct skl_dev *skl); -int skl_suspend_dsp(struct skl_dev *skl); -int skl_resume_dsp(struct skl_dev *skl); -void skl_cleanup_resources(struct skl_dev *skl); -const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); -void skl_update_d0i3c(struct device *dev, bool enable); -int skl_nhlt_create_sysfs(struct skl_dev *skl); -void skl_nhlt_remove_sysfs(struct skl_dev *skl); -void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks); -struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id); -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id); - -struct skl_module_cfg; - -#ifdef CONFIG_DEBUG_FS -struct skl_debug *skl_debugfs_init(struct skl_dev *skl); -void skl_debugfs_exit(struct skl_dev *skl); -void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig); -#else -static inline struct skl_debug *skl_debugfs_init(struct skl_dev *skl) -{ - return NULL; -} - -static inline void skl_debugfs_exit(struct skl_dev *skl) -{} - -static inline void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig) -{} -#endif - -#endif /* __SOUND_SOC_SKL_H */ diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index d1eb90310afa..99bd066c7309 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -759,7 +759,7 @@ MODULE_DEVICE_TABLE(of, mvebu_audio_of_match); static struct platform_driver kirkwood_i2s_driver = { .probe = kirkwood_i2s_dev_probe, - .remove_new = kirkwood_i2s_dev_remove, + .remove = kirkwood_i2s_dev_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(mvebu_audio_of_match), diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index fae5e9312bf0..7379f24d385c 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -24,27 +24,27 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct loongson_card_data *ls_card = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); int ret, mclk; - if (ls_card->mclk_fs) { - mclk = ls_card->mclk_fs * params_rate(params); - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, - SND_SOC_CLOCK_OUT); - if (ret < 0) { - dev_err(codec_dai->dev, "cpu_dai clock not set\n"); - return ret; - } + if (!ls_card->mclk_fs) + return 0; - ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(codec_dai->dev, "codec_dai clock not set\n"); - return ret; - } + mclk = ls_card->mclk_fs * params_rate(params); + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "cpu_dai clock not set\n"); + return ret; } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "codec_dai clock not set\n"); + return ret; + } + return 0; } @@ -68,46 +68,53 @@ static struct snd_soc_dai_link loongson_dai_links[] = { }, }; +static struct acpi_device *loongson_card_acpi_find_device(struct snd_soc_card *card, + const char *name) +{ + struct fwnode_handle *fwnode = card->dev->fwnode; + struct fwnode_reference_args args; + int status; + + memset(&args, 0, sizeof(args)); + status = acpi_node_get_property_reference(fwnode, name, 0, &args); + if (status || !is_acpi_device_node(args.fwnode)) { + dev_err(card->dev, "No matching phy in ACPI table\n"); + return NULL; + } + + return to_acpi_device_node(args.fwnode); +} + static int loongson_card_parse_acpi(struct loongson_card_data *data) { struct snd_soc_card *card = &data->snd_card; - struct fwnode_handle *fwnode = card->dev->fwnode; - struct fwnode_reference_args args; const char *codec_dai_name; struct acpi_device *adev; struct device *phy_dev; - int ret, i; + int i; /* fixup platform name based on reference node */ - memset(&args, 0, sizeof(args)); - ret = acpi_node_get_property_reference(fwnode, "cpu", 0, &args); - if (ret || !is_acpi_device_node(args.fwnode)) { - dev_err(card->dev, "No matching phy in ACPI table\n"); - return ret ?: -ENOENT; - } - adev = to_acpi_device_node(args.fwnode); + adev = loongson_card_acpi_find_device(card, "cpu"); + if (!adev) + return -ENOENT; + phy_dev = acpi_get_first_physical_node(adev); if (!phy_dev) return -EPROBE_DEFER; - for (i = 0; i < card->num_links; i++) - loongson_dai_links[i].platforms->name = dev_name(phy_dev); /* fixup codec name based on reference node */ - memset(&args, 0, sizeof(args)); - ret = acpi_node_get_property_reference(fwnode, "codec", 0, &args); - if (ret || !is_acpi_device_node(args.fwnode)) { - dev_err(card->dev, "No matching phy in ACPI table\n"); - return ret ?: -ENOENT; - } - adev = to_acpi_device_node(args.fwnode); + adev = loongson_card_acpi_find_device(card, "codec"); + if (!adev) + return -ENOENT; snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); - for (i = 0; i < card->num_links; i++) - loongson_dai_links[i].codecs->name = codec_name; - device_property_read_string(card->dev, "codec-dai-name", - &codec_dai_name); - for (i = 0; i < card->num_links; i++) + device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name); + + for (i = 0; i < card->num_links; i++) { + loongson_dai_links[i].platforms->name = dev_name(phy_dev); + loongson_dai_links[i].codecs->name = codec_name; loongson_dai_links[i].codecs->dai_name = codec_dai_name; + } return 0; } @@ -127,8 +134,8 @@ static int loongson_card_parse_of(struct loongson_card_data *data) codec = of_get_child_by_name(dev->of_node, "codec"); if (!codec) { dev_err(dev, "audio-codec property missing or invalid\n"); - ret = -EINVAL; - goto err; + of_node_put(cpu); + return -EINVAL; } for (i = 0; i < card->num_links; i++) { @@ -159,42 +166,36 @@ err: static int loongson_asoc_card_probe(struct platform_device *pdev) { struct loongson_card_data *ls_priv; + struct device *dev = &pdev->dev; struct snd_soc_card *card; int ret; - ls_priv = devm_kzalloc(&pdev->dev, sizeof(*ls_priv), GFP_KERNEL); + ls_priv = devm_kzalloc(dev, sizeof(*ls_priv), GFP_KERNEL); if (!ls_priv) return -ENOMEM; card = &ls_priv->snd_card; - card->dev = &pdev->dev; + card->dev = dev; card->owner = THIS_MODULE; card->dai_link = loongson_dai_links; card->num_links = ARRAY_SIZE(loongson_dai_links); snd_soc_card_set_drvdata(card, ls_priv); - ret = device_property_read_string(&pdev->dev, "model", &card->name); - if (ret) { - dev_err(&pdev->dev, "Error parsing card name: %d\n", ret); - return ret; - } - ret = device_property_read_u32(&pdev->dev, "mclk-fs", &ls_priv->mclk_fs); - if (ret) { - dev_err(&pdev->dev, "Error parsing mclk-fs: %d\n", ret); - return ret; - } + ret = device_property_read_string(dev, "model", &card->name); + if (ret) + return dev_err_probe(dev, ret, "Error parsing card name\n"); - if (has_acpi_companion(&pdev->dev)) - ret = loongson_card_parse_acpi(ls_priv); - else - ret = loongson_card_parse_of(ls_priv); - if (ret < 0) - return ret; + ret = device_property_read_u32(dev, "mclk-fs", &ls_priv->mclk_fs); + if (ret) + return dev_err_probe(dev, ret, "Error parsing mclk-fs\n"); - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = has_acpi_companion(dev) ? loongson_card_parse_acpi(ls_priv) + : loongson_card_parse_of(ls_priv); + if (ret) + return dev_err_probe(dev, ret, "Error parsing acpi/of properties\n"); - return ret; + return devm_snd_soc_register_card(dev, card); } static const struct of_device_id loongson_asoc_dt_ids[] = { diff --git a/sound/soc/loongson/loongson_dma.c b/sound/soc/loongson/loongson_dma.c index 4fcc2868160b..20e4a0641340 100644 --- a/sound/soc/loongson/loongson_dma.c +++ b/sound/soc/loongson/loongson_dma.c @@ -17,11 +17,11 @@ #include "loongson_i2s.h" /* DMA dma_order Register */ -#define DMA_ORDER_STOP (1 << 4) /* DMA stop */ -#define DMA_ORDER_START (1 << 3) /* DMA start */ -#define DMA_ORDER_ASK_VALID (1 << 2) /* DMA ask valid flag */ -#define DMA_ORDER_AXI_UNCO (1 << 1) /* Uncache access */ -#define DMA_ORDER_ADDR_64 (1 << 0) /* 64bits address support */ +#define DMA_ORDER_STOP BIT(4) /* DMA stop */ +#define DMA_ORDER_START BIT(3) /* DMA start */ +#define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */ +#define DMA_ORDER_AXI_UNCO BIT(1) /* Uncache access */ +#define DMA_ORDER_ADDR_64 BIT(0) /* 64bits address support */ #define DMA_ORDER_ASK_MASK (~0x1fUL) /* Ask addr mask */ #define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */ @@ -95,7 +95,6 @@ static int loongson_pcm_trigger(struct snd_soc_component *component, struct device *dev = substream->pcm->card->dev; void __iomem *order_reg = prtd->dma_data->order_addr; u64 val; - int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -129,7 +128,7 @@ static int loongson_pcm_trigger(struct snd_soc_component *component, return -EINVAL; } - return ret; + return 0; } static int loongson_pcm_hw_params(struct snd_soc_component *component, @@ -230,7 +229,6 @@ static int loongson_pcm_open(struct snd_soc_component *component, struct snd_card *card = substream->pcm->card; struct loongson_runtime_data *prtd; struct loongson_dma_data *dma_data; - int ret; /* * For mysterious reasons (and despite what the manual says) @@ -252,20 +250,17 @@ static int loongson_pcm_open(struct snd_soc_component *component, prtd->dma_desc_arr = dma_alloc_coherent(card->dev, PAGE_SIZE, &prtd->dma_desc_arr_phy, GFP_KERNEL); - if (!prtd->dma_desc_arr) { - ret = -ENOMEM; + if (!prtd->dma_desc_arr) goto desc_err; - } + prtd->dma_desc_arr_size = PAGE_SIZE / sizeof(*prtd->dma_desc_arr); prtd->dma_pos_desc = dma_alloc_coherent(card->dev, sizeof(*prtd->dma_pos_desc), &prtd->dma_pos_desc_phy, GFP_KERNEL); - if (!prtd->dma_pos_desc) { - ret = -ENOMEM; + if (!prtd->dma_pos_desc) goto pos_err; - } dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream); prtd->dma_data = dma_data; @@ -279,7 +274,7 @@ pos_err: desc_err: kfree(prtd); - return ret; + return -ENOMEM; } static int loongson_pcm_close(struct snd_soc_component *component, diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index d45228a3a558..40bbf3205391 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -21,34 +21,33 @@ SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE) +#define LOONGSON_I2S_TX_ENABLE (I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN) +#define LOONGSON_I2S_RX_ENABLE (I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN) + +#define LOONGSON_I2S_DEF_DELAY 10 +#define LOONGSON_I2S_DEF_TIMEOUT 500000 + static int loongson_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct loongson_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int mask; int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN, - I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN); - else - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN, - I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN); + mask = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + LOONGSON_I2S_TX_ENABLE : LOONGSON_I2S_RX_ENABLE; + regmap_update_bits(i2s->regmap, LS_I2S_CTRL, mask, mask); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN, 0); - else - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN, 0); + mask = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + LOONGSON_I2S_TX_ENABLE : LOONGSON_I2S_RX_ENABLE; + regmap_update_bits(i2s->regmap, LS_I2S_CTRL, mask, 0); break; default: ret = -EINVAL; @@ -123,10 +122,40 @@ static int loongson_i2s_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static int loongson_i2s_enable_mclk(struct loongson_i2s *i2s) +{ + u32 val; + + if (i2s->rev_id == 0) + return 0; + + regmap_update_bits(i2s->regmap, LS_I2S_CTRL, + I2S_CTRL_MCLK_EN, I2S_CTRL_MCLK_EN); + + return regmap_read_poll_timeout_atomic(i2s->regmap, + LS_I2S_CTRL, val, + val & I2S_CTRL_MCLK_READY, + LOONGSON_I2S_DEF_DELAY, + LOONGSON_I2S_DEF_TIMEOUT); +} + +static int loongson_i2s_enable_bclk(struct loongson_i2s *i2s) +{ + u32 val; + + if (i2s->rev_id == 0) + return 0; + + return regmap_read_poll_timeout_atomic(i2s->regmap, + LS_I2S_CTRL, val, + val & I2S_CTRL_CLK_READY, + LOONGSON_I2S_DEF_DELAY, + LOONGSON_I2S_DEF_TIMEOUT); +} + static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct loongson_i2s *i2s = snd_soc_dai_get_drvdata(dai); - u32 val; int ret; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -148,54 +177,29 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* Enable master mode */ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_MASTER, I2S_CTRL_MASTER); - if (i2s->rev_id == 1) { - ret = regmap_read_poll_timeout_atomic(i2s->regmap, - LS_I2S_CTRL, val, - val & I2S_CTRL_CLK_READY, - 10, 500000); - if (ret < 0) - dev_warn(dai->dev, "wait BCLK ready timeout\n"); - } + ret = loongson_i2s_enable_bclk(i2s); + if (ret < 0) + dev_warn(dai->dev, "wait BCLK ready timeout\n"); break; case SND_SOC_DAIFMT_BC_FP: /* Enable MCLK */ - if (i2s->rev_id == 1) { - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_MCLK_EN, - I2S_CTRL_MCLK_EN); - ret = regmap_read_poll_timeout_atomic(i2s->regmap, - LS_I2S_CTRL, val, - val & I2S_CTRL_MCLK_READY, - 10, 500000); - if (ret < 0) - dev_warn(dai->dev, "wait MCLK ready timeout\n"); - } + ret = loongson_i2s_enable_mclk(i2s); + if (ret < 0) + dev_warn(dai->dev, "wait MCLK ready timeout\n"); break; case SND_SOC_DAIFMT_BP_FP: /* Enable MCLK */ - if (i2s->rev_id == 1) { - regmap_update_bits(i2s->regmap, LS_I2S_CTRL, - I2S_CTRL_MCLK_EN, - I2S_CTRL_MCLK_EN); - ret = regmap_read_poll_timeout_atomic(i2s->regmap, - LS_I2S_CTRL, val, - val & I2S_CTRL_MCLK_READY, - 10, 500000); - if (ret < 0) - dev_warn(dai->dev, "wait MCLK ready timeout\n"); - } + ret = loongson_i2s_enable_mclk(i2s); + if (ret < 0) + dev_warn(dai->dev, "wait MCLK ready timeout\n"); /* Enable master mode */ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_MASTER, I2S_CTRL_MASTER); - if (i2s->rev_id == 1) { - ret = regmap_read_poll_timeout_atomic(i2s->regmap, - LS_I2S_CTRL, val, - val & I2S_CTRL_CLK_READY, - 10, 500000); - if (ret < 0) - dev_warn(dai->dev, "wait BCLK ready timeout\n"); - } + + ret = loongson_i2s_enable_bclk(i2s); + if (ret < 0) + dev_warn(dai->dev, "wait BCLK ready timeout\n"); break; default: return -EINVAL; @@ -255,13 +259,10 @@ static int i2s_suspend(struct device *dev) static int i2s_resume(struct device *dev) { struct loongson_i2s *i2s = dev_get_drvdata(dev); - int ret; regcache_cache_only(i2s->regmap, false); regcache_mark_dirty(i2s->regmap); - ret = regcache_sync(i2s->regmap); - - return ret; + return regcache_sync(i2s->regmap); } const struct dev_pm_ops loongson_i2s_pm = { diff --git a/sound/soc/loongson/loongson_i2s.h b/sound/soc/loongson/loongson_i2s.h index 89492eebf834..c8052a762c1b 100644 --- a/sound/soc/loongson/loongson_i2s.h +++ b/sound/soc/loongson/loongson_i2s.h @@ -27,18 +27,18 @@ #define LS_I2S_RX_ORDER 0x110 /* RX DMA Order */ /* Loongson I2S Control Register */ -#define I2S_CTRL_MCLK_READY (1 << 16) /* MCLK ready */ -#define I2S_CTRL_MASTER (1 << 15) /* Master mode */ -#define I2S_CTRL_MSB (1 << 14) /* MSB bit order */ -#define I2S_CTRL_RX_EN (1 << 13) /* RX enable */ -#define I2S_CTRL_TX_EN (1 << 12) /* TX enable */ -#define I2S_CTRL_RX_DMA_EN (1 << 11) /* DMA RX enable */ -#define I2S_CTRL_CLK_READY (1 << 8) /* BCLK ready */ -#define I2S_CTRL_TX_DMA_EN (1 << 7) /* DMA TX enable */ -#define I2S_CTRL_RESET (1 << 4) /* Controller soft reset */ -#define I2S_CTRL_MCLK_EN (1 << 3) /* Enable MCLK */ -#define I2S_CTRL_RX_INT_EN (1 << 1) /* RX interrupt enable */ -#define I2S_CTRL_TX_INT_EN (1 << 0) /* TX interrupt enable */ +#define I2S_CTRL_MCLK_READY BIT(16) /* MCLK ready */ +#define I2S_CTRL_MASTER BIT(15) /* Master mode */ +#define I2S_CTRL_MSB BIT(14) /* MSB bit order */ +#define I2S_CTRL_RX_EN BIT(13) /* RX enable */ +#define I2S_CTRL_TX_EN BIT(12) /* TX enable */ +#define I2S_CTRL_RX_DMA_EN BIT(11) /* DMA RX enable */ +#define I2S_CTRL_CLK_READY BIT(8) /* BCLK ready */ +#define I2S_CTRL_TX_DMA_EN BIT(7) /* DMA TX enable */ +#define I2S_CTRL_RESET BIT(4) /* Controller soft reset */ +#define I2S_CTRL_MCLK_EN BIT(3) /* Enable MCLK */ +#define I2S_CTRL_RX_INT_EN BIT(1) /* RX interrupt enable */ +#define I2S_CTRL_TX_INT_EN BIT(0) /* TX interrupt enable */ #define LS_I2S_DRVNAME "loongson-i2s" diff --git a/sound/soc/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c index ec18b122cd79..d2d0e5d8cac9 100644 --- a/sound/soc/loongson/loongson_i2s_pci.c +++ b/sound/soc/loongson/loongson_i2s_pci.c @@ -75,34 +75,34 @@ static int loongson_i2s_pci_probe(struct pci_dev *pdev, { const struct fwnode_handle *fwnode = pdev->dev.fwnode; struct loongson_dma_data *tx_data, *rx_data; + struct device *dev = &pdev->dev; struct loongson_i2s *i2s; int ret; if (pcim_enable_device(pdev)) { - dev_err(&pdev->dev, "pci_enable_device failed\n"); + dev_err(dev, "pci_enable_device failed\n"); return -ENODEV; } - i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) return -ENOMEM; i2s->rev_id = pdev->revision; - i2s->dev = &pdev->dev; + i2s->dev = dev; pci_set_drvdata(pdev, i2s); - ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(&pdev->dev)); + ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(dev)); if (ret < 0) { - dev_err(&pdev->dev, "iomap_regions failed\n"); + dev_err(dev, "iomap_regions failed\n"); return ret; } + i2s->reg_base = pcim_iomap_table(pdev)[0]; - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->reg_base, + i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base, &loongson_i2s_regmap_config); - if (IS_ERR(i2s->regmap)) { - dev_err(&pdev->dev, "regmap_init_mmio failed\n"); - return PTR_ERR(i2s->regmap); - } + if (IS_ERR(i2s->regmap)) + return dev_err_probe(dev, PTR_ERR(i2s->regmap), "regmap_init_mmio failed\n"); tx_data = &i2s->tx_dma_data; rx_data = &i2s->rx_dma_data; @@ -114,37 +114,28 @@ static int loongson_i2s_pci_probe(struct pci_dev *pdev, rx_data->order_addr = i2s->reg_base + LS_I2S_RX_ORDER; tx_data->irq = fwnode_irq_get_byname(fwnode, "tx"); - if (tx_data->irq < 0) { - dev_err(&pdev->dev, "dma tx irq invalid\n"); - return tx_data->irq; - } + if (tx_data->irq < 0) + return dev_err_probe(dev, tx_data->irq, "dma tx irq invalid\n"); rx_data->irq = fwnode_irq_get_byname(fwnode, "rx"); - if (rx_data->irq < 0) { - dev_err(&pdev->dev, "dma rx irq invalid\n"); - return rx_data->irq; - } + if (rx_data->irq < 0) + return dev_err_probe(dev, rx_data->irq, "dma rx irq invalid\n"); - device_property_read_u32(&pdev->dev, "clock-frequency", &i2s->clk_rate); - if (!i2s->clk_rate) { - dev_err(&pdev->dev, "clock-frequency property invalid\n"); - return -EINVAL; - } + ret = device_property_read_u32(dev, "clock-frequency", &i2s->clk_rate); + if (ret) + return dev_err_probe(dev, ret, "clock-frequency property invalid\n"); - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (i2s->rev_id == 1) { regmap_write(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET); udelay(200); } - ret = devm_snd_soc_register_component(&pdev->dev, - &loongson_i2s_component, + ret = devm_snd_soc_register_component(dev, &loongson_i2s_component, &loongson_i2s_dai, 1); - if (ret) { - dev_err(&pdev->dev, "register DAI failed %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "register DAI failed\n"); return 0; } diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 5a8476e1ecca..3033e2d3fe16 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -298,3 +298,23 @@ config SND_SOC_MT8195_MT6359 boards with the MT6359 and other I2S audio codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MT8365 + tristate "ASoC support for MediaTek MT8365 chip" + depends on ARCH_MEDIATEK || COMPILE_TEST + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for MediaTek MT8365 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8365_MT6357 + tristate "ASoC Audio driver for MT8365 with MT6357 codec" + depends on SND_SOC_MT8365 && MTK_PMIC_WRAP + select SND_SOC_MT6357 + help + This adds support for ASoC machine driver for MediaTek MT8365 + boards with the MT6357 PMIC codec. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3938e7f75c2e..4b55434f2168 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ obj-$(CONFIG_SND_SOC_MT8188) += mt8188/ obj-$(CONFIG_SND_SOC_MT8192) += mt8192/ obj-$(CONFIG_SND_SOC_MT8195) += mt8195/ +obj-$(CONFIG_SND_SOC_MT8365) += mt8365/ diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index c12d170fa1de..d07f288f9752 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1400,7 +1400,7 @@ static struct platform_driver mtk_btcvsd_snd_driver = { .of_match_table = mtk_btcvsd_snd_dt_match, }, .probe = mtk_btcvsd_snd_probe, - .remove_new = mtk_btcvsd_snd_remove, + .remove = mtk_btcvsd_snd_remove, }; module_platform_driver(mtk_btcvsd_snd_driver); diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 6a17deb874df..5f11bc5438bd 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1473,7 +1473,7 @@ static struct platform_driver mt2701_afe_pcm_driver = { .pm = &mt2701_afe_pm_ops, }, .probe = mt2701_afe_pcm_dev_probe, - .remove_new = mt2701_afe_pcm_dev_remove, + .remove = mt2701_afe_pcm_dev_remove, }; module_platform_driver(mt2701_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 1262e8a1bc9a..4974b0536b7b 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -329,10 +329,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) int ret; int i; struct device_node *platform_node, *codec_node, *codec_node_bt_mrg; - struct mt2701_cs42448_private *priv = - devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), - GFP_KERNEL); struct device *dev = &pdev->dev; + struct mt2701_cs42448_private *priv = + devm_kzalloc(dev, sizeof(struct mt2701_cs42448_private), + GFP_KERNEL); struct snd_soc_dai_link *dai_link; if (!priv) @@ -341,7 +341,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); if (!platform_node) { - dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + dev_err(dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { @@ -355,7 +355,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) codec_node = of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); if (!codec_node) { - dev_err(&pdev->dev, + dev_err(dev, "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } @@ -368,7 +368,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec-bt-mrg", 0); if (!codec_node_bt_mrg) { - dev_err(&pdev->dev, + dev_err(dev, "Property 'audio-codec-bt-mrg' missing or invalid\n"); return -EINVAL; } @@ -377,7 +377,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret) { - dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + dev_err(dev, "failed to parse audio-routing: %d\n", ret); return ret; } @@ -395,10 +395,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(dev, card); if (ret) - dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + dev_err(dev, "%s snd_soc_register_card fail %d\n", __func__, ret); return ret; } diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index c1dee119e93a..9159b42adf6a 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -890,7 +890,7 @@ static struct platform_driver mt6797_afe_pcm_driver = { .pm = &mt6797_afe_pm_ops, }, .probe = mt6797_afe_pcm_dev_probe, - .remove_new = mt6797_afe_pcm_dev_remove, + .remove = mt6797_afe_pcm_dev_remove, }; module_platform_driver(mt6797_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c index 572ded279b53..7db090414d59 100644 --- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -529,10 +529,9 @@ static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev) /* request irq */ irq_id = platform_get_irq(pdev, 0); - if (irq_id < 0) { - ret = irq_id; - return dev_err_probe(dev, ret, "No irq found\n"); - } + if (irq_id < 0) + return irq_id; + ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler, IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); if (ret) @@ -601,7 +600,7 @@ static struct platform_driver mt7986_afe_pcm_driver = { .pm = &mt7986_afe_pm_ops, }, .probe = mt7986_afe_pcm_dev_probe, - .remove_new = mt7986_afe_pcm_dev_remove, + .remove = mt7986_afe_pcm_dev_remove, }; module_platform_driver(mt7986_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index b6291b7c811e..03250273ea9c 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1223,7 +1223,7 @@ static struct platform_driver mt8173_afe_pcm_driver = { .pm = &mt8173_afe_pm_ops, }, .probe = mt8173_afe_pcm_dev_probe, - .remove_new = mt8173_afe_pcm_dev_remove, + .remove = mt8173_afe_pcm_dev_remove, }; module_platform_driver(mt8173_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 25348fdf75fa..3f377ba4ad53 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1268,7 +1268,7 @@ static struct platform_driver mt8183_afe_pcm_driver = { .pm = &mt8183_afe_pm_ops, }, .probe = mt8183_afe_pcm_dev_probe, - .remove_new = mt8183_afe_pcm_dev_remove, + .remove = mt8183_afe_pcm_dev_remove, }; module_platform_driver(mt8183_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index 424c5c68f78a..9b502f4cd6ea 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -2325,7 +2325,7 @@ static struct platform_driver mt8192_afe_pcm_driver = { .pm = &mt8192_afe_pm_ops, }, .probe = mt8192_afe_pcm_dev_probe, - .remove_new = mt8192_afe_pcm_dev_remove, + .remove = mt8192_afe_pcm_dev_remove, }; module_platform_driver(mt8192_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 8b323fb19925..db00704e206d 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1108,9 +1108,7 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data) err_headset_codec: of_node_put(speaker_codec); err_speaker_codec: - if (hdmi_codec) - of_node_put(hdmi_codec); - + of_node_put(hdmi_codec); return ret; } diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 38891d1bd18a..8016bfb35015 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3199,7 +3199,7 @@ static struct platform_driver mt8195_afe_pcm_driver = { .pm = &mt8195_afe_pm_ops, }, .probe = mt8195_afe_pcm_dev_probe, - .remove_new = mt8195_afe_pcm_dev_remove, + .remove = mt8195_afe_pcm_dev_remove, }; module_platform_driver(mt8195_afe_pcm_driver); diff --git a/sound/soc/mediatek/mt8365/Makefile b/sound/soc/mediatek/mt8365/Makefile new file mode 100644 index 000000000000..52ba45a8498a --- /dev/null +++ b/sound/soc/mediatek/mt8365/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 + +# MTK Platform driver +snd-soc-mt8365-pcm-objs := \ + mt8365-afe-clk.o \ + mt8365-afe-pcm.o \ + mt8365-dai-adda.o \ + mt8365-dai-dmic.o \ + mt8365-dai-i2s.o \ + mt8365-dai-pcm.o + +obj-$(CONFIG_SND_SOC_MT8365) += snd-soc-mt8365-pcm.o + +# Machine driver +obj-$(CONFIG_SND_SOC_MT8365_MT6357) += mt8365-mt6357.o diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c new file mode 100644 index 000000000000..8a0af2ea8546 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 AFE clock control + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include "mt8365-afe-clk.h" +#include "mt8365-afe-common.h" +#include "mt8365-reg.h" +#include "../common/mtk-base-afe.h" +#include +#include + +static const char *aud_clks[MT8365_CLK_NUM] = { + [MT8365_CLK_TOP_AUD_SEL] = "top_audio_sel", + [MT8365_CLK_AUD_I2S0_M] = "audio_i2s0_m", + [MT8365_CLK_AUD_I2S1_M] = "audio_i2s1_m", + [MT8365_CLK_AUD_I2S2_M] = "audio_i2s2_m", + [MT8365_CLK_AUD_I2S3_M] = "audio_i2s3_m", + [MT8365_CLK_ENGEN1] = "engen1", + [MT8365_CLK_ENGEN2] = "engen2", + [MT8365_CLK_AUD1] = "aud1", + [MT8365_CLK_AUD2] = "aud2", + [MT8365_CLK_I2S0_M_SEL] = "i2s0_m_sel", + [MT8365_CLK_I2S1_M_SEL] = "i2s1_m_sel", + [MT8365_CLK_I2S2_M_SEL] = "i2s2_m_sel", + [MT8365_CLK_I2S3_M_SEL] = "i2s3_m_sel", + [MT8365_CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe) +{ + size_t i; + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { + afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clocks[i])) { + dev_err(afe->dev, "%s devm_clk_get %s fail\n", + __func__, aud_clks[i]); + return PTR_ERR(afe_priv->clocks[i]); + } + } + return 0; +} + +void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk) +{ + if (clk) + clk_disable_unprepare(clk); +} + +int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, + unsigned int rate) +{ + int ret; + + if (clk) { + ret = clk_set_rate(clk, rate); + if (ret) { + dev_err(afe->dev, "Failed to set rate\n"); + return ret; + } + } + return 0; +} + +int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, + struct clk *parent) +{ + int ret; + + if (clk && parent) { + ret = clk_set_parent(clk, parent); + if (ret) { + dev_err(afe->dev, "Failed to set parent\n"); + return ret; + } + } + return 0; +} + +static unsigned int get_top_cg_reg(unsigned int cg_type) +{ + switch (cg_type) { + case MT8365_TOP_CG_AFE: + case MT8365_TOP_CG_I2S_IN: + case MT8365_TOP_CG_22M: + case MT8365_TOP_CG_24M: + case MT8365_TOP_CG_INTDIR_CK: + case MT8365_TOP_CG_APLL2_TUNER: + case MT8365_TOP_CG_APLL_TUNER: + case MT8365_TOP_CG_SPDIF: + case MT8365_TOP_CG_TDM_OUT: + case MT8365_TOP_CG_TDM_IN: + case MT8365_TOP_CG_ADC: + case MT8365_TOP_CG_DAC: + case MT8365_TOP_CG_DAC_PREDIS: + case MT8365_TOP_CG_TML: + return AUDIO_TOP_CON0; + case MT8365_TOP_CG_I2S1_BCLK: + case MT8365_TOP_CG_I2S2_BCLK: + case MT8365_TOP_CG_I2S3_BCLK: + case MT8365_TOP_CG_I2S4_BCLK: + case MT8365_TOP_CG_DMIC0_ADC: + case MT8365_TOP_CG_DMIC1_ADC: + case MT8365_TOP_CG_DMIC2_ADC: + case MT8365_TOP_CG_DMIC3_ADC: + case MT8365_TOP_CG_CONNSYS_I2S_ASRC: + case MT8365_TOP_CG_GENERAL1_ASRC: + case MT8365_TOP_CG_GENERAL2_ASRC: + case MT8365_TOP_CG_TDM_ASRC: + return AUDIO_TOP_CON1; + default: + return 0; + } +} + +static unsigned int get_top_cg_mask(unsigned int cg_type) +{ + switch (cg_type) { + case MT8365_TOP_CG_AFE: + return AUD_TCON0_PDN_AFE; + case MT8365_TOP_CG_I2S_IN: + return AUD_TCON0_PDN_I2S_IN; + case MT8365_TOP_CG_22M: + return AUD_TCON0_PDN_22M; + case MT8365_TOP_CG_24M: + return AUD_TCON0_PDN_24M; + case MT8365_TOP_CG_INTDIR_CK: + return AUD_TCON0_PDN_INTDIR; + case MT8365_TOP_CG_APLL2_TUNER: + return AUD_TCON0_PDN_APLL2_TUNER; + case MT8365_TOP_CG_APLL_TUNER: + return AUD_TCON0_PDN_APLL_TUNER; + case MT8365_TOP_CG_SPDIF: + return AUD_TCON0_PDN_SPDIF; + case MT8365_TOP_CG_TDM_OUT: + return AUD_TCON0_PDN_TDM_OUT; + case MT8365_TOP_CG_TDM_IN: + return AUD_TCON0_PDN_TDM_IN; + case MT8365_TOP_CG_ADC: + return AUD_TCON0_PDN_ADC; + case MT8365_TOP_CG_DAC: + return AUD_TCON0_PDN_DAC; + case MT8365_TOP_CG_DAC_PREDIS: + return AUD_TCON0_PDN_DAC_PREDIS; + case MT8365_TOP_CG_TML: + return AUD_TCON0_PDN_TML; + case MT8365_TOP_CG_I2S1_BCLK: + return AUD_TCON1_PDN_I2S1_BCLK; + case MT8365_TOP_CG_I2S2_BCLK: + return AUD_TCON1_PDN_I2S2_BCLK; + case MT8365_TOP_CG_I2S3_BCLK: + return AUD_TCON1_PDN_I2S3_BCLK; + case MT8365_TOP_CG_I2S4_BCLK: + return AUD_TCON1_PDN_I2S4_BCLK; + case MT8365_TOP_CG_DMIC0_ADC: + return AUD_TCON1_PDN_DMIC0_ADC; + case MT8365_TOP_CG_DMIC1_ADC: + return AUD_TCON1_PDN_DMIC1_ADC; + case MT8365_TOP_CG_DMIC2_ADC: + return AUD_TCON1_PDN_DMIC2_ADC; + case MT8365_TOP_CG_DMIC3_ADC: + return AUD_TCON1_PDN_DMIC3_ADC; + case MT8365_TOP_CG_CONNSYS_I2S_ASRC: + return AUD_TCON1_PDN_CONNSYS_I2S_ASRC; + case MT8365_TOP_CG_GENERAL1_ASRC: + return AUD_TCON1_PDN_GENERAL1_ASRC; + case MT8365_TOP_CG_GENERAL2_ASRC: + return AUD_TCON1_PDN_GENERAL2_ASRC; + case MT8365_TOP_CG_TDM_ASRC: + return AUD_TCON1_PDN_TDM_ASRC; + default: + return 0; + } +} + +static unsigned int get_top_cg_on_val(unsigned int cg_type) +{ + return 0; +} + +static unsigned int get_top_cg_off_val(unsigned int cg_type) +{ + return get_top_cg_mask(cg_type); +} + +int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + unsigned int reg = get_top_cg_reg(cg_type); + unsigned int mask = get_top_cg_mask(cg_type); + unsigned int val = get_top_cg_on_val(cg_type); + unsigned long flags; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + afe_priv->top_cg_ref_cnt[cg_type]++; + if (afe_priv->top_cg_ref_cnt[cg_type] == 1) + regmap_update_bits(afe->regmap, reg, mask, val); + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + unsigned int reg = get_top_cg_reg(cg_type); + unsigned int mask = get_top_cg_mask(cg_type); + unsigned int val = get_top_cg_off_val(cg_type); + unsigned long flags; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + afe_priv->top_cg_ref_cnt[cg_type]--; + if (afe_priv->top_cg_ref_cnt[cg_type] == 0) + regmap_update_bits(afe->regmap, reg, mask, val); + else if (afe_priv->top_cg_ref_cnt[cg_type] < 0) + afe_priv->top_cg_ref_cnt[cg_type] = 0; + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + clk_prepare_enable(afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE); + mt8365_afe_enable_afe_on(afe); + + return 0; +} + +int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + mt8365_afe_disable_afe_on(afe); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE); + mt8365_afe_disable_clk(afe, afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]); + + return 0; +} + +int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe) +{ + return 0; +} + +int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe) +{ + return 0; +} + +int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + unsigned long flags; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + afe_priv->afe_on_ref_cnt++; + if (afe_priv->afe_on_ref_cnt == 1) + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + unsigned long flags; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + afe_priv->afe_on_ref_cnt--; + if (afe_priv->afe_on_ref_cnt == 0) + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0); + else if (afe_priv->afe_on_ref_cnt < 0) + afe_priv->afe_on_ref_cnt = 0; + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +static int mt8365_afe_hd_engen_enable(struct mtk_base_afe *afe, bool apll1) +{ + if (apll1) + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_PLL_EN, AFE_22M_PLL_EN); + else + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_PLL_EN, AFE_24M_PLL_EN); + + return 0; +} + +static int mt8365_afe_hd_engen_disable(struct mtk_base_afe *afe, bool apll1) +{ + if (apll1) + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_PLL_EN, ~AFE_22M_PLL_EN); + else + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_PLL_EN, ~AFE_24M_PLL_EN); + + return 0; +} + +int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + mutex_lock(&afe_priv->afe_clk_mutex); + + afe_priv->apll_tuner_ref_cnt[apll]++; + if (afe_priv->apll_tuner_ref_cnt[apll] != 1) { + mutex_unlock(&afe_priv->afe_clk_mutex); + return 0; + } + + if (apll == MT8365_AFE_APLL1) { + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG, + AFE_APLL_TUNER_CFG_MASK, 0x432); + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG, + AFE_APLL_TUNER_CFG_EN_MASK, 0x1); + } else { + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1, + AFE_APLL_TUNER_CFG1_MASK, 0x434); + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1, + AFE_APLL_TUNER_CFG1_EN_MASK, 0x1); + } + + mutex_unlock(&afe_priv->afe_clk_mutex); + return 0; +} + +int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + mutex_lock(&afe_priv->afe_clk_mutex); + + afe_priv->apll_tuner_ref_cnt[apll]--; + if (afe_priv->apll_tuner_ref_cnt[apll] == 0) { + if (apll == MT8365_AFE_APLL1) + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG, + AFE_APLL_TUNER_CFG_EN_MASK, 0x0); + else + regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1, + AFE_APLL_TUNER_CFG1_EN_MASK, 0x0); + + } else if (afe_priv->apll_tuner_ref_cnt[apll] < 0) { + afe_priv->apll_tuner_ref_cnt[apll] = 0; + } + + mutex_unlock(&afe_priv->afe_clk_mutex); + return 0; +} + +int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + if (apll == MT8365_AFE_APLL1) { + if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN1])) { + dev_info(afe->dev, "%s Failed to enable ENGEN1 clk\n", + __func__); + return 0; + } + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_22M); + mt8365_afe_hd_engen_enable(afe, true); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER); + mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL1); + } else { + if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN2])) { + dev_info(afe->dev, "%s Failed to enable ENGEN2 clk\n", + __func__); + return 0; + } + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_24M); + mt8365_afe_hd_engen_enable(afe, false); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER); + mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL2); + } + + return 0; +} + +int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + if (apll == MT8365_AFE_APLL1) { + mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL1); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER); + mt8365_afe_hd_engen_disable(afe, true); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_22M); + clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN1]); + } else { + mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL2); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER); + mt8365_afe_hd_engen_disable(afe, false); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_24M); + clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN2]); + } + + return 0; +} diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.h b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h new file mode 100644 index 000000000000..a6fa653f2183 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * MediaTek 8365 AFE clock control definitions + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#ifndef _MT8365_AFE_UTILS_H_ +#define _MT8365_AFE_UTILS_H_ + +struct mtk_base_afe; +struct clk; + +int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe); +void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk); +int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, unsigned int rate); +int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, struct clk *parent); +int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type); +int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type); +int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe); +int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe); +int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe); +int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe); +int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe); +int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe); +int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll); +int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll); +int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll); +int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll); +#endif diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-common.h b/sound/soc/mediatek/mt8365/mt8365-afe-common.h new file mode 100644 index 000000000000..731406e15ac7 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-afe-common.h @@ -0,0 +1,448 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * MediaTek 8365 audio driver common definitions + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#ifndef _MT8365_AFE_COMMON_H_ +#define _MT8365_AFE_COMMON_H_ + +#include +#include +#include +#include +#include +#include "../common/mtk-base-afe.h" +#include "mt8365-reg.h" + +enum { + MT8365_AFE_MEMIF_DL1, + MT8365_AFE_MEMIF_DL2, + MT8365_AFE_MEMIF_TDM_OUT, + /* + * MT8365_AFE_MEMIF_SPDIF_OUT, + */ + MT8365_AFE_MEMIF_AWB, + MT8365_AFE_MEMIF_VUL, + MT8365_AFE_MEMIF_VUL2, + MT8365_AFE_MEMIF_VUL3, + MT8365_AFE_MEMIF_TDM_IN, + /* + * MT8365_AFE_MEMIF_SPDIF_IN, + */ + MT8365_AFE_MEMIF_NUM, + MT8365_AFE_BACKEND_BASE = MT8365_AFE_MEMIF_NUM, + MT8365_AFE_IO_TDM_OUT = MT8365_AFE_BACKEND_BASE, + MT8365_AFE_IO_TDM_IN, + MT8365_AFE_IO_I2S, + MT8365_AFE_IO_2ND_I2S, + MT8365_AFE_IO_PCM1, + MT8365_AFE_IO_VIRTUAL_DL_SRC, + MT8365_AFE_IO_VIRTUAL_TDM_OUT_SRC, + MT8365_AFE_IO_VIRTUAL_FM, + MT8365_AFE_IO_DMIC, + MT8365_AFE_IO_INT_ADDA, + MT8365_AFE_IO_GASRC1, + MT8365_AFE_IO_GASRC2, + MT8365_AFE_IO_TDM_ASRC, + MT8365_AFE_IO_HW_GAIN1, + MT8365_AFE_IO_HW_GAIN2, + MT8365_AFE_BACKEND_END, + MT8365_AFE_BACKEND_NUM = (MT8365_AFE_BACKEND_END - + MT8365_AFE_BACKEND_BASE), +}; + +enum { + MT8365_AFE_IRQ1, + MT8365_AFE_IRQ2, + MT8365_AFE_IRQ3, + MT8365_AFE_IRQ4, + MT8365_AFE_IRQ5, + MT8365_AFE_IRQ6, + MT8365_AFE_IRQ7, + MT8365_AFE_IRQ8, + MT8365_AFE_IRQ9, + MT8365_AFE_IRQ10, + MT8365_AFE_IRQ_NUM, +}; + +enum { + MT8365_TOP_CG_AFE, + MT8365_TOP_CG_I2S_IN, + MT8365_TOP_CG_22M, + MT8365_TOP_CG_24M, + MT8365_TOP_CG_INTDIR_CK, + MT8365_TOP_CG_APLL2_TUNER, + MT8365_TOP_CG_APLL_TUNER, + MT8365_TOP_CG_SPDIF, + MT8365_TOP_CG_TDM_OUT, + MT8365_TOP_CG_TDM_IN, + MT8365_TOP_CG_ADC, + MT8365_TOP_CG_DAC, + MT8365_TOP_CG_DAC_PREDIS, + MT8365_TOP_CG_TML, + MT8365_TOP_CG_I2S1_BCLK, + MT8365_TOP_CG_I2S2_BCLK, + MT8365_TOP_CG_I2S3_BCLK, + MT8365_TOP_CG_I2S4_BCLK, + MT8365_TOP_CG_DMIC0_ADC, + MT8365_TOP_CG_DMIC1_ADC, + MT8365_TOP_CG_DMIC2_ADC, + MT8365_TOP_CG_DMIC3_ADC, + MT8365_TOP_CG_CONNSYS_I2S_ASRC, + MT8365_TOP_CG_GENERAL1_ASRC, + MT8365_TOP_CG_GENERAL2_ASRC, + MT8365_TOP_CG_TDM_ASRC, + MT8365_TOP_CG_NUM +}; + +enum { + MT8365_CLK_TOP_AUD_SEL, + MT8365_CLK_AUD_I2S0_M, + MT8365_CLK_AUD_I2S1_M, + MT8365_CLK_AUD_I2S2_M, + MT8365_CLK_AUD_I2S3_M, + MT8365_CLK_ENGEN1, + MT8365_CLK_ENGEN2, + MT8365_CLK_AUD1, + MT8365_CLK_AUD2, + MT8365_CLK_I2S0_M_SEL, + MT8365_CLK_I2S1_M_SEL, + MT8365_CLK_I2S2_M_SEL, + MT8365_CLK_I2S3_M_SEL, + MT8365_CLK_CLK26M, + MT8365_CLK_NUM +}; + +enum { + MT8365_AFE_APLL1 = 0, + MT8365_AFE_APLL2, + MT8365_AFE_APLL_NUM, +}; + +enum { + MT8365_AFE_1ST_I2S = 0, + MT8365_AFE_2ND_I2S, + MT8365_AFE_I2S_SETS, +}; + +enum { + MT8365_AFE_I2S_SEPARATE_CLOCK = 0, + MT8365_AFE_I2S_SHARED_CLOCK, +}; + +enum { + MT8365_AFE_TDM_OUT_I2S = 0, + MT8365_AFE_TDM_OUT_TDM, + MT8365_AFE_TDM_OUT_I2S_32BITS, +}; + +enum mt8365_afe_tdm_ch_start { + AFE_TDM_CH_START_O28_O29 = 0, + AFE_TDM_CH_START_O30_O31, + AFE_TDM_CH_START_O32_O33, + AFE_TDM_CH_START_O34_O35, + AFE_TDM_CH_ZERO, +}; + +enum { + MT8365_PCM_FORMAT_I2S = 0, + MT8365_PCM_FORMAT_EIAJ, + MT8365_PCM_FORMAT_PCMA, + MT8365_PCM_FORMAT_PCMB, +}; + +enum { + MT8365_FS_8K = 0, + MT8365_FS_11D025K, + MT8365_FS_12K, + MT8365_FS_384K, + MT8365_FS_16K, + MT8365_FS_22D05K, + MT8365_FS_24K, + MT8365_FS_130K, + MT8365_FS_32K, + MT8365_FS_44D1K, + MT8365_FS_48K, + MT8365_FS_88D2K, + MT8365_FS_96K, + MT8365_FS_176D4K, + MT8365_FS_192K, +}; + +enum { + FS_8000HZ = 0, /* 0000b */ + FS_11025HZ = 1, /* 0001b */ + FS_12000HZ = 2, /* 0010b */ + FS_384000HZ = 3, /* 0011b */ + FS_16000HZ = 4, /* 0100b */ + FS_22050HZ = 5, /* 0101b */ + FS_24000HZ = 6, /* 0110b */ + FS_130000HZ = 7, /* 0111b */ + FS_32000HZ = 8, /* 1000b */ + FS_44100HZ = 9, /* 1001b */ + FS_48000HZ = 10, /* 1010b */ + FS_88200HZ = 11, /* 1011b */ + FS_96000HZ = 12, /* 1100b */ + FS_176400HZ = 13, /* 1101b */ + FS_192000HZ = 14, /* 1110b */ + FS_260000HZ = 15, /* 1111b */ +}; + +enum { + MT8365_AFE_DEBUGFS_AFE, + MT8365_AFE_DEBUGFS_MEMIF, + MT8365_AFE_DEBUGFS_IRQ, + MT8365_AFE_DEBUGFS_CONN, + MT8365_AFE_DEBUGFS_DBG, + MT8365_AFE_DEBUGFS_NUM, +}; + +enum { + MT8365_AFE_IRQ_DIR_MCU = 0, + MT8365_AFE_IRQ_DIR_DSP, + MT8365_AFE_IRQ_DIR_BOTH, +}; + +/* MCLK */ +enum { + MT8365_I2S0_MCK = 0, + MT8365_I2S3_MCK, + MT8365_MCK_NUM, +}; + +struct mt8365_fe_dai_data { + bool use_sram; + unsigned int sram_phy_addr; + void __iomem *sram_vir_addr; + unsigned int sram_size; +}; + +struct mt8365_be_dai_data { + bool prepared[SNDRV_PCM_STREAM_LAST + 1]; + unsigned int fmt_mode; +}; + +#define MT8365_CLK_26M 26000000 +#define MT8365_CLK_24M 24000000 +#define MT8365_CLK_22M 22000000 +#define MT8365_CM_UPDATA_CNT_SET 8 + +enum mt8365_cm_num { + MT8365_CM1 = 0, + MT8365_CM2, + MT8365_CM_NUM, +}; + +enum mt8365_cm2_mux_in { + MT8365_FROM_GASRC1 = 1, + MT8365_FROM_GASRC2, + MT8365_FROM_TDM_ASRC, + MT8365_CM_MUX_NUM, +}; + +enum cm2_mux_conn_in { + GENERAL2_ASRC_OUT_LCH = 0, + GENERAL2_ASRC_OUT_RCH = 1, + TDM_IN_CH0 = 2, + TDM_IN_CH1 = 3, + TDM_IN_CH2 = 4, + TDM_IN_CH3 = 5, + TDM_IN_CH4 = 6, + TDM_IN_CH5 = 7, + TDM_IN_CH6 = 8, + TDM_IN_CH7 = 9, + GENERAL1_ASRC_OUT_LCH = 10, + GENERAL1_ASRC_OUT_RCH = 11, + TDM_OUT_ASRC_CH0 = 12, + TDM_OUT_ASRC_CH1 = 13, + TDM_OUT_ASRC_CH2 = 14, + TDM_OUT_ASRC_CH3 = 15, + TDM_OUT_ASRC_CH4 = 16, + TDM_OUT_ASRC_CH5 = 17, + TDM_OUT_ASRC_CH6 = 18, + TDM_OUT_ASRC_CH7 = 19 +}; + +struct mt8365_cm_ctrl_reg { + unsigned int con0; + unsigned int con1; + unsigned int con2; + unsigned int con3; + unsigned int con4; +}; + +struct mt8365_control_data { + bool bypass_cm1; + bool bypass_cm2; + unsigned int loopback_type; +}; + +enum dmic_input_mode { + DMIC_MODE_3P25M = 0, + DMIC_MODE_1P625M, + DMIC_MODE_812P5K, + DMIC_MODE_406P25K, +}; + +enum iir_mode { + IIR_MODE0 = 0, + IIR_MODE1, + IIR_MODE2, + IIR_MODE3, + IIR_MODE4, + IIR_MODE5, +}; + +enum { + MT8365_GASRC1 = 0, + MT8365_GASRC2, + MT8365_GASRC_NUM, + MT8365_TDM_ASRC1 = MT8365_GASRC_NUM, + MT8365_TDM_ASRC2, + MT8365_TDM_ASRC3, + MT8365_TDM_ASRC4, + MT8365_TDM_ASRC_NUM, +}; + +struct mt8365_gasrc_ctrl_reg { + unsigned int con0; + unsigned int con2; + unsigned int con3; + unsigned int con4; + unsigned int con5; + unsigned int con6; + unsigned int con9; + unsigned int con10; + unsigned int con12; + unsigned int con13; +}; + +struct mt8365_gasrc_data { + bool duplex; + bool tx_mode; + bool cali_on; + bool tdm_asrc_out_cm2; + bool iir_on; +}; + +struct mt8365_afe_private { + struct clk *clocks[MT8365_CLK_NUM]; + struct regmap *topckgen; + struct mt8365_fe_dai_data fe_data[MT8365_AFE_MEMIF_NUM]; + struct mt8365_be_dai_data be_data[MT8365_AFE_BACKEND_NUM]; + struct mt8365_control_data ctrl_data; + struct mt8365_gasrc_data gasrc_data[MT8365_TDM_ASRC_NUM]; + int afe_on_ref_cnt; + int top_cg_ref_cnt[MT8365_TOP_CG_NUM]; + void __iomem *afe_sram_vir_addr; + unsigned int afe_sram_phy_addr; + unsigned int afe_sram_size; + /* locks */ + spinlock_t afe_ctrl_lock; + struct mutex afe_clk_mutex; /* Protect & sync APLL TUNER registers access*/ +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_dentry[MT8365_AFE_DEBUGFS_NUM]; +#endif + int apll_tuner_ref_cnt[MT8365_AFE_APLL_NUM]; + unsigned int tdm_out_mode; + unsigned int cm2_mux_input; + + /* dai */ + bool dai_on[MT8365_AFE_BACKEND_END]; + void *dai_priv[MT8365_AFE_BACKEND_END]; +}; + +static inline u32 rx_frequency_palette(unsigned int fs) +{ + /* * + * A = (26M / fs) * 64 + * B = 8125 / A + * return = DEC2HEX(B * 2^23) + */ + switch (fs) { + case FS_8000HZ: return 0x050000; + case FS_11025HZ: return 0x06E400; + case FS_12000HZ: return 0x078000; + case FS_16000HZ: return 0x0A0000; + case FS_22050HZ: return 0x0DC800; + case FS_24000HZ: return 0x0F0000; + case FS_32000HZ: return 0x140000; + case FS_44100HZ: return 0x1B9000; + case FS_48000HZ: return 0x1E0000; + case FS_88200HZ: return 0x372000; + case FS_96000HZ: return 0x3C0000; + case FS_176400HZ: return 0x6E4000; + case FS_192000HZ: return 0x780000; + default: return 0x0; + } +} + +static inline u32 AutoRstThHi(unsigned int fs) +{ + switch (fs) { + case FS_8000HZ: return 0x36000; + case FS_11025HZ: return 0x27000; + case FS_12000HZ: return 0x24000; + case FS_16000HZ: return 0x1B000; + case FS_22050HZ: return 0x14000; + case FS_24000HZ: return 0x12000; + case FS_32000HZ: return 0x0D800; + case FS_44100HZ: return 0x09D00; + case FS_48000HZ: return 0x08E00; + case FS_88200HZ: return 0x04E00; + case FS_96000HZ: return 0x04800; + case FS_176400HZ: return 0x02700; + case FS_192000HZ: return 0x02400; + default: return 0x0; + } +} + +static inline u32 AutoRstThLo(unsigned int fs) +{ + switch (fs) { + case FS_8000HZ: return 0x30000; + case FS_11025HZ: return 0x23000; + case FS_12000HZ: return 0x20000; + case FS_16000HZ: return 0x18000; + case FS_22050HZ: return 0x11000; + case FS_24000HZ: return 0x0FE00; + case FS_32000HZ: return 0x0BE00; + case FS_44100HZ: return 0x08A00; + case FS_48000HZ: return 0x07F00; + case FS_88200HZ: return 0x04500; + case FS_96000HZ: return 0x04000; + case FS_176400HZ: return 0x02300; + case FS_192000HZ: return 0x02000; + default: return 0x0; + } +} + +bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id); +bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id); + +int mt8365_dai_i2s_register(struct mtk_base_afe *afe); +int mt8365_dai_set_priv(struct mtk_base_afe *afe, + int id, + int priv_size, + const void *priv_data); + +int mt8365_afe_fs_timing(unsigned int rate); + +void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable); +int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe, unsigned int rate, int bit_width); + +int mt8365_dai_adda_register(struct mtk_base_afe *afe); +int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe); +int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe); + +int mt8365_dai_dmic_register(struct mtk_base_afe *afe); + +int mt8365_dai_pcm_register(struct mtk_base_afe *afe); + +int mt8365_dai_tdm_register(struct mtk_base_afe *afe); + +#endif diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c new file mode 100644 index 000000000000..743b46572144 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c @@ -0,0 +1,2274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 ALSA SoC AFE platform driver + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt8365-afe-common.h" +#include "mt8365-afe-clk.h" +#include "mt8365-reg.h" +#include "../common/mtk-base-afe.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +#define AFE_BASE_END_OFFSET 8 + +static unsigned int mCM2Input; + +static const unsigned int mt8365_afe_backup_list[] = { + AUDIO_TOP_CON0, + AFE_CONN0, + AFE_CONN1, + AFE_CONN3, + AFE_CONN4, + AFE_CONN5, + AFE_CONN6, + AFE_CONN7, + AFE_CONN8, + AFE_CONN9, + AFE_CONN10, + AFE_CONN11, + AFE_CONN12, + AFE_CONN13, + AFE_CONN14, + AFE_CONN15, + AFE_CONN16, + AFE_CONN17, + AFE_CONN18, + AFE_CONN19, + AFE_CONN20, + AFE_CONN21, + AFE_CONN26, + AFE_CONN27, + AFE_CONN28, + AFE_CONN29, + AFE_CONN30, + AFE_CONN31, + AFE_CONN32, + AFE_CONN33, + AFE_CONN34, + AFE_CONN35, + AFE_CONN36, + AFE_CONN_24BIT, + AFE_CONN_24BIT_1, + AFE_DAC_CON0, + AFE_DAC_CON1, + AFE_DL1_BASE, + AFE_DL1_END, + AFE_DL2_BASE, + AFE_DL2_END, + AFE_VUL_BASE, + AFE_VUL_END, + AFE_AWB_BASE, + AFE_AWB_END, + AFE_VUL3_BASE, + AFE_VUL3_END, + AFE_HDMI_OUT_BASE, + AFE_HDMI_OUT_END, + AFE_HDMI_IN_2CH_BASE, + AFE_HDMI_IN_2CH_END, + AFE_ADDA_UL_DL_CON0, + AFE_ADDA_DL_SRC2_CON0, + AFE_ADDA_DL_SRC2_CON1, + AFE_I2S_CON, + AFE_I2S_CON1, + AFE_I2S_CON2, + AFE_I2S_CON3, + AFE_ADDA_UL_SRC_CON0, + AFE_AUD_PAD_TOP, + AFE_HD_ENGEN_ENABLE, +}; + +static const struct snd_pcm_hardware mt8365_afe_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .buffer_bytes_max = 256 * 1024, + .period_bytes_min = 512, + .period_bytes_max = 128 * 1024, + .periods_min = 2, + .periods_max = 256, + .fifo_size = 0, +}; + +struct mt8365_afe_rate { + unsigned int rate; + unsigned int reg_val; +}; + +static const struct mt8365_afe_rate mt8365_afe_fs_rates[] = { + { .rate = 8000, .reg_val = MT8365_FS_8K }, + { .rate = 11025, .reg_val = MT8365_FS_11D025K }, + { .rate = 12000, .reg_val = MT8365_FS_12K }, + { .rate = 16000, .reg_val = MT8365_FS_16K }, + { .rate = 22050, .reg_val = MT8365_FS_22D05K }, + { .rate = 24000, .reg_val = MT8365_FS_24K }, + { .rate = 32000, .reg_val = MT8365_FS_32K }, + { .rate = 44100, .reg_val = MT8365_FS_44D1K }, + { .rate = 48000, .reg_val = MT8365_FS_48K }, + { .rate = 88200, .reg_val = MT8365_FS_88D2K }, + { .rate = 96000, .reg_val = MT8365_FS_96K }, + { .rate = 176400, .reg_val = MT8365_FS_176D4K }, + { .rate = 192000, .reg_val = MT8365_FS_192K }, +}; + +int mt8365_afe_fs_timing(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt8365_afe_fs_rates); i++) + if (mt8365_afe_fs_rates[i].rate == rate) + return mt8365_afe_fs_rates[i].reg_val; + + return -EINVAL; +} + +bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id) +{ + switch (id) { + case MT8365_AFE_IO_TDM_IN: + if (rate >= 8000 && rate <= 192000) + return true; + break; + case MT8365_AFE_IO_DMIC: + if (rate >= 8000 && rate <= 48000) + return true; + break; + default: + break; + } + + return false; +} + +bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id) +{ + switch (id) { + case MT8365_AFE_IO_TDM_IN: + if (channel >= 1 && channel <= 8) + return true; + break; + case MT8365_AFE_IO_DMIC: + if (channel >= 1 && channel <= 8) + return true; + break; + default: + break; + } + + return false; +} + +static bool mt8365_afe_clk_group_44k(int sample_rate) +{ + if (sample_rate == 11025 || + sample_rate == 22050 || + sample_rate == 44100 || + sample_rate == 88200 || + sample_rate == 176400) + return true; + else + return false; +} + +static bool mt8365_afe_clk_group_48k(int sample_rate) +{ + return (!mt8365_afe_clk_group_44k(sample_rate)); +} + +int mt8365_dai_set_priv(struct mtk_base_afe *afe, int id, + int priv_size, const void *priv_data) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + void *temp_data; + + temp_data = devm_kzalloc(afe->dev, priv_size, GFP_KERNEL); + if (!temp_data) + return -ENOMEM; + + if (priv_data) + memcpy(temp_data, priv_data, priv_size); + + afe_priv->dai_priv[id] = temp_data; + + return 0; +} + +static int mt8365_afe_irq_direction_enable(struct mtk_base_afe *afe, + int irq_id, int direction) +{ + struct mtk_base_afe_irq *irq; + + if (irq_id >= MT8365_AFE_IRQ_NUM) + return -1; + + irq = &afe->irqs[irq_id]; + + if (direction == MT8365_AFE_IRQ_DIR_MCU) { + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, + (1 << irq->irq_data->irq_clr_shift), + 0); + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, + (1 << irq->irq_data->irq_clr_shift), + (1 << irq->irq_data->irq_clr_shift)); + } else if (direction == MT8365_AFE_IRQ_DIR_DSP) { + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, + (1 << irq->irq_data->irq_clr_shift), + (1 << irq->irq_data->irq_clr_shift)); + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, + (1 << irq->irq_data->irq_clr_shift), + 0); + } else { + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, + (1 << irq->irq_data->irq_clr_shift), + (1 << irq->irq_data->irq_clr_shift)); + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, + (1 << irq->irq_data->irq_clr_shift), + (1 << irq->irq_data->irq_clr_shift)); + } + return 0; +} + +static int mt8365_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + return mt8365_afe_fs_timing(rate); +} + +static int mt8365_irq_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + return mt8365_memif_fs(substream, rate); +} + +static const struct mt8365_cm_ctrl_reg cm_ctrl_reg[MT8365_CM_NUM] = { + [MT8365_CM1] = { + .con0 = AFE_CM1_CON0, + .con1 = AFE_CM1_CON1, + .con2 = AFE_CM1_CON2, + .con3 = AFE_CM1_CON3, + .con4 = AFE_CM1_CON4, + }, + [MT8365_CM2] = { + .con0 = AFE_CM2_CON0, + .con1 = AFE_CM2_CON1, + .con2 = AFE_CM2_CON2, + .con3 = AFE_CM2_CON3, + .con4 = AFE_CM2_CON4, + } +}; + +static int mt8365_afe_cm2_mux_conn(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + unsigned int input = afe_priv->cm2_mux_input; + + /* TDM_IN interconnect to CM2 */ + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG1_MASK, + CM2_AFE_CM2_CONN_CFG1(TDM_IN_CH0)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG2_MASK, + CM2_AFE_CM2_CONN_CFG2(TDM_IN_CH1)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG3_MASK, + CM2_AFE_CM2_CONN_CFG3(TDM_IN_CH2)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG4_MASK, + CM2_AFE_CM2_CONN_CFG4(TDM_IN_CH3)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG5_MASK, + CM2_AFE_CM2_CONN_CFG5(TDM_IN_CH4)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN0, + CM2_AFE_CM2_CONN_CFG6_MASK, + CM2_AFE_CM2_CONN_CFG6(TDM_IN_CH5)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG7_MASK, + CM2_AFE_CM2_CONN_CFG7(TDM_IN_CH6)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG8_MASK, + CM2_AFE_CM2_CONN_CFG8(TDM_IN_CH7)); + + /* ref data interconnect to CM2 */ + if (input == MT8365_FROM_GASRC1) { + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG9_MASK, + CM2_AFE_CM2_CONN_CFG9(GENERAL1_ASRC_OUT_LCH)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG10_MASK, + CM2_AFE_CM2_CONN_CFG10(GENERAL1_ASRC_OUT_RCH)); + } else if (input == MT8365_FROM_GASRC2) { + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG9_MASK, + CM2_AFE_CM2_CONN_CFG9(GENERAL2_ASRC_OUT_LCH)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG10_MASK, + CM2_AFE_CM2_CONN_CFG10(GENERAL2_ASRC_OUT_RCH)); + } else if (input == MT8365_FROM_TDM_ASRC) { + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG9_MASK, + CM2_AFE_CM2_CONN_CFG9(TDM_OUT_ASRC_CH0)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG10_MASK, + CM2_AFE_CM2_CONN_CFG10(TDM_OUT_ASRC_CH1)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG11_MASK, + CM2_AFE_CM2_CONN_CFG11(TDM_OUT_ASRC_CH2)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN1, + CM2_AFE_CM2_CONN_CFG12_MASK, + CM2_AFE_CM2_CONN_CFG12(TDM_OUT_ASRC_CH3)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN2, + CM2_AFE_CM2_CONN_CFG13_MASK, + CM2_AFE_CM2_CONN_CFG13(TDM_OUT_ASRC_CH4)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN2, + CM2_AFE_CM2_CONN_CFG14_MASK, + CM2_AFE_CM2_CONN_CFG14(TDM_OUT_ASRC_CH5)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN2, + CM2_AFE_CM2_CONN_CFG15_MASK, + CM2_AFE_CM2_CONN_CFG15(TDM_OUT_ASRC_CH6)); + regmap_update_bits(afe->regmap, AFE_CM2_CONN2, + CM2_AFE_CM2_CONN_CFG16_MASK, + CM2_AFE_CM2_CONN_CFG16(TDM_OUT_ASRC_CH7)); + } else { + dev_err(afe->dev, "%s wrong CM2 input %d\n", __func__, input); + return -1; + } + + return 0; +} + +static int mt8365_afe_get_cm_update_cnt(struct mtk_base_afe *afe, + enum mt8365_cm_num cmNum, + unsigned int rate, unsigned int channel) +{ + unsigned int total_cnt, div_cnt, ch_pair, best_cnt; + unsigned int ch_update_cnt[MT8365_CM_UPDATA_CNT_SET]; + int i; + + /* calculate cm update cnt + * total_cnt = clk / fs, clk is 26m or 24m or 22m + * div_cnt = total_cnt / ch_pair, max ch 16ch ,2ch is a set + * best_cnt < div_cnt ,we set best_cnt = div_cnt -10 + * ch01 = best_cnt, ch23 = 2* ch01_up_cnt + * ch45 = 3* ch01_up_cnt ...ch1415 = 8* ch01_up_cnt + */ + + if (cmNum == MT8365_CM1) { + total_cnt = MT8365_CLK_26M / rate; + } else if (cmNum == MT8365_CM2) { + if (mt8365_afe_clk_group_48k(rate)) + total_cnt = MT8365_CLK_24M / rate; + else + total_cnt = MT8365_CLK_22M / rate; + } else { + return -1; + } + + if (channel % 2) + ch_pair = (channel / 2) + 1; + else + ch_pair = channel / 2; + + div_cnt = total_cnt / ch_pair; + best_cnt = div_cnt - 10; + + if (best_cnt <= 0) + return -1; + + for (i = 0; i < ch_pair; i++) + ch_update_cnt[i] = (i + 1) * best_cnt; + + switch (channel) { + case 16: + fallthrough; + case 15: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4, + CM_AFE_CM_UPDATE_CNT2_MASK, + CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[7])); + fallthrough; + case 14: + fallthrough; + case 13: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4, + CM_AFE_CM_UPDATE_CNT1_MASK, + CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[6])); + fallthrough; + case 12: + fallthrough; + case 11: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3, + CM_AFE_CM_UPDATE_CNT2_MASK, + CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[5])); + fallthrough; + case 10: + fallthrough; + case 9: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3, + CM_AFE_CM_UPDATE_CNT1_MASK, + CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[4])); + fallthrough; + case 8: + fallthrough; + case 7: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2, + CM_AFE_CM_UPDATE_CNT2_MASK, + CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[3])); + fallthrough; + case 6: + fallthrough; + case 5: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2, + CM_AFE_CM_UPDATE_CNT1_MASK, + CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[2])); + fallthrough; + case 4: + fallthrough; + case 3: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1, + CM_AFE_CM_UPDATE_CNT2_MASK, + CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[1])); + fallthrough; + case 2: + fallthrough; + case 1: + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1, + CM_AFE_CM_UPDATE_CNT1_MASK, + CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[0])); + break; + default: + return -1; + } + + return 0; +} + +static int mt8365_afe_configure_cm(struct mtk_base_afe *afe, + enum mt8365_cm_num cmNum, + unsigned int channels, + unsigned int rate) +{ + unsigned int val, mask; + unsigned int fs = mt8365_afe_fs_timing(rate); + + val = FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, (channels - 1)) | + FIELD_PREP(CM_AFE_CM_START_DATA_MASK, 0); + + mask = CM_AFE_CM_CH_NUM_MASK | + CM_AFE_CM_START_DATA_MASK; + + if (cmNum == MT8365_CM1) { + val |= FIELD_PREP(CM_AFE_CM1_IN_MODE_MASK, fs); + + mask |= CM_AFE_CM1_VUL_SEL | + CM_AFE_CM1_IN_MODE_MASK; + } else if (cmNum == MT8365_CM2) { + if (mt8365_afe_clk_group_48k(rate)) + val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 0); + else + val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 1); + + val |= FIELD_PREP(CM_AFE_CM2_TDM_SEL, 1); + + mask |= CM_AFE_CM2_TDM_SEL | + CM_AFE_CM1_IN_MODE_MASK | + CM_AFE_CM2_CLK_SEL; + + mt8365_afe_cm2_mux_conn(afe); + } else { + return -1; + } + + regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con0, mask, val); + + mt8365_afe_get_cm_update_cnt(afe, cmNum, rate, channels); + + return 0; +} + +static int mt8365_afe_fe_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = substream->runtime; + int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; + int ret; + + memif->substream = substream; + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); + + snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); + + mt8365_afe_enable_main_clk(afe); + return ret; +} + +static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; + + memif->substream = NULL; + + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data; + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[dai_id]; + struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id]; + size_t request_size = params_buffer_bytes(params); + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + unsigned int base_end_offset = 8; + int ret, fs; + + dev_info(afe->dev, "%s %s period = %d rate = %d channels = %d\n", + __func__, memif->data->name, params_period_size(params), + rate, channels); + + if (dai_id == MT8365_AFE_MEMIF_VUL2) { + if (!ctrl_data->bypass_cm1) + /* configure cm1 */ + mt8365_afe_configure_cm(afe, MT8365_CM1, + channels, rate); + else + regmap_update_bits(afe->regmap, AFE_CM1_CON0, + CM_AFE_CM1_VUL_SEL, + CM_AFE_CM1_VUL_SEL); + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) { + if (!ctrl_data->bypass_cm2) + /* configure cm2 */ + mt8365_afe_configure_cm(afe, MT8365_CM2, + channels, rate); + else + regmap_update_bits(afe->regmap, AFE_CM2_CON0, + CM_AFE_CM2_TDM_SEL, + ~CM_AFE_CM2_TDM_SEL); + + base_end_offset = 4; + } + + if (request_size > fe_data->sram_size) { + ret = snd_pcm_lib_malloc_pages(substream, request_size); + if (ret < 0) { + dev_err(afe->dev, + "%s %s malloc pages %zu bytes failed %d\n", + __func__, memif->data->name, request_size, ret); + return ret; + } + + fe_data->use_sram = false; + + mt8365_afe_emi_clk_on(afe); + } else { + struct snd_dma_buffer *dma_buf = &substream->dma_buffer; + + dma_buf->dev.type = SNDRV_DMA_TYPE_DEV; + dma_buf->dev.dev = substream->pcm->card->dev; + dma_buf->area = (unsigned char *)fe_data->sram_vir_addr; + dma_buf->addr = fe_data->sram_phy_addr; + dma_buf->bytes = request_size; + snd_pcm_set_runtime_buffer(substream, dma_buf); + + fe_data->use_sram = true; + } + + memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); + memif->buffer_size = substream->runtime->dma_bytes; + + /* start */ + regmap_write(afe->regmap, memif->data->reg_ofs_base, + memif->phys_buf_addr); + /* end */ + regmap_write(afe->regmap, + memif->data->reg_ofs_base + base_end_offset, + memif->phys_buf_addr + memif->buffer_size - 1); + + /* set channel */ + if (memif->data->mono_shift >= 0) { + unsigned int mono = (params_channels(params) == 1) ? 1 : 0; + + if (memif->data->mono_reg < 0) + dev_info(afe->dev, "%s mono_reg is NULL\n", __func__); + else + regmap_update_bits(afe->regmap, memif->data->mono_reg, + 1 << memif->data->mono_shift, + mono << memif->data->mono_shift); + } + + /* set rate */ + if (memif->data->fs_shift < 0) + return 0; + + fs = afe->memif_fs(substream, params_rate(params)); + + if (fs < 0) + return -EINVAL; + + if (memif->data->fs_reg < 0) + dev_info(afe->dev, "%s fs_reg is NULL\n", __func__); + else + regmap_update_bits(afe->regmap, memif->data->fs_reg, + memif->data->fs_maskbit << memif->data->fs_shift, + fs << memif->data->fs_shift); + + return 0; +} + +static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id]; + int ret = 0; + + if (fe_data->use_sram) { + snd_pcm_set_runtime_buffer(substream, NULL); + } else { + ret = snd_pcm_lib_free_pages(substream); + + mt8365_afe_emi_clk_off(afe); + } + + return ret; +} + +static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mtk_base_afe_memif *memif = &afe->memif[dai_id]; + + /* set format */ + if (memif->data->hd_reg >= 0) { + switch (substream->runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + regmap_update_bits(afe->regmap, memif->data->hd_reg, + 3 << memif->data->hd_shift, + 0 << memif->data->hd_shift); + break; + case SNDRV_PCM_FORMAT_S32_LE: + regmap_update_bits(afe->regmap, memif->data->hd_reg, + 3 << memif->data->hd_shift, + 3 << memif->data->hd_shift); + + if (dai_id == MT8365_AFE_MEMIF_TDM_IN) { + regmap_update_bits(afe->regmap, + memif->data->hd_reg, + 3 << memif->data->hd_shift, + 1 << memif->data->hd_shift); + regmap_update_bits(afe->regmap, + memif->data->hd_reg, + 1 << memif->data->hd_align_mshift, + 1 << memif->data->hd_align_mshift); + } + break; + case SNDRV_PCM_FORMAT_S24_LE: + regmap_update_bits(afe->regmap, memif->data->hd_reg, + 3 << memif->data->hd_shift, + 1 << memif->data->hd_shift); + break; + default: + return -EINVAL; + } + } + + mt8365_afe_irq_direction_enable(afe, memif->irq_usage, + MT8365_AFE_IRQ_DIR_MCU); + + return 0; +} + +static int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; + struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* enable channel merge */ + if (dai_id == MT8365_AFE_MEMIF_VUL2 && + !ctrl_data->bypass_cm1) { + regmap_update_bits(afe->regmap, AFE_CM1_CON0, + CM_AFE_CM_ON, CM_AFE_CM_ON); + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN && + !ctrl_data->bypass_cm2) { + regmap_update_bits(afe->regmap, AFE_CM2_CON0, + CM_AFE_CM_ON, CM_AFE_CM_ON); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* disable channel merge */ + if (dai_id == MT8365_AFE_MEMIF_VUL2 && + !ctrl_data->bypass_cm1) { + regmap_update_bits(afe->regmap, AFE_CM1_CON0, + CM_AFE_CM_ON, ~CM_AFE_CM_ON); + } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN && + !ctrl_data->bypass_cm2) { + regmap_update_bits(afe->regmap, AFE_CM2_CON0, + CM_AFE_CM_ON, ~CM_AFE_CM_ON); + } + break; + default: + break; + } + + return mtk_afe_fe_trigger(substream, cmd, dai); +} + +static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mt8365_afe_enable_main_clk(afe); + return 0; +} + +static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + + if (be->prepared[substream->stream]) { + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, + AFE_GAIN1_CON0_EN_MASK, 0); + be->prepared[substream->stream] = false; + } + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + + int fs; + unsigned int val1 = 0, val2 = 0; + + if (be->prepared[substream->stream]) { + dev_info(afe->dev, "%s prepared already\n", __func__); + return 0; + } + + fs = mt8365_afe_fs_timing(substream->runtime->rate); + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, + AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs << 4); + + regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1); + regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2); + if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK)) + regmap_update_bits(afe->regmap, AFE_GAIN1_CUR, + AFE_GAIN1_CUR_MASK, val1); + + regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, + AFE_GAIN1_CON0_EN_MASK, 1); + be->prepared[substream->stream] = true; + + return 0; +} + +static const struct snd_pcm_hardware mt8365_hostless_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +/* dai ops */ +static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + snd_soc_set_runtime_hwparams(substream, &mt8365_hostless_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); + return ret; +} + +/* FE DAIs */ +static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = { + .startup = mt8365_afe_fe_startup, + .shutdown = mt8365_afe_fe_shutdown, + .hw_params = mt8365_afe_fe_hw_params, + .hw_free = mt8365_afe_fe_hw_free, + .prepare = mt8365_afe_fe_prepare, + .trigger = mt8365_afe_fe_trigger, +}; + +static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = { + .startup = mtk_dai_hostless_startup, +}; + +static const struct snd_soc_dai_ops mt8365_afe_hw_gain1_ops = { + .startup = mt8365_afe_hw_gain1_startup, + .shutdown = mt8365_afe_hw_gain1_shutdown, + .prepare = mt8365_afe_hw_gain1_prepare, +}; + +static struct snd_soc_dai_driver mt8365_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8365_AFE_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "DL2", + .id = MT8365_AFE_MEMIF_DL2, + .playback = { + .stream_name = "DL2", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "TDM_OUT", + .id = MT8365_AFE_MEMIF_TDM_OUT, + .playback = { + .stream_name = "TDM_OUT", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "AWB", + .id = MT8365_AFE_MEMIF_AWB, + .capture = { + .stream_name = "AWB", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "VUL", + .id = MT8365_AFE_MEMIF_VUL, + .capture = { + .stream_name = "VUL", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "VUL2", + .id = MT8365_AFE_MEMIF_VUL2, + .capture = { + .stream_name = "VUL2", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "VUL3", + .id = MT8365_AFE_MEMIF_VUL3, + .capture = { + .stream_name = "VUL3", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "TDM_IN", + .id = MT8365_AFE_MEMIF_TDM_IN, + .capture = { + .stream_name = "TDM_IN", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_fe_dai_ops, + }, { + .name = "Hostless FM DAI", + .id = MT8365_AFE_IO_VIRTUAL_FM, + .playback = { + .stream_name = "Hostless FM DL", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Hostless FM UL", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_dai_hostless_ops, + }, { + .name = "HW_GAIN1", + .id = MT8365_AFE_IO_HW_GAIN1, + .playback = { + .stream_name = "HW Gain 1 In", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "HW Gain 1 Out", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_hw_gain1_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + }, +}; + +static const struct snd_kcontrol_new mt8365_afe_o00_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN0, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN0, 7, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o01_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN1, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN1, 8, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o03_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN3, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN3, 7, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN3, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I10 Switch", AFE_CONN3, 10, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o04_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN4, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN4, 8, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN4, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I11 Switch", AFE_CONN4, 11, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o05_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN5, 3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN5, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN5, 7, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN5, 9, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN5, 14, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN5, 16, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN5, 18, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN5, 20, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN5, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I10L Switch", AFE_CONN5, 10, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o06_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN6, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN6, 4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN6, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN6, 8, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN6, 22, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN6, 15, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN6, 17, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN6, 19, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN6, 21, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN6, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I11L Switch", AFE_CONN6, 11, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o07_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN7, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN7, 7, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o08_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN8, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN8, 8, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o09_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN9, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN9, 3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN9, 9, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN9, 14, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN9, 16, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN9, 18, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN9, 20, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o10_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN10, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN10, 4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN10, 22, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN10, 15, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN10, 17, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN10, 19, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN10, 21, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o11_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN11, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN11, 3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN11, 9, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN11, 14, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN11, 16, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN11, 18, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN11, 20, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o12_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN12, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN12, 4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN12, 22, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN12, 15, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN12, 17, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN12, 19, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN12, 21, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o13_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN13, 0, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o14_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN14, 1, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o15_mix[] = { +}; + +static const struct snd_kcontrol_new mt8365_afe_o16_mix[] = { +}; + +static const struct snd_kcontrol_new mt8365_afe_o17_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN17, 3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o18_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN18, 4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN18, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN18, 25, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o19_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN19, 4, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN19, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN19, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN19, 25, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN19, 26, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o20_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN20, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN20, 26, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o21_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN21, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN21, 25, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o22_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN22, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN22, 26, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o23_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN23, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN23, 25, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o24_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN24, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN24, 26, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN24, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN24, 25, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o25_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I27 Switch", AFE_CONN25, 27, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN25, 23, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN25, 25, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o26_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I28 Switch", AFE_CONN26, 28, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN26, 24, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN26, 26, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o27_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN27, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN27, 7, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o28_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN28, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN28, 8, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o29_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN29, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN29, 7, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o30_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN30, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN30, 8, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o31_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I29 Switch", AFE_CONN31, 29, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o32_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I30 Switch", AFE_CONN32, 30, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o33_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I31 Switch", AFE_CONN33, 31, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o34_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I32 Switch", AFE_CONN34_1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o35_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I33 Switch", AFE_CONN35_1, 1, 1, 0), +}; + +static const struct snd_kcontrol_new mt8365_afe_o36_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I34 Switch", AFE_CONN36_1, 2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13, + 0, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14, + 1, 1, 0), +}; + +static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = mCM2Input; + + return 0; +} + +static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + int ret; + + mCM2Input = ucontrol->value.enumerated.item[0]; + + afe_priv->cm2_mux_input = mCM2Input; + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return ret; +} + +static const char * const fmhwgain_text[] = { + "OPEN", "FM_HW_GAIN_IO" +}; + +static const char * const ain_text[] = { + "INT ADC", "EXT ADC", +}; + +static const char * const vul2_in_input_text[] = { + "VUL2_IN_FROM_O17O18", "VUL2_IN_FROM_CM1", +}; + +static const char * const mt8365_afe_cm2_mux_text[] = { + "OPEN", "FROM_GASRC1_OUT", "FROM_GASRC2_OUT", "FROM_TDM_ASRC_OUT", +}; + +static SOC_ENUM_SINGLE_VIRT_DECL(fmhwgain_enum, fmhwgain_text); +static SOC_ENUM_SINGLE_DECL(ain_enum, AFE_ADDA_TOP_CON0, 0, ain_text); +static SOC_ENUM_SINGLE_VIRT_DECL(vul2_in_input_enum, vul2_in_input_text); +static SOC_ENUM_SINGLE_VIRT_DECL(mt8365_afe_cm2_mux_input_enum, + mt8365_afe_cm2_mux_text); + +static const struct snd_kcontrol_new fmhwgain_mux = + SOC_DAPM_ENUM("FM HW Gain Source", fmhwgain_enum); + +static const struct snd_kcontrol_new ain_mux = + SOC_DAPM_ENUM("AIN Source", ain_enum); + +static const struct snd_kcontrol_new vul2_in_input_mux = + SOC_DAPM_ENUM("VUL2 Input", vul2_in_input_enum); + +static const struct snd_kcontrol_new mt8365_afe_cm2_mux_input_mux = + SOC_DAPM_ENUM_EXT("CM2_MUX Source", mt8365_afe_cm2_mux_input_enum, + mt8365_afe_cm2_io_input_mux_get, + mt8365_afe_cm2_io_input_mux_put); + +static const struct snd_soc_dapm_widget mt8365_memif_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I07", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I08", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I05L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I06L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I07L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I08L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I09", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I10", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I11", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I10L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I11L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I20", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I21", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I22", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I23", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I24", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I25", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I27", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I28", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I29", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I30", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I31", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I32", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I33", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I34", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, + mt8365_afe_o00_mix, ARRAY_SIZE(mt8365_afe_o00_mix)), + SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, + mt8365_afe_o01_mix, ARRAY_SIZE(mt8365_afe_o01_mix)), + SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, + mt8365_afe_o03_mix, ARRAY_SIZE(mt8365_afe_o03_mix)), + SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, + mt8365_afe_o04_mix, ARRAY_SIZE(mt8365_afe_o04_mix)), + SND_SOC_DAPM_MIXER("O05", SND_SOC_NOPM, 0, 0, + mt8365_afe_o05_mix, ARRAY_SIZE(mt8365_afe_o05_mix)), + SND_SOC_DAPM_MIXER("O06", SND_SOC_NOPM, 0, 0, + mt8365_afe_o06_mix, ARRAY_SIZE(mt8365_afe_o06_mix)), + SND_SOC_DAPM_MIXER("O07", SND_SOC_NOPM, 0, 0, + mt8365_afe_o07_mix, ARRAY_SIZE(mt8365_afe_o07_mix)), + SND_SOC_DAPM_MIXER("O08", SND_SOC_NOPM, 0, 0, + mt8365_afe_o08_mix, ARRAY_SIZE(mt8365_afe_o08_mix)), + SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, + mt8365_afe_o09_mix, ARRAY_SIZE(mt8365_afe_o09_mix)), + SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, + mt8365_afe_o10_mix, ARRAY_SIZE(mt8365_afe_o10_mix)), + SND_SOC_DAPM_MIXER("O11", SND_SOC_NOPM, 0, 0, + mt8365_afe_o11_mix, ARRAY_SIZE(mt8365_afe_o11_mix)), + SND_SOC_DAPM_MIXER("O12", SND_SOC_NOPM, 0, 0, + mt8365_afe_o12_mix, ARRAY_SIZE(mt8365_afe_o12_mix)), + SND_SOC_DAPM_MIXER("O13", SND_SOC_NOPM, 0, 0, + mt8365_afe_o13_mix, ARRAY_SIZE(mt8365_afe_o13_mix)), + SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, + mt8365_afe_o14_mix, ARRAY_SIZE(mt8365_afe_o14_mix)), + SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, + mt8365_afe_o15_mix, ARRAY_SIZE(mt8365_afe_o15_mix)), + SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, + mt8365_afe_o16_mix, ARRAY_SIZE(mt8365_afe_o16_mix)), + SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, + mt8365_afe_o17_mix, ARRAY_SIZE(mt8365_afe_o17_mix)), + SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, + mt8365_afe_o18_mix, ARRAY_SIZE(mt8365_afe_o18_mix)), + SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, + mt8365_afe_o19_mix, ARRAY_SIZE(mt8365_afe_o19_mix)), + SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, + mt8365_afe_o20_mix, ARRAY_SIZE(mt8365_afe_o20_mix)), + SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, + mt8365_afe_o21_mix, ARRAY_SIZE(mt8365_afe_o21_mix)), + SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, + mt8365_afe_o22_mix, ARRAY_SIZE(mt8365_afe_o22_mix)), + SND_SOC_DAPM_MIXER("O23", SND_SOC_NOPM, 0, 0, + mt8365_afe_o23_mix, ARRAY_SIZE(mt8365_afe_o23_mix)), + SND_SOC_DAPM_MIXER("O24", SND_SOC_NOPM, 0, 0, + mt8365_afe_o24_mix, ARRAY_SIZE(mt8365_afe_o24_mix)), + SND_SOC_DAPM_MIXER("O25", SND_SOC_NOPM, 0, 0, + mt8365_afe_o25_mix, ARRAY_SIZE(mt8365_afe_o25_mix)), + SND_SOC_DAPM_MIXER("O26", SND_SOC_NOPM, 0, 0, + mt8365_afe_o26_mix, ARRAY_SIZE(mt8365_afe_o26_mix)), + SND_SOC_DAPM_MIXER("O27", SND_SOC_NOPM, 0, 0, + mt8365_afe_o27_mix, ARRAY_SIZE(mt8365_afe_o27_mix)), + SND_SOC_DAPM_MIXER("O28", SND_SOC_NOPM, 0, 0, + mt8365_afe_o28_mix, ARRAY_SIZE(mt8365_afe_o28_mix)), + SND_SOC_DAPM_MIXER("O29", SND_SOC_NOPM, 0, 0, + mt8365_afe_o29_mix, ARRAY_SIZE(mt8365_afe_o29_mix)), + SND_SOC_DAPM_MIXER("O30", SND_SOC_NOPM, 0, 0, + mt8365_afe_o30_mix, ARRAY_SIZE(mt8365_afe_o30_mix)), + SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, + mt8365_afe_o31_mix, ARRAY_SIZE(mt8365_afe_o31_mix)), + SND_SOC_DAPM_MIXER("O32", SND_SOC_NOPM, 0, 0, + mt8365_afe_o32_mix, ARRAY_SIZE(mt8365_afe_o32_mix)), + SND_SOC_DAPM_MIXER("O33", SND_SOC_NOPM, 0, 0, + mt8365_afe_o33_mix, ARRAY_SIZE(mt8365_afe_o33_mix)), + SND_SOC_DAPM_MIXER("O34", SND_SOC_NOPM, 0, 0, + mt8365_afe_o34_mix, ARRAY_SIZE(mt8365_afe_o34_mix)), + SND_SOC_DAPM_MIXER("O35", SND_SOC_NOPM, 0, 0, + mt8365_afe_o35_mix, ARRAY_SIZE(mt8365_afe_o35_mix)), + SND_SOC_DAPM_MIXER("O36", SND_SOC_NOPM, 0, 0, + mt8365_afe_o36_mix, ARRAY_SIZE(mt8365_afe_o36_mix)), + SND_SOC_DAPM_MIXER("CM2_Mux IO", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("CM1_IO", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("O17O18", SND_SOC_NOPM, 0, 0, NULL, 0), + /* inter-connections */ + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch1_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)), + SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0, + mtk_hw_gain1_in_ch2_mix, + ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)), + + SND_SOC_DAPM_INPUT("DL Source"), + + SND_SOC_DAPM_MUX("CM2_Mux_IO Input Mux", SND_SOC_NOPM, 0, 0, + &mt8365_afe_cm2_mux_input_mux), + + SND_SOC_DAPM_MUX("AIN Mux", SND_SOC_NOPM, 0, 0, &ain_mux), + SND_SOC_DAPM_MUX("VUL2 Input Mux", SND_SOC_NOPM, 0, 0, + &vul2_in_input_mux), + + SND_SOC_DAPM_MUX("FM HW Gain Mux", SND_SOC_NOPM, 0, 0, &fmhwgain_mux), + + SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"), + SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"), +}; + +static const struct snd_soc_dapm_route mt8365_memif_routes[] = { + /* downlink */ + {"I00", NULL, "2ND I2S Capture"}, + {"I01", NULL, "2ND I2S Capture"}, + {"I05", NULL, "DL1"}, + {"I06", NULL, "DL1"}, + {"I07", NULL, "DL2"}, + {"I08", NULL, "DL2"}, + + {"O03", "I05 Switch", "I05"}, + {"O04", "I06 Switch", "I06"}, + {"O00", "I05 Switch", "I05"}, + {"O01", "I06 Switch", "I06"}, + {"O07", "I05 Switch", "I05"}, + {"O08", "I06 Switch", "I06"}, + {"O27", "I05 Switch", "I05"}, + {"O28", "I06 Switch", "I06"}, + {"O29", "I05 Switch", "I05"}, + {"O30", "I06 Switch", "I06"}, + + {"O03", "I07 Switch", "I07"}, + {"O04", "I08 Switch", "I08"}, + {"O00", "I07 Switch", "I07"}, + {"O01", "I08 Switch", "I08"}, + {"O07", "I07 Switch", "I07"}, + {"O08", "I08 Switch", "I08"}, + + /* uplink */ + {"AWB", NULL, "O05"}, + {"AWB", NULL, "O06"}, + {"VUL", NULL, "O09"}, + {"VUL", NULL, "O10"}, + {"VUL3", NULL, "O11"}, + {"VUL3", NULL, "O12"}, + + {"AIN Mux", "EXT ADC", "I2S Capture"}, + {"I03", NULL, "AIN Mux"}, + {"I04", NULL, "AIN Mux"}, + + {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1", "Hostless FM DL"}, + {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2", "Hostless FM DL"}, + + {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"}, + {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"}, + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"}, + {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"}, + + {"FM HW Gain Mux", "FM_HW_GAIN_IO", "HW Gain 1 Out"}, + {"Hostless FM UL", NULL, "FM HW Gain Mux"}, + {"Hostless FM UL", NULL, "FM 2ND I2S Mux"}, + + {"O05", "I05 Switch", "I05L"}, + {"O06", "I06 Switch", "I06L"}, + {"O05", "I07 Switch", "I07L"}, + {"O06", "I08 Switch", "I08L"}, + + {"O05", "I03 Switch", "I03"}, + {"O06", "I04 Switch", "I04"}, + {"O05", "I00 Switch", "I00"}, + {"O06", "I01 Switch", "I01"}, + {"O05", "I09 Switch", "I09"}, + {"O06", "I22 Switch", "I22"}, + {"O05", "I14 Switch", "I14"}, + {"O06", "I15 Switch", "I15"}, + {"O05", "I16 Switch", "I16"}, + {"O06", "I17 Switch", "I17"}, + {"O05", "I18 Switch", "I18"}, + {"O06", "I19 Switch", "I19"}, + {"O05", "I20 Switch", "I20"}, + {"O06", "I21 Switch", "I21"}, + {"O05", "I23 Switch", "I23"}, + {"O06", "I24 Switch", "I24"}, + + {"O09", "I03 Switch", "I03"}, + {"O10", "I04 Switch", "I04"}, + {"O09", "I00 Switch", "I00"}, + {"O10", "I01 Switch", "I01"}, + {"O09", "I09 Switch", "I09"}, + {"O10", "I22 Switch", "I22"}, + {"O09", "I14 Switch", "I14"}, + {"O10", "I15 Switch", "I15"}, + {"O09", "I16 Switch", "I16"}, + {"O10", "I17 Switch", "I17"}, + {"O09", "I18 Switch", "I18"}, + {"O10", "I19 Switch", "I19"}, + {"O09", "I20 Switch", "I20"}, + {"O10", "I21 Switch", "I21"}, + + {"O11", "I03 Switch", "I03"}, + {"O12", "I04 Switch", "I04"}, + {"O11", "I00 Switch", "I00"}, + {"O12", "I01 Switch", "I01"}, + {"O11", "I09 Switch", "I09"}, + {"O12", "I22 Switch", "I22"}, + {"O11", "I14 Switch", "I14"}, + {"O12", "I15 Switch", "I15"}, + {"O11", "I16 Switch", "I16"}, + {"O12", "I17 Switch", "I17"}, + {"O11", "I18 Switch", "I18"}, + {"O12", "I19 Switch", "I19"}, + {"O11", "I20 Switch", "I20"}, + {"O12", "I21 Switch", "I21"}, + + /* CM2_Mux*/ + {"CM2_Mux IO", NULL, "CM2_Mux_IO Input Mux"}, + + /* VUL2 */ + {"VUL2", NULL, "VUL2 Input Mux"}, + {"VUL2 Input Mux", "VUL2_IN_FROM_O17O18", "O17O18"}, + {"VUL2 Input Mux", "VUL2_IN_FROM_CM1", "CM1_IO"}, + + {"O17O18", NULL, "O17"}, + {"O17O18", NULL, "O18"}, + {"CM1_IO", NULL, "O17"}, + {"CM1_IO", NULL, "O18"}, + {"CM1_IO", NULL, "O19"}, + {"CM1_IO", NULL, "O20"}, + {"CM1_IO", NULL, "O21"}, + {"CM1_IO", NULL, "O22"}, + {"CM1_IO", NULL, "O23"}, + {"CM1_IO", NULL, "O24"}, + {"CM1_IO", NULL, "O25"}, + {"CM1_IO", NULL, "O26"}, + {"CM1_IO", NULL, "O31"}, + {"CM1_IO", NULL, "O32"}, + {"CM1_IO", NULL, "O33"}, + {"CM1_IO", NULL, "O34"}, + {"CM1_IO", NULL, "O35"}, + {"CM1_IO", NULL, "O36"}, + + {"O17", "I14 Switch", "I14"}, + {"O18", "I15 Switch", "I15"}, + {"O19", "I16 Switch", "I16"}, + {"O20", "I17 Switch", "I17"}, + {"O21", "I18 Switch", "I18"}, + {"O22", "I19 Switch", "I19"}, + {"O23", "I20 Switch", "I20"}, + {"O24", "I21 Switch", "I21"}, + {"O25", "I23 Switch", "I23"}, + {"O26", "I24 Switch", "I24"}, + {"O25", "I25 Switch", "I25"}, + {"O26", "I26 Switch", "I26"}, + + {"O17", "I03 Switch", "I03"}, + {"O18", "I04 Switch", "I04"}, + {"O18", "I23 Switch", "I23"}, + {"O18", "I25 Switch", "I25"}, + {"O19", "I04 Switch", "I04"}, + {"O19", "I23 Switch", "I23"}, + {"O19", "I24 Switch", "I24"}, + {"O19", "I25 Switch", "I25"}, + {"O19", "I26 Switch", "I26"}, + {"O20", "I24 Switch", "I24"}, + {"O20", "I26 Switch", "I26"}, + {"O21", "I23 Switch", "I23"}, + {"O21", "I25 Switch", "I25"}, + {"O22", "I24 Switch", "I24"}, + {"O22", "I26 Switch", "I26"}, + + {"O23", "I23 Switch", "I23"}, + {"O23", "I25 Switch", "I25"}, + {"O24", "I24 Switch", "I24"}, + {"O24", "I26 Switch", "I26"}, + {"O24", "I23 Switch", "I23"}, + {"O24", "I25 Switch", "I25"}, + {"O13", "I00 Switch", "I00"}, + {"O14", "I01 Switch", "I01"}, + {"O03", "I10 Switch", "I10"}, + {"O04", "I11 Switch", "I11"}, +}; + +static const struct mtk_base_memif_data memif_data[MT8365_AFE_MEMIF_NUM] = { + { + .name = "DL1", + .id = MT8365_AFE_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 0, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 21, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 16, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 1, + .msb_reg = -1, + .msb_shift = -1, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "DL2", + .id = MT8365_AFE_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 4, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 22, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 18, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 2, + .msb_reg = -1, + .msb_shift = -1, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "TDM OUT", + .id = MT8365_AFE_MEMIF_TDM_OUT, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .fs_reg = -1, + .fs_shift = -1, + .fs_maskbit = -1, + .mono_reg = -1, + .mono_shift = -1, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 28, + .enable_reg = AFE_HDMI_OUT_CON0, + .enable_shift = 0, + .msb_reg = -1, + .msb_shift = -1, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "AWB", + .id = MT8365_AFE_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 12, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 24, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 20, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 6, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 17, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "VUL", + .id = MT8365_AFE_MEMIF_VUL, + .reg_ofs_base = AFE_VUL_BASE, + .reg_ofs_cur = AFE_VUL_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 16, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = 27, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 22, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 3, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 20, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "VUL2", + .id = MT8365_AFE_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL_D2_BASE, + .reg_ofs_cur = AFE_VUL_D2_CUR, + .fs_reg = AFE_DAC_CON0, + .fs_shift = 20, + .fs_maskbit = 0xf, + .mono_reg = -1, + .mono_shift = -1, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 14, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 9, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 21, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "VUL3", + .id = MT8365_AFE_MEMIF_VUL3, + .reg_ofs_base = AFE_VUL3_BASE, + .reg_ofs_cur = AFE_VUL3_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 8, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON0, + .mono_shift = 13, + .hd_reg = AFE_MEMIF_PBUF2_SIZE, + .hd_shift = 10, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 12, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 27, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, { + .name = "TDM IN", + .id = MT8365_AFE_MEMIF_TDM_IN, + .reg_ofs_base = AFE_HDMI_IN_2CH_BASE, + .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR, + .fs_reg = -1, + .fs_shift = -1, + .fs_maskbit = -1, + .mono_reg = AFE_HDMI_IN_2CH_CON0, + .mono_shift = 1, + .hd_reg = AFE_MEMIF_PBUF2_SIZE, + .hd_shift = 8, + .hd_align_mshift = 5, + .enable_reg = AFE_HDMI_IN_2CH_CON0, + .enable_shift = 0, + .msb_reg = AFE_MEMIF_MSB, + .msb_shift = 28, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT8365_AFE_IRQ_NUM] = { + { + .id = MT8365_AFE_IRQ1, + .irq_cnt_reg = AFE_IRQ_MCU_CNT1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 0, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 4, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 0, + }, { + .id = MT8365_AFE_IRQ2, + .irq_cnt_reg = AFE_IRQ_MCU_CNT2, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 1, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 8, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 1, + }, { + .id = MT8365_AFE_IRQ3, + .irq_cnt_reg = AFE_IRQ_MCU_CNT3, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 2, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 16, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 2, + }, { + .id = MT8365_AFE_IRQ4, + .irq_cnt_reg = AFE_IRQ_MCU_CNT4, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 3, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 20, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 3, + }, { + .id = MT8365_AFE_IRQ5, + .irq_cnt_reg = AFE_IRQ_MCU_CNT5, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 3, + .irq_fs_reg = -1, + .irq_fs_shift = 0, + .irq_fs_maskbit = 0x0, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 4, + }, { + .id = MT8365_AFE_IRQ6, + .irq_cnt_reg = -1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x0, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 13, + .irq_fs_reg = -1, + .irq_fs_shift = 0, + .irq_fs_maskbit = 0x0, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 5, + }, { + .id = MT8365_AFE_IRQ7, + .irq_cnt_reg = AFE_IRQ_MCU_CNT7, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 14, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 24, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 6, + }, { + .id = MT8365_AFE_IRQ8, + .irq_cnt_reg = AFE_IRQ_MCU_CNT8, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 15, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 28, + .irq_fs_maskbit = 0xf, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 7, + }, { + .id = MT8365_AFE_IRQ9, + .irq_cnt_reg = -1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x0, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 2, + .irq_fs_reg = -1, + .irq_fs_shift = 0, + .irq_fs_maskbit = 0x0, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 8, + }, { + .id = MT8365_AFE_IRQ10, + .irq_cnt_reg = AFE_IRQ_MCU_CNT10, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 4, + .irq_fs_reg = -1, + .irq_fs_shift = 0, + .irq_fs_maskbit = 0x0, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = 9, + }, +}; + +static int memif_specified_irqs[MT8365_AFE_MEMIF_NUM] = { + [MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1, + [MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2, + [MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5, + [MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3, + [MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4, + [MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7, + [MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8, + [MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10, +}; + +static const struct regmap_config mt8365_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = MAX_REGISTER, + .cache_type = REGCACHE_NONE, +}; + +static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id) +{ + struct mtk_base_afe *afe = dev_id; + unsigned int reg_value; + unsigned int mcu_irq_mask; + int i, ret; + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, ®_value); + if (ret) { + dev_err_ratelimited(afe->dev, "%s irq status err\n", __func__); + reg_value = AFE_IRQ_STATUS_BITS; + goto err_irq; + } + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask); + if (ret) { + dev_err_ratelimited(afe->dev, "%s irq mcu_en err\n", __func__); + reg_value = AFE_IRQ_STATUS_BITS; + goto err_irq; + } + + /* only clr cpu irq */ + reg_value &= mcu_irq_mask; + + for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + struct mtk_base_afe_irq *mcu_irq; + + if (memif->irq_usage < 0) + continue; + + mcu_irq = &afe->irqs[memif->irq_usage]; + + if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift))) + continue; + + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, + reg_value & AFE_IRQ_STATUS_BITS); + + return IRQ_HANDLED; +} + +static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int mt8365_afe_runtime_resume(struct device *dev) +{ + return 0; +} + +static int __maybe_unused mt8365_afe_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct regmap *regmap = afe->regmap; + int i; + + mt8365_afe_enable_main_clk(afe); + + if (!afe->reg_back_up) + afe->reg_back_up = + devm_kcalloc(dev, afe->reg_back_up_list_num, + sizeof(unsigned int), GFP_KERNEL); + + for (i = 0; i < afe->reg_back_up_list_num; i++) + regmap_read(regmap, afe->reg_back_up_list[i], + &afe->reg_back_up[i]); + + mt8365_afe_disable_main_clk(afe); + + return 0; +} + +static int __maybe_unused mt8365_afe_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct regmap *regmap = afe->regmap; + int i = 0; + + if (!afe->reg_back_up) + return 0; + + mt8365_afe_enable_main_clk(afe); + + for (i = 0; i < afe->reg_back_up_list_num; i++) + regmap_write(regmap, afe->reg_back_up_list[i], + afe->reg_back_up[i]); + + mt8365_afe_disable_main_clk(afe); + + return 0; +} + +static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + + if (pm_runtime_status_suspended(dev) || afe->suspended) + return 0; + + mt8365_afe_suspend(dev); + afe->suspended = true; + return 0; +} + +static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + + if (pm_runtime_status_suspended(dev) || !afe->suspended) + return 0; + + mt8365_afe_resume(dev); + afe->suspended = false; + return 0; +} + +static int mt8365_afe_init_registers(struct mtk_base_afe *afe) +{ + size_t i; + + static struct { + unsigned int reg; + unsigned int mask; + unsigned int val; + } init_regs[] = { + { AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) }, + { AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) }, + }; + + mt8365_afe_enable_main_clk(afe); + + for (i = 0; i < ARRAY_SIZE(init_regs); i++) + regmap_update_bits(afe->regmap, init_regs[i].reg, + init_regs[i].mask, init_regs[i].val); + + mt8365_afe_disable_main_clk(afe); + + return 0; +} + +static int mt8365_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt8365_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver); + + dai->dapm_widgets = mt8365_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets); + dai->dapm_routes = mt8365_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes); + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8365_dai_pcm_register, + mt8365_dai_i2s_register, + mt8365_dai_adda_register, + mt8365_dai_dmic_register, + mt8365_dai_memif_register, +}; + +static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt8365_afe_private *afe_priv; + struct device *dev; + int ret, i, sel_irq; + unsigned int irq_id; + struct resource *res; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + dev = afe->dev; + + spin_lock_init(&afe_priv->afe_ctrl_lock); + mutex_init(&afe_priv->afe_clk_mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(afe->base_addr)) + return PTR_ERR(afe->base_addr); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + afe_priv->afe_sram_vir_addr = + devm_ioremap_resource(&pdev->dev, res); + if (!IS_ERR(afe_priv->afe_sram_vir_addr)) { + afe_priv->afe_sram_phy_addr = res->start; + afe_priv->afe_sram_size = resource_size(res); + } + } + + /* initial audio related clock */ + ret = mt8365_afe_init_audio_clk(afe); + if (ret) + return dev_err_probe(afe->dev, ret, "mt8365_afe_init_audio_clk fail\n"); + + afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel", + afe->base_addr, + &mt8365_afe_regmap_config); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + /* memif % irq initialize*/ + afe->memif_size = MT8365_AFE_MEMIF_NUM; + afe->memif = devm_kcalloc(afe->dev, afe->memif_size, + sizeof(*afe->memif), GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + afe->irqs_size = MT8365_AFE_IRQ_NUM; + afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size, + sizeof(*afe->irqs), GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + + irq_id = ret; + ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler, + 0, "Afe_ISR_Handle", (void *)afe); + if (ret) + return dev_err_probe(afe->dev, ret, "could not request_irq\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(afe->dev, "dai register i %d fail, ret %d\n", + i, ret); + return ret; + } + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) { + dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", + ret); + return ret; + } + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + sel_irq = memif_specified_irqs[i]; + if (sel_irq >= 0) { + afe->memif[i].irq_usage = sel_irq; + afe->memif[i].const_irq = 1; + afe->irqs[sel_irq].irq_occupyed = true; + } else { + afe->memif[i].irq_usage = -1; + } + } + + afe->mtk_afe_hardware = &mt8365_afe_hardware; + afe->memif_fs = mt8365_memif_fs; + afe->irq_fs = mt8365_irq_fs; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + pm_runtime_get_sync(&pdev->dev); + afe->reg_back_up_list = mt8365_afe_backup_list; + afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list); + afe->runtime_resume = mt8365_afe_runtime_resume; + afe->runtime_suspend = mt8365_afe_runtime_suspend; + + /* open afe pdn for dapm read/write audio register */ + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE); + + /* Set 26m parent clk */ + mt8365_afe_set_clk_parent(afe, + afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL], + afe_priv->clocks[MT8365_CLK_CLK26M]); + + ret = devm_snd_soc_register_component(&pdev->dev, + &mtk_afe_pcm_platform, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) { + dev_warn(dev, "err_platform\n"); + return ret; + } + + mt8365_afe_init_registers(afe); + + return 0; +} + +static void mt8365_afe_pcm_dev_remove(struct platform_device *pdev) +{ + struct mtk_base_afe *afe = platform_get_drvdata(pdev); + + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt8365_afe_runtime_suspend(&pdev->dev); +} + +static const struct of_device_id mt8365_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8365-afe-pcm", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match); + +static const struct dev_pm_ops mt8365_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend, + mt8365_afe_dev_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend, + mt8365_afe_resume) +}; + +static struct platform_driver mt8365_afe_pcm_driver = { + .driver = { + .name = "mt8365-afe-pcm", + .of_match_table = mt8365_afe_pcm_dt_match, + .pm = &mt8365_afe_pm_ops, + }, + .probe = mt8365_afe_pcm_dev_probe, + .remove = mt8365_afe_pcm_dev_remove, +}; + +module_platform_driver(mt8365_afe_pcm_driver); + +MODULE_DESCRIPTION("MediaTek ALSA SoC AFE platform driver"); +MODULE_AUTHOR("Jia Zeng "); +MODULE_AUTHOR("Alexandre Mergnat "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-adda.c b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c new file mode 100644 index 000000000000..a04c24bbfcff --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 ALSA SoC Audio DAI ADDA Control + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include +#include +#include +#include "mt8365-afe-clk.h" +#include "mt8365-afe-common.h" +#include "../common/mtk-dai-adda-common.h" + +static int adda_afe_on_ref_cnt; + +/* DAI Drivers */ + +static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate) +{ + unsigned int val; + + if (rate == 8000 || rate == 16000) + val = AFE_ADDA_DL_VOICE_DATA; + else + val = 0; + + val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE, + mtk_adda_dl_rate_transform(afe, rate)); + val |= AFE_ADDA_DL_8X_UPSAMPLE | + AFE_ADDA_DL_MUTE_OFF_CH1 | + AFE_ADDA_DL_MUTE_OFF_CH2 | + AFE_ADDA_DL_DEGRADE_GAIN; + + regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0); + regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0); + regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val); + /* SA suggest apply -0.3db to audio/speech path */ + regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1, + 0xffffffff, 0xf74f0000); + /* SA suggest use default value for sdm */ + regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON, + 0xffffffff, 0x0700701e); + + return 0; +} + +static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate) +{ + unsigned int val; + + val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE, + mtk_adda_ul_rate_transform(afe, rate)); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + AFE_ADDA_UL_SAMPLING_RATE, val); + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0); + + return 0; +} + +int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe) +{ + unsigned long flags; + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + adda_afe_on_ref_cnt++; + if (adda_afe_on_ref_cnt == 1) + regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, + AFE_ADDA_UL_DL_ADDA_AFE_ON, + AFE_ADDA_UL_DL_ADDA_AFE_ON); + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe) +{ + unsigned long flags; + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + adda_afe_on_ref_cnt--; + if (adda_afe_on_ref_cnt == 0) + regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, + AFE_ADDA_UL_DL_ADDA_AFE_ON, + ~AFE_ADDA_UL_DL_ADDA_AFE_ON); + else if (adda_afe_on_ref_cnt < 0) { + adda_afe_on_ref_cnt = 0; + dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n"); + } + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); + + return 0; +} + +static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe, + bool enable) +{ + regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable); + + if (enable) + mt8365_dai_enable_adda_on(afe); + else + mt8365_dai_disable_adda_on(afe); +} + +static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable) +{ + if (enable) { + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1); + mt8365_dai_enable_adda_on(afe); + /* enable aud_pad_top fifo */ + regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, + 0xffffffff, 0x31); + } else { + /* disable aud_pad_top fifo */ + regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, + 0xffffffff, 0x30); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0); + /* de suggest disable ADDA_UL_SRC at least wait 125us */ + usleep_range(150, 300); + mt8365_dai_disable_adda_on(afe); + } +} + +static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int stream = substream->stream; + + mt8365_afe_enable_main_clk(afe); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS); + } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC); + } + + return 0; +} + +static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + unsigned int stream = substream->stream; + + if (be->prepared[stream]) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mt8365_dai_set_adda_out_enable(afe, false); + mt8365_afe_set_i2s_out_enable(afe, false); + } else { + mt8365_dai_set_adda_in_enable(afe, false); + } + be->prepared[stream] = false; + } + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC); + } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC); + } + + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = + &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + unsigned int rate = substream->runtime->rate; + int bit_width = snd_pcm_format_width(substream->runtime->format); + int ret; + + dev_info(afe->dev, "%s '%s' rate = %u\n", __func__, + snd_pcm_stream_str(substream), rate); + + if (be->prepared[substream->stream]) { + dev_info(afe->dev, "%s '%s' prepared already\n", + __func__, snd_pcm_stream_str(substream)); + return 0; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = mt8365_dai_set_adda_out(afe, rate); + if (ret) + return ret; + + ret = mt8365_afe_set_i2s_out(afe, rate, bit_width); + if (ret) + return ret; + + mt8365_dai_set_adda_out_enable(afe, true); + mt8365_afe_set_i2s_out_enable(afe, true); + } else { + ret = mt8365_dai_set_adda_in(afe, rate); + if (ret) + return ret; + + mt8365_dai_set_adda_in_enable(afe, true); + } + be->prepared[substream->stream] = true; + return 0; +} + +static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = { + .startup = mt8365_dai_int_adda_startup, + .shutdown = mt8365_dai_int_adda_shutdown, + .prepare = mt8365_dai_int_adda_prepare, +}; + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "INT ADDA", + .id = MT8365_AFE_IO_INT_ADDA, + .playback = { + .stream_name = "INT ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "INT ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_int_adda_ops, + } +}; + +/* DAI Controls */ + +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3, + 10, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4, + 11, 1, 0), +}; + +static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +/* DAI widget */ + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0, + &int_adda_o03_o04_enable_ctl), + /* inter-connections */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), +}; + +/* DAI route */ + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + {"INT ADDA O03_O04", "Switch", "O03"}, + {"INT ADDA O03_O04", "Switch", "O04"}, + {"INT ADDA Playback", NULL, "INT ADDA O03_O04"}, + {"INT ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"INT ADDA Playback", NULL, "ADDA_DL_CH2"}, + {"AIN Mux", "INT ADC", "INT ADDA Capture"}, + {"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"}, + {"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"}, +}; + +int mt8365_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + list_add(&dai->list, &afe->sub_dais); + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + return 0; +} diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c new file mode 100644 index 000000000000..f9945c2a2cd1 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 ALSA SoC Audio DAI DMIC Control + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include +#include +#include +#include "mt8365-afe-clk.h" +#include "mt8365-afe-common.h" + +struct mt8365_dmic_data { + bool two_wire_mode; + unsigned int clk_phase_sel_ch1; + unsigned int clk_phase_sel_ch2; + bool iir_on; + unsigned int irr_mode; + unsigned int dmic_mode; + unsigned int dmic_channel; +}; + +static int get_chan_reg(unsigned int channel) +{ + switch (channel) { + case 8: + fallthrough; + case 7: + return AFE_DMIC3_UL_SRC_CON0; + case 6: + fallthrough; + case 5: + return AFE_DMIC2_UL_SRC_CON0; + case 4: + fallthrough; + case 3: + return AFE_DMIC1_UL_SRC_CON0; + case 2: + fallthrough; + case 1: + return AFE_DMIC0_UL_SRC_CON0; + default: + return -EINVAL; + } +} + +/* DAI Drivers */ + +static void audio_dmic_adda_enable(struct mtk_base_afe *afe) +{ + mt8365_dai_enable_adda_on(afe); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, + AFE_ADDA_UL_DL_DMIC_CLKDIV_ON, + AFE_ADDA_UL_DL_DMIC_CLKDIV_ON); +} + +static void audio_dmic_adda_disable(struct mtk_base_afe *afe) +{ + regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, + AFE_ADDA_UL_DL_DMIC_CLKDIV_ON, + ~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON); + mt8365_dai_disable_adda_on(afe); +} + +static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC]; + unsigned int val_mask; + int reg = get_chan_reg(dmic_data->dmic_channel); + + if (reg < 0) + return; + + /* val and mask will be always same to enable */ + val_mask = DMIC_TOP_CON_CH1_ON | + DMIC_TOP_CON_CH2_ON | + DMIC_TOP_CON_SRC_ON; + + regmap_update_bits(afe->regmap, reg, val_mask, val_mask); +} + +static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC]; + unsigned int mask; + int reg = get_chan_reg(dmic_data->dmic_channel); + + if (reg < 0) + return; + + dev_dbg(afe->dev, "%s dmic_channel %d\n", __func__, dmic_data->dmic_channel); + + mask = DMIC_TOP_CON_CH1_ON | + DMIC_TOP_CON_CH2_ON | + DMIC_TOP_CON_SRC_ON | + DMIC_TOP_CON_SDM3_LEVEL_MODE; + + /* Set all masked values to 0 */ + regmap_update_bits(afe->regmap, reg, mask, 0); +} + +static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC]; + bool two_wire_mode = dmic_data->two_wire_mode; + unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1; + unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2; + unsigned int val = 0; + unsigned int rate = dai->rate; + int reg = get_chan_reg(dai->channels); + + if (reg < 0) + return -EINVAL; + + dmic_data->dmic_channel = dai->channels; + + val |= DMIC_TOP_CON_SDM3_LEVEL_MODE; + + if (two_wire_mode) { + val |= DMIC_TOP_CON_TWO_WIRE_MODE; + } else { + val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1, + clk_phase_sel_ch1); + val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2, + clk_phase_sel_ch2); + } + + switch (rate) { + case 48000: + val |= DMIC_TOP_CON_VOICE_MODE_48K; + break; + case 32000: + val |= DMIC_TOP_CON_VOICE_MODE_32K; + break; + case 16000: + val |= DMIC_TOP_CON_VOICE_MODE_16K; + break; + case 8000: + val |= DMIC_TOP_CON_VOICE_MODE_8K; + break; + default: + return -EINVAL; + } + + regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val); + + return 0; +} + +static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mt8365_afe_enable_main_clk(afe); + + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC); + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC); + + audio_dmic_adda_enable(afe); + + return 0; +} + +static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mt8365_dai_disable_dmic(afe, substream, dai); + audio_dmic_adda_disable(afe); + /* HW Request delay 125us before CG off */ + usleep_range(125, 300); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC); + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC); + + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mt8365_dai_configure_dmic(afe, substream, dai); + mt8365_dai_enable_dmic(afe, substream, dai); + + return 0; +} + +static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = { + .startup = mt8365_dai_dmic_startup, + .shutdown = mt8365_dai_dmic_shutdown, + .prepare = mt8365_dai_dmic_prepare, +}; + +static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = { + { + .name = "DMIC", + .id = MT8365_AFE_IO_DMIC, + .capture = { + .stream_name = "DMIC Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_dmic_ops, + } +}; + +/* DAI Controls */ + +/* Values for 48kHz mode */ +static const char * const iir_mode_src[] = { + "SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz" +}; + +static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src); + +static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = { + SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0), + SOC_ENUM("DMIC IIR Mode", iir_mode), +}; + +/* DAI widget */ + +static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC In"), +}; + +/* DAI route */ + +static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = { + {"I14", NULL, "DMIC Capture"}, + {"I15", NULL, "DMIC Capture"}, + {"I16", NULL, "DMIC Capture"}, + {"I17", NULL, "DMIC Capture"}, + {"I18", NULL, "DMIC Capture"}, + {"I19", NULL, "DMIC Capture"}, + {"I20", NULL, "DMIC Capture"}, + {"I21", NULL, "DMIC Capture"}, + {"DMIC Capture", NULL, "DMIC In"}, +}; + +static int init_dmic_priv_data(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_dmic_data *dmic_priv; + struct device_node *np = afe->dev->of_node; + unsigned int temps[4]; + int ret; + + dmic_priv = devm_kzalloc(afe->dev, sizeof(*dmic_priv), GFP_KERNEL); + if (!dmic_priv) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "mediatek,dmic-mode", + &temps[0], + 1); + if (ret == 0) + dmic_priv->two_wire_mode = !!temps[0]; + + if (!dmic_priv->two_wire_mode) { + dmic_priv->clk_phase_sel_ch1 = 0; + dmic_priv->clk_phase_sel_ch2 = 4; + } + + afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv; + return 0; +} + +int mt8365_dai_dmic_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + dai->dai_drivers = mtk_dai_dmic_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver); + dai->controls = mtk_dai_dmic_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls); + dai->dapm_widgets = mtk_dai_dmic_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets); + dai->dapm_routes = mtk_dai_dmic_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes); + return init_dmic_priv_data(afe); +} diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c new file mode 100644 index 000000000000..11b9a5bc7163 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 ALSA SoC Audio DAI I2S Control + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include +#include +#include +#include "mt8365-afe-clk.h" +#include "mt8365-afe-common.h" + +#define IIR_RATIOVER 9 +#define IIR_INV_COEF 10 +#define IIR_NO_NEED 11 + +struct mtk_afe_i2s_priv { + bool adda_link; + int i2s_out_on_ref_cnt; + int id; + int low_jitter_en; + int mclk_id; + int share_i2s_id; + unsigned int clk_id_in; + unsigned int clk_id_in_m_sel; + unsigned int clk_id_out; + unsigned int clk_id_out_m_sel; + unsigned int clk_in_mult; + unsigned int clk_out_mult; + unsigned int config_val_in; + unsigned int config_val_out; + unsigned int dynamic_bck; + unsigned int reg_off_in; + unsigned int reg_off_out; +}; + +/* This enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S3, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8365_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8365_AFE_IO_I2S, + .mclk_id = MT8365_I2S0_MCK, + .share_i2s_id = -1, + .clk_id_in = MT8365_CLK_AUD_I2S2_M, + .clk_id_out = MT8365_CLK_AUD_I2S1_M, + .clk_id_in_m_sel = MT8365_CLK_I2S2_M_SEL, + .clk_id_out_m_sel = MT8365_CLK_I2S1_M_SEL, + .clk_in_mult = 256, + .clk_out_mult = 256, + .adda_link = true, + .config_val_out = AFE_I2S_CON1_I2S2_TO_PAD, + .reg_off_in = AFE_I2S_CON2, + .reg_off_out = AFE_I2S_CON1, + }, + [DAI_I2S3] = { + .id = MT8365_AFE_IO_2ND_I2S, + .mclk_id = MT8365_I2S3_MCK, + .share_i2s_id = -1, + .clk_id_in = MT8365_CLK_AUD_I2S0_M, + .clk_id_out = MT8365_CLK_AUD_I2S3_M, + .clk_id_in_m_sel = MT8365_CLK_I2S0_M_SEL, + .clk_id_out_m_sel = MT8365_CLK_I2S3_M_SEL, + .clk_in_mult = 256, + .clk_out_mult = 256, + .adda_link = false, + .config_val_in = AFE_I2S_CON_FROM_IO_MUX, + .reg_off_in = AFE_I2S_CON, + .reg_off_out = AFE_I2S_CON3, + }, +}; + +static const u32 *get_iir_coef(unsigned int input_fs, + unsigned int output_fs, unsigned int *count) +{ + static const u32 IIR_COEF_48_TO_44p1[30] = { + 0x061fb0, 0x0bd256, 0x061fb0, 0xe3a3e6, 0xf0a300, 0x000003, + 0x0e416d, 0x1bb577, 0x0e416d, 0xe59178, 0xf23637, 0x000003, + 0x0c7d72, 0x189060, 0x0c7d72, 0xe96f09, 0xf505b2, 0x000003, + 0x126054, 0x249143, 0x126054, 0xe1fc0c, 0xf4b20a, 0x000002, + 0x000000, 0x323c85, 0x323c85, 0xf76d4e, 0x000000, 0x000002, + }; + + static const u32 IIR_COEF_44p1_TO_32[42] = { + 0x0a6074, 0x0d237a, 0x0a6074, 0xdd8d6c, 0xe0b3f6, 0x000002, + 0x0e41f8, 0x128d48, 0x0e41f8, 0xefc14e, 0xf12d7a, 0x000003, + 0x0cfa60, 0x11e89c, 0x0cfa60, 0xf1b09e, 0xf27205, 0x000003, + 0x15b69c, 0x20e7e4, 0x15b69c, 0xea799a, 0xe9314a, 0x000002, + 0x0f79e2, 0x1a7064, 0x0f79e2, 0xf65e4a, 0xf03d8e, 0x000002, + 0x10c34f, 0x1ffe4b, 0x10c34f, 0x0bbecb, 0xf2bc4b, 0x000001, + 0x000000, 0x23b063, 0x23b063, 0x07335f, 0x000000, 0x000002, + }; + + static const u32 IIR_COEF_48_TO_32[42] = { + 0x0a2a9b, 0x0a2f05, 0x0a2a9b, 0xe73873, 0xe0c525, 0x000002, + 0x0dd4ad, 0x0e765a, 0x0dd4ad, 0xf49808, 0xf14844, 0x000003, + 0x18a8cd, 0x1c40d0, 0x18a8cd, 0xed2aab, 0xe542ec, 0x000002, + 0x13e044, 0x1a47c4, 0x13e044, 0xf44aed, 0xe9acc7, 0x000002, + 0x1abd9c, 0x2a5429, 0x1abd9c, 0xff3441, 0xe0fc5f, 0x000001, + 0x0d86db, 0x193e2e, 0x0d86db, 0x1a6f15, 0xf14507, 0x000001, + 0x000000, 0x1f820c, 0x1f820c, 0x0a1b1f, 0x000000, 0x000002, + }; + + static const u32 IIR_COEF_32_TO_16[48] = { + 0x122893, 0xffadd4, 0x122893, 0x0bc205, 0xc0ee1c, 0x000001, + 0x1bab8a, 0x00750d, 0x1bab8a, 0x06a983, 0xe18a5c, 0x000002, + 0x18f68e, 0x02706f, 0x18f68e, 0x0886a9, 0xe31bcb, 0x000002, + 0x149c05, 0x054487, 0x149c05, 0x0bec31, 0xe5973e, 0x000002, + 0x0ea303, 0x07f24a, 0x0ea303, 0x115ff9, 0xe967b6, 0x000002, + 0x0823fd, 0x085531, 0x0823fd, 0x18d5b4, 0xee8d21, 0x000002, + 0x06888e, 0x0acbbb, 0x06888e, 0x40b55c, 0xe76dce, 0x000001, + 0x000000, 0x2d31a9, 0x2d31a9, 0x23ba4f, 0x000000, 0x000001, + }; + + static const u32 IIR_COEF_96_TO_44p1[48] = { + 0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002, + 0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002, + 0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002, + 0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002, + 0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002, + 0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002, + 0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001, + 0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001, + }; + + static const u32 IIR_COEF_44p1_TO_16[48] = { + 0x0998fb, 0xf7f925, 0x0998fb, 0x1e54a0, 0xe06605, 0x000002, + 0x0d828e, 0xf50f97, 0x0d828e, 0x0f41b5, 0xf0a999, 0x000003, + 0x17ebeb, 0xee30d8, 0x17ebeb, 0x1f48ca, 0xe2ae88, 0x000002, + 0x12fab5, 0xf46ddc, 0x12fab5, 0x20cc51, 0xe4d068, 0x000002, + 0x0c7ac6, 0xfbd00e, 0x0c7ac6, 0x2337da, 0xe8028c, 0x000002, + 0x060ddc, 0x015b3e, 0x060ddc, 0x266754, 0xec21b6, 0x000002, + 0x0407b5, 0x04f827, 0x0407b5, 0x52e3d0, 0xe0149f, 0x000001, + 0x000000, 0x1f9521, 0x1f9521, 0x2ac116, 0x000000, 0x000001, + }; + + static const u32 IIR_COEF_48_TO_16[48] = { + 0x0955ff, 0xf6544a, 0x0955ff, 0x2474e5, 0xe062e6, 0x000002, + 0x0d4180, 0xf297f4, 0x0d4180, 0x12415b, 0xf0a3b0, 0x000003, + 0x0ba079, 0xf4f0b0, 0x0ba079, 0x1285d3, 0xf1488b, 0x000003, + 0x12247c, 0xf1033c, 0x12247c, 0x2625be, 0xe48e0d, 0x000002, + 0x0b98e0, 0xf96d1a, 0x0b98e0, 0x27e79c, 0xe7798a, 0x000002, + 0x055e3b, 0xffed09, 0x055e3b, 0x2a2e2d, 0xeb2854, 0x000002, + 0x01a934, 0x01ca03, 0x01a934, 0x2c4fea, 0xee93ab, 0x000002, + 0x000000, 0x1c46c5, 0x1c46c5, 0x2d37dc, 0x000000, 0x000001, + }; + + static const u32 IIR_COEF_96_TO_16[48] = { + 0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002, + 0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003, + 0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003, + 0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003, + 0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002, + 0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002, + 0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002, + 0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001, + }; + + static const struct { + const u32 *coef; + unsigned int cnt; + } iir_coef_tbl_list[8] = { + /* 0: 0.9188 */ + { IIR_COEF_48_TO_44p1, ARRAY_SIZE(IIR_COEF_48_TO_44p1) }, + /* 1: 0.7256 */ + { IIR_COEF_44p1_TO_32, ARRAY_SIZE(IIR_COEF_44p1_TO_32) }, + /* 2: 0.6667 */ + { IIR_COEF_48_TO_32, ARRAY_SIZE(IIR_COEF_48_TO_32) }, + /* 3: 0.5 */ + { IIR_COEF_32_TO_16, ARRAY_SIZE(IIR_COEF_32_TO_16) }, + /* 4: 0.4594 */ + { IIR_COEF_96_TO_44p1, ARRAY_SIZE(IIR_COEF_96_TO_44p1) }, + /* 5: 0.3628 */ + { IIR_COEF_44p1_TO_16, ARRAY_SIZE(IIR_COEF_44p1_TO_16) }, + /* 6: 0.3333 */ + { IIR_COEF_48_TO_16, ARRAY_SIZE(IIR_COEF_48_TO_16) }, + /* 7: 0.1667 */ + { IIR_COEF_96_TO_16, ARRAY_SIZE(IIR_COEF_96_TO_16) }, + }; + + static const u32 freq_new_index[16] = { + 0, 1, 2, 99, 3, 4, 5, 99, 6, 7, 8, 9, 10, 11, 12, 99 + }; + + static const u32 iir_coef_tbl_matrix[13][13] = { + {/*0*/ + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*1*/ + 1, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*2*/ + 2, 0, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*3*/ + 3, IIR_INV_COEF, IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*4*/ + 5, 3, IIR_INV_COEF, 2, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*5*/ + 6, 4, 3, 2, 0, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED + }, + {/*6*/ + IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 3, IIR_INV_COEF, + IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*7*/ + IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 5, 3, + IIR_INV_COEF, 1, IIR_NO_NEED, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*8*/ + 7, IIR_INV_COEF, IIR_INV_COEF, 6, 4, 3, 2, 0, IIR_NO_NEED, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*9*/ + IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, + IIR_INV_COEF, IIR_INV_COEF, 5, 3, IIR_INV_COEF, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + {/*10*/ + IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 7, IIR_INV_COEF, + IIR_INV_COEF, 6, 4, 3, 0, + IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED + }, + { /*11*/ + IIR_RATIOVER, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, + IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, + IIR_INV_COEF, 3, IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED + }, + {/*12*/ + IIR_RATIOVER, IIR_RATIOVER, IIR_INV_COEF, IIR_INV_COEF, + IIR_INV_COEF, IIR_INV_COEF, 7, IIR_INV_COEF, + IIR_INV_COEF, 4, 3, 0, IIR_NO_NEED + }, + }; + + const u32 *coef = NULL; + unsigned int cnt = 0; + u32 i = freq_new_index[input_fs]; + u32 j = freq_new_index[output_fs]; + + if (i < 13 && j < 13) { + u32 k = iir_coef_tbl_matrix[i][j]; + + if (k >= IIR_NO_NEED) { + } else if (k == IIR_RATIOVER) { + } else if (k == IIR_INV_COEF) { + } else { + coef = iir_coef_tbl_list[k].coef; + cnt = iir_coef_tbl_list[k].cnt; + } + } + *count = cnt; + return coef; +} + +static int mt8365_dai_set_config(struct mtk_base_afe *afe, + struct mtk_afe_i2s_priv *i2s_data, + bool is_input, unsigned int rate, + int bit_width) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = + &afe_priv->be_data[i2s_data->id - MT8365_AFE_BACKEND_BASE]; + unsigned int val, reg_off; + int fs = mt8365_afe_fs_timing(rate); + + if (fs < 0) + return -EINVAL; + + val = AFE_I2S_CON_LOW_JITTER_CLK | AFE_I2S_CON_FORMAT_I2S; + val |= FIELD_PREP(AFE_I2S_CON_RATE_MASK, fs); + + if (is_input) { + reg_off = i2s_data->reg_off_in; + if (i2s_data->adda_link) + val |= i2s_data->config_val_in; + } else { + reg_off = i2s_data->reg_off_out; + val |= i2s_data->config_val_in; + } + + /* 1:bck=32lrck(16bit) or bck=64lrck(32bit) 0:fix bck=64lrck */ + if (i2s_data->dynamic_bck) { + if (bit_width > 16) + val |= AFE_I2S_CON_WLEN_32BIT; + else + val &= ~(u32)AFE_I2S_CON_WLEN_32BIT; + } else { + val |= AFE_I2S_CON_WLEN_32BIT; + } + + if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBM_CFM) { + val |= AFE_I2S_CON_SRC_SLAVE; + val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys + } + + regmap_update_bits(afe->regmap, reg_off, ~(u32)AFE_I2S_CON_EN, val); + + if (i2s_data->adda_link && is_input) + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1); + + return 0; +} + +int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe, + unsigned int rate, int bit_width) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_data = + afe_priv->dai_priv[MT8365_AFE_IO_I2S]; + + return mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width); +} + +static int mt8365_afe_set_2nd_i2s_asrc(struct mtk_base_afe *afe, + unsigned int rate_in, + unsigned int rate_out, + unsigned int width, + unsigned int mono, + int o16bit, int tracking) +{ + int ifs, ofs = 0; + unsigned int val = 0; + unsigned int mask = 0; + const u32 *coef; + u32 iir_stage; + unsigned int coef_count = 0; + + ifs = mt8365_afe_fs_timing(rate_in); + + if (ifs < 0) + return -EINVAL; + + ofs = mt8365_afe_fs_timing(rate_out); + + if (ofs < 0) + return -EINVAL; + + val = FIELD_PREP(O16BIT, o16bit) | FIELD_PREP(IS_MONO, mono); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, + O16BIT | IS_MONO, val); + + coef = get_iir_coef(ifs, ofs, &coef_count); + iir_stage = ((u32)coef_count / 6) - 1; + + if (coef) { + unsigned int i; + + /* CPU control IIR coeff SRAM */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + COEFF_SRAM_CTRL, COEFF_SRAM_CTRL); + + /* set to 0, IIR coeff SRAM addr */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON13, + 0xffffffff, 0x0); + + for (i = 0; i < coef_count; ++i) + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON12, + 0xffffffff, coef[i]); + + /* disable IIR coeff SRAM access */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + COEFF_SRAM_CTRL, + ~COEFF_SRAM_CTRL); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, + CLR_IIR_HISTORY | IIR_EN | IIR_STAGE_MASK, + CLR_IIR_HISTORY | IIR_EN | + FIELD_PREP(IIR_STAGE_MASK, iir_stage)); + } else { + /* disable IIR */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2, + IIR_EN, ~IIR_EN); + } + + /* CON3 setting (RX OFS) */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON3, + 0x00FFFFFF, rx_frequency_palette(ofs)); + /* CON4 setting (RX IFS) */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON4, + 0x00FFFFFF, rx_frequency_palette(ifs)); + + /* CON5 setting */ + if (tracking) { + val = CALI_64_CYCLE | + CALI_AUTORST | + AUTO_TUNE_FREQ5 | + COMP_FREQ_RES | + CALI_BP_DGL | + CALI_AUTO_RESTART | + CALI_USE_FREQ_OUT | + CALI_SEL_01; + + mask = CALI_CYCLE_MASK | + CALI_AUTORST | + AUTO_TUNE_FREQ5 | + COMP_FREQ_RES | + CALI_SEL_MASK | + CALI_BP_DGL | + AUTO_TUNE_FREQ4 | + CALI_AUTO_RESTART | + CALI_USE_FREQ_OUT | + CALI_ON; + + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5, + mask, val); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5, + CALI_ON, CALI_ON); + } else { + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5, + 0xffffffff, 0x0); + } + /* CON6 setting fix 8125 */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON6, + 0x0000ffff, 0x1FBD); + /* CON9 setting (RX IFS) */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON9, + 0x000fffff, AutoRstThHi(ifs)); + /* CON10 setting (RX IFS) */ + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON10, + 0x000fffff, AutoRstThLo(ifs)); + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + CHSET_STR_CLR, CHSET_STR_CLR); + + return 0; +} + +static int mt8365_afe_set_2nd_i2s_asrc_enable(struct mtk_base_afe *afe, + bool enable) +{ + if (enable) + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + ASM_ON, ASM_ON); + else + regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0, + ASM_ON, ~ASM_ON); + return 0; +} + +void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable) +{ + int i; + unsigned long flags; + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_data = NULL; + + for (i = 0; i < DAI_I2S_NUM; i++) { + if (mt8365_i2s_priv[i].adda_link) + i2s_data = afe_priv->dai_priv[mt8365_i2s_priv[i].id]; + } + + if (!i2s_data) + return; + + spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags); + + if (enable) { + i2s_data->i2s_out_on_ref_cnt++; + if (i2s_data->i2s_out_on_ref_cnt == 1) + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0x1, enable); + } else { + i2s_data->i2s_out_on_ref_cnt--; + if (i2s_data->i2s_out_on_ref_cnt == 0) + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0x1, enable); + else if (i2s_data->i2s_out_on_ref_cnt < 0) + i2s_data->i2s_out_on_ref_cnt = 0; + } + + spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags); +} + +static void mt8365_dai_set_enable(struct mtk_base_afe *afe, + struct mtk_afe_i2s_priv *i2s_data, + bool is_input, bool enable) +{ + unsigned int reg_off; + + if (is_input) { + reg_off = i2s_data->reg_off_in; + } else { + if (i2s_data->adda_link) { + mt8365_afe_set_i2s_out_enable(afe, enable); + return; + } + reg_off = i2s_data->reg_off_out; + } + regmap_update_bits(afe->regmap, reg_off, + 0x1, enable); +} + +static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id]; + struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + bool i2s_in_slave = + (substream->stream == SNDRV_PCM_STREAM_CAPTURE) && + ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBM_CFM); + + mt8365_afe_enable_main_clk(afe); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + clk_prepare_enable(afe_priv->clocks[i2s_data->clk_id_out]); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && !i2s_in_slave) + clk_prepare_enable(afe_priv->clocks[i2s_data->clk_id_in]); + + if (i2s_in_slave) + mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_I2S_IN); + + return 0; +} + +static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id]; + struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + bool reset_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + bool reset_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + bool i2s_in_slave = + (substream->stream == SNDRV_PCM_STREAM_CAPTURE) && + ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBM_CFM); + + if (be->prepared[substream->stream]) { + if (reset_i2s_out_change) + mt8365_dai_set_enable(afe, i2s_data, false, false); + + if (reset_i2s_in_change) + mt8365_dai_set_enable(afe, i2s_data, true, false); + + if (substream->runtime->rate % 8000) + mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL1); + else + mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL2); + + if (reset_i2s_out_change) + be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false; + + if (reset_i2s_in_change) + be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false; + } + + if (reset_i2s_out_change) + mt8365_afe_disable_clk(afe, + afe_priv->clocks[i2s_data->clk_id_out]); + + if (reset_i2s_in_change && !i2s_in_slave) + mt8365_afe_disable_clk(afe, + afe_priv->clocks[i2s_data->clk_id_in]); + + if (i2s_in_slave) + mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_I2S_IN); + + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id]; + struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + bool apply_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + bool apply_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + unsigned int rate = substream->runtime->rate; + int bit_width = snd_pcm_format_width(substream->runtime->format); + int ret; + + if (be->prepared[substream->stream]) { + dev_info(afe->dev, "%s '%s' prepared already\n", + __func__, snd_pcm_stream_str(substream)); + return 0; + } + + if (apply_i2s_out_change) { + ret = mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width); + if (ret) + return ret; + } + + if (apply_i2s_in_change) { + if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) + == SND_SOC_DAIFMT_CBM_CFM) { + ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate, + (unsigned int)bit_width, + 0, 0, 1); + if (ret < 0) + return ret; + } + ret = mt8365_dai_set_config(afe, i2s_data, true, rate, bit_width); + if (ret) + return ret; + } + + if (rate % 8000) + mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL1); + else + mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL2); + + if (apply_i2s_out_change) { + mt8365_afe_set_clk_parent(afe, + afe_priv->clocks[i2s_data->clk_id_out_m_sel], + ((rate % 8000) ? + afe_priv->clocks[MT8365_CLK_AUD1] : + afe_priv->clocks[MT8365_CLK_AUD2])); + + mt8365_afe_set_clk_rate(afe, + afe_priv->clocks[i2s_data->clk_id_out], + rate * i2s_data->clk_out_mult); + + mt8365_dai_set_enable(afe, i2s_data, false, true); + be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true; + } + + if (apply_i2s_in_change) { + mt8365_afe_set_clk_parent(afe, + afe_priv->clocks[i2s_data->clk_id_in_m_sel], + ((rate % 8000) ? + afe_priv->clocks[MT8365_CLK_AUD1] : + afe_priv->clocks[MT8365_CLK_AUD2])); + + mt8365_afe_set_clk_rate(afe, + afe_priv->clocks[i2s_data->clk_id_in], + rate * i2s_data->clk_in_mult); + + mt8365_dai_set_enable(afe, i2s_data, true, true); + + if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) + == SND_SOC_DAIFMT_CBM_CFM) + mt8365_afe_set_2nd_i2s_asrc_enable(afe, true); + + be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true; + } + return 0; +} + +static int mt8365_afe_2nd_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int width_val = params_width(params) > 16 ? + (AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01) : 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_update_bits(afe->regmap, AFE_CONN_24BIT, + AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01, width_val); + + return 0; +} + +static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; + + be->fmt_mode = 0; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + be->fmt_mode |= SND_SOC_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + be->fmt_mode |= SND_SOC_DAIFMT_LEFT_J; + break; + default: + dev_err(afe->dev, "invalid audio format for 2nd i2s!\n"); + return -EINVAL; + } + + if (((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) && + ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_IF) && + ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_NF) && + ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_IF)) { + dev_err(afe->dev, "invalid audio format for 2nd i2s!\n"); + return -EINVAL; + } + + be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK); + + if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)) + be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK); + + return 0; +} + +static const struct snd_soc_dai_ops mt8365_afe_i2s_ops = { + .startup = mt8365_dai_i2s_startup, + .shutdown = mt8365_dai_i2s_shutdown, + .prepare = mt8365_dai_i2s_prepare, +}; + +static const struct snd_soc_dai_ops mt8365_afe_2nd_i2s_ops = { + .startup = mt8365_dai_i2s_startup, + .shutdown = mt8365_dai_i2s_shutdown, + .hw_params = mt8365_afe_2nd_i2s_hw_params, + .prepare = mt8365_dai_i2s_prepare, + .set_fmt = mt8365_afe_2nd_i2s_set_fmt, +}; + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "I2S", + .id = MT8365_AFE_IO_I2S, + .playback = { + .stream_name = "I2S Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "I2S Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_i2s_ops, + }, { + .name = "2ND I2S", + .id = MT8365_AFE_IO_2ND_I2S, + .playback = { + .stream_name = "2ND I2S Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "2ND I2S Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_afe_2nd_i2s_ops, + } +}; + +static const char * const fmi2sin_text[] = { + "OPEN", "FM_2ND_I2S_IN" +}; + +static SOC_ENUM_SINGLE_VIRT_DECL(fmi2sin_enum, fmi2sin_text); + +static const struct snd_kcontrol_new fmi2sin_mux = + SOC_DAPM_ENUM("FM 2ND I2S Source", fmi2sin_enum); + +static const struct snd_kcontrol_new i2s_o03_o04_enable_ctl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_SWITCH("I2S O03_O04", SND_SOC_NOPM, 0, 0, + &i2s_o03_o04_enable_ctl), + SND_SOC_DAPM_MUX("FM 2ND I2S Mux", SND_SOC_NOPM, 0, 0, &fmi2sin_mux), + SND_SOC_DAPM_INPUT("2ND I2S In"), +}; + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + {"I2S O03_O04", "Switch", "O03"}, + {"I2S O03_O04", "Switch", "O04"}, + {"I2S Playback", NULL, "I2S O03_O04"}, + {"2ND I2S Playback", NULL, "O00"}, + {"2ND I2S Playback", NULL, "O01"}, + {"2ND I2S Capture", NULL, "2ND I2S In"}, + {"FM 2ND I2S Mux", "FM_2ND_I2S_IN", "2ND I2S Capture"}, +}; + +static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + int i, ret; + struct mt8365_afe_private *afe_priv = afe->platform_priv; + + for (i = 0; i < DAI_I2S_NUM; i++) { + ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id, + sizeof(*afe_priv), + &mt8365_i2s_priv[i]); + if (ret) + return ret; + } + return 0; +} + +int mt8365_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + return mt8365_dai_i2s_set_priv(afe); +} diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c new file mode 100644 index 000000000000..f85ec07249c3 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek 8365 ALSA SoC Audio DAI PCM Control + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#include +#include +#include +#include "mt8365-afe-clk.h" +#include "mt8365-afe-common.h" + +struct mt8365_pcm_intf_data { + bool slave_mode; + bool lrck_inv; + bool bck_inv; + unsigned int format; +}; + +/* DAI Drivers */ + +static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe) +{ + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + PCM_INTF_CON1_EN, PCM_INTF_CON1_EN); +} + +static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe) +{ + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + PCM_INTF_CON1_EN, 0x0); +} + +static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1]; + bool slave_mode = pcm_priv->slave_mode; + bool lrck_inv = pcm_priv->lrck_inv; + bool bck_inv = pcm_priv->bck_inv; + unsigned int fmt = pcm_priv->format; + unsigned int bit_width = dai->sample_bits; + unsigned int val = 0; + + if (!slave_mode) { + val |= PCM_INTF_CON1_MASTER_MODE | + PCM_INTF_CON1_BYPASS_ASRC; + + if (lrck_inv) + val |= PCM_INTF_CON1_SYNC_OUT_INV; + if (bck_inv) + val |= PCM_INTF_CON1_BCLK_OUT_INV; + } else { + val |= PCM_INTF_CON1_SLAVE_MODE; + + if (lrck_inv) + val |= PCM_INTF_CON1_SYNC_IN_INV; + if (bck_inv) + val |= PCM_INTF_CON1_BCLK_IN_INV; + + /* TODO: add asrc setting */ + } + + val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt); + + if (fmt == MT8365_PCM_FORMAT_PCMA || + fmt == MT8365_PCM_FORMAT_PCMB) + val |= PCM_INTF_CON1_SYNC_LEN(1); + else + val |= PCM_INTF_CON1_SYNC_LEN(bit_width); + + switch (substream->runtime->rate) { + case 48000: + val |= PCM_INTF_CON1_FS_48K; + break; + case 32000: + val |= PCM_INTF_CON1_FS_32K; + break; + case 16000: + val |= PCM_INTF_CON1_FS_16K; + break; + case 8000: + val |= PCM_INTF_CON1_FS_8K; + break; + default: + return -EINVAL; + } + + if (bit_width > 16) + val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK; + else + val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK; + + val |= PCM_INTF_CON1_EXT_MODEM; + + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + PCM_INTF_CON1_CONFIG_MASK, val); + + return 0; +} + +static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + if (snd_soc_dai_active(dai)) + return 0; + + mt8365_afe_enable_main_clk(afe); + + return 0; +} + +static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + if (snd_soc_dai_active(dai)) + return; + + mt8365_dai_disable_pcm1(afe); + mt8365_afe_disable_main_clk(afe); +} + +static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + int ret; + + if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) + + snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) { + dev_info(afe->dev, "%s '%s' active(%u-%u) already\n", + __func__, snd_pcm_stream_str(substream), + snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK), + snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)); + return 0; + } + + ret = mt8365_dai_configure_pcm1(substream, dai); + if (ret) + return ret; + + mt8365_dai_enable_pcm1(afe); + + return 0; +} + +static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1]; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + pcm_priv->format = MT8365_PCM_FORMAT_I2S; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + pcm_priv->bck_inv = false; + pcm_priv->lrck_inv = false; + break; + case SND_SOC_DAIFMT_NB_IF: + pcm_priv->bck_inv = false; + pcm_priv->lrck_inv = true; + break; + case SND_SOC_DAIFMT_IB_NF: + pcm_priv->bck_inv = true; + pcm_priv->lrck_inv = false; + break; + case SND_SOC_DAIFMT_IB_IF: + pcm_priv->bck_inv = true; + pcm_priv->lrck_inv = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + pcm_priv->slave_mode = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + pcm_priv->slave_mode = false; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = { + .startup = mt8365_dai_pcm1_startup, + .shutdown = mt8365_dai_pcm1_shutdown, + .prepare = mt8365_dai_pcm1_prepare, + .set_fmt = mt8365_dai_pcm1_set_fmt, +}; + +static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { + { + .name = "PCM1", + .id = MT8365_AFE_IO_PCM1, + .playback = { + .stream_name = "PCM1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "PCM1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mt8365_dai_pcm1_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + } +}; + +/* DAI widget */ + +static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { + SND_SOC_DAPM_OUTPUT("PCM1 Out"), + SND_SOC_DAPM_INPUT("PCM1 In"), +}; + +/* DAI route */ + +static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { + {"PCM1 Playback", NULL, "O07"}, + {"PCM1 Playback", NULL, "O08"}, + {"PCM1 Out", NULL, "PCM1 Playback"}, + + {"I09", NULL, "PCM1 Capture"}, + {"I22", NULL, "PCM1 Capture"}, + {"PCM1 Capture", NULL, "PCM1 In"}, +}; + +static int init_pcmif_priv_data(struct mtk_base_afe *afe) +{ + struct mt8365_afe_private *afe_priv = afe->platform_priv; + struct mt8365_pcm_intf_data *pcmif_priv; + + pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data), + GFP_KERNEL); + if (!pcmif_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv; + return 0; +} + +int mt8365_dai_pcm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + dai->dai_drivers = mtk_dai_pcm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); + dai->dapm_widgets = mtk_dai_pcm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); + dai->dapm_routes = mtk_dai_pcm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); + return init_pcmif_priv_data(afe); +} diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c new file mode 100644 index 000000000000..42cbdfdfadb5 --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek MT8365 Sound Card driver + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Nicolas Belin + */ + +#include +#include +#include +#include +#include "mt8365-afe-common.h" +#include +#include "../common/mtk-soc-card.h" +#include "../common/mtk-soundcard-driver.h" + +enum pinctrl_pin_state { + PIN_STATE_DEFAULT, + PIN_STATE_DMIC, + PIN_STATE_MISO_OFF, + PIN_STATE_MISO_ON, + PIN_STATE_MOSI_OFF, + PIN_STATE_MOSI_ON, + PIN_STATE_MAX +}; + +static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = { + "default", + "dmic", + "miso_off", + "miso_on", + "mosi_off", + "mosi_on", +}; + +struct mt8365_mt6357_priv { + struct pinctrl *pinctrl; + struct pinctrl_state *pin_states[PIN_STATE_MAX]; +}; + +enum { + /* FE */ + DAI_LINK_DL1_PLAYBACK = 0, + DAI_LINK_DL2_PLAYBACK, + DAI_LINK_AWB_CAPTURE, + DAI_LINK_VUL_CAPTURE, + /* BE */ + DAI_LINK_2ND_I2S_INTF, + DAI_LINK_DMIC, + DAI_LINK_INT_ADDA, + DAI_LINK_NUM +}; + +static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = { + SND_SOC_DAPM_OUTPUT("HDMI Out"), +}; + +static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = { + {"HDMI Out", NULL, "2ND I2S Playback"}, + {"DMIC In", NULL, "MICBIAS0"}, +}; + +static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); + int ret = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON])) + return ret; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_MOSI_ON]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON])) + return ret; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_MISO_ON]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + } + + return 0; +} + +static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); + int ret = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF])) + return; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_MOSI_OFF]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF])) + return; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_MISO_OFF]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + } +} + +static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = { + .startup = mt8365_mt6357_int_adda_startup, + .shutdown = mt8365_mt6357_int_adda_shutdown, +}; + +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(awb_capture, + DAILINK_COMP_ARRAY(COMP_CPU("AWB")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(vul, + DAILINK_COMP_ARRAY(COMP_CPU("VUL")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s3, + DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(dmic, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(primary_codec, + DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link mt8365_mt6357_dais[] = { + /* Front End DAI links */ + [DAI_LINK_DL1_PLAYBACK] = { + .name = "DL1_FE", + .stream_name = "MultiMedia1_PLayback", + .id = DAI_LINK_DL1_PLAYBACK, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback1), + }, + [DAI_LINK_DL2_PLAYBACK] = { + .name = "DL2_FE", + .stream_name = "MultiMedia2_PLayback", + .id = DAI_LINK_DL2_PLAYBACK, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback2), + }, + [DAI_LINK_AWB_CAPTURE] = { + .name = "AWB_FE", + .stream_name = "DL1_AWB_Record", + .id = DAI_LINK_AWB_CAPTURE, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(awb_capture), + }, + [DAI_LINK_VUL_CAPTURE] = { + .name = "VUL_FE", + .stream_name = "MultiMedia1_Capture", + .id = DAI_LINK_VUL_CAPTURE, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST + }, + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(vul), + }, + /* Back End DAI links */ + [DAI_LINK_2ND_I2S_INTF] = { + .name = "I2S_OUT_BE", + .no_pcm = 1, + .id = DAI_LINK_2ND_I2S_INTF, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(i2s3), + }, + [DAI_LINK_DMIC] = { + .name = "DMIC_BE", + .no_pcm = 1, + .id = DAI_LINK_DMIC, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(dmic), + }, + [DAI_LINK_INT_ADDA] = { + .name = "MTK_Codec", + .no_pcm = 1, + .id = DAI_LINK_INT_ADDA, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &mt8365_mt6357_int_adda_ops, + SND_SOC_DAILINK_REG(primary_codec), + }, +}; + +static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card) +{ + struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card); + int ret, i; + + priv->pinctrl = devm_pinctrl_get(card->dev); + if (IS_ERR(priv->pinctrl)) { + ret = PTR_ERR(priv->pinctrl); + return dev_err_probe(card->dev, ret, + "Failed to get pinctrl\n"); + } + + for (i = PIN_STATE_DEFAULT ; i < PIN_STATE_MAX ; i++) { + priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl, + mt8365_mt6357_pin_str[i]); + if (IS_ERR(priv->pin_states[i])) { + dev_info(card->dev, "No pin state for %s\n", + mt8365_mt6357_pin_str[i]); + } else { + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[i]); + if (ret) { + dev_err_probe(card->dev, ret, + "Failed to select pin state %s\n", + mt8365_mt6357_pin_str[i]); + return ret; + } + } + } + return 0; +} + +static struct snd_soc_card mt8365_mt6357_soc_card = { + .name = "mt8365-evk", + .owner = THIS_MODULE, + .dai_link = mt8365_mt6357_dais, + .num_links = ARRAY_SIZE(mt8365_mt6357_dais), + .dapm_widgets = mt8365_mt6357_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets), + .dapm_routes = mt8365_mt6357_routes, + .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes), +}; + +static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool legacy) +{ + struct mtk_platform_card_data *card_data = soc_card_data->card_data; + struct snd_soc_card *card = card_data->card; + struct device *dev = card->dev; + struct mt8365_mt6357_priv *mach_priv; + int ret; + + card->dev = dev; + ret = parse_dai_link_info(card); + if (ret) + goto err; + + mach_priv = devm_kzalloc(dev, sizeof(*mach_priv), + GFP_KERNEL); + if (!mach_priv) + return -ENOMEM; + soc_card_data->mach_priv = mach_priv; + snd_soc_card_set_drvdata(card, soc_card_data); + mt8365_mt6357_gpio_probe(card); + return 0; + +err: + clean_card_reference(card); + return ret; +} + +static const struct mtk_soundcard_pdata mt8365_mt6357_card = { + .card_name = "mt8365-mt6357", + .card_data = &(struct mtk_platform_card_data) { + .card = &mt8365_mt6357_soc_card, + }, + .soc_probe = mt8365_mt6357_dev_probe +}; + +static const struct of_device_id mt8365_mt6357_dt_match[] = { + { .compatible = "mediatek,mt8365-mt6357", .data = &mt8365_mt6357_card }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match); + +static struct platform_driver mt8365_mt6357_driver = { + .driver = { + .name = "mt8365_mt6357", + .of_match_table = mt8365_mt6357_dt_match, + .pm = &snd_soc_pm_ops, + }, + .probe = mtk_soundcard_common_probe, +}; + +module_platform_driver(mt8365_mt6357_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8365 EVK SoC machine driver"); +MODULE_AUTHOR("Nicolas Belin "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform: mt8365_mt6357"); diff --git a/sound/soc/mediatek/mt8365/mt8365-reg.h b/sound/soc/mediatek/mt8365/mt8365-reg.h new file mode 100644 index 000000000000..4ebbb94ff02e --- /dev/null +++ b/sound/soc/mediatek/mt8365/mt8365-reg.h @@ -0,0 +1,993 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * MediaTek 8365 audio driver reg definition + * + * Copyright (c) 2024 MediaTek Inc. + * Authors: Jia Zeng + * Alexandre Mergnat + */ + +#ifndef _MT8365_REG_H_ +#define _MT8365_REG_H_ + +#include + +#define AUDIO_TOP_CON0 (0x0000) +#define AUDIO_TOP_CON1 (0x0004) +#define AUDIO_TOP_CON2 (0x0008) +#define AUDIO_TOP_CON3 (0x000c) + +#define AFE_DAC_CON0 (0x0010) +#define AFE_DAC_CON1 (0x0014) +#define AFE_I2S_CON (0x0018) +#define AFE_CONN0 (0x0020) +#define AFE_CONN1 (0x0024) +#define AFE_CONN2 (0x0028) +#define AFE_CONN3 (0x002c) +#define AFE_CONN4 (0x0030) +#define AFE_I2S_CON1 (0x0034) +#define AFE_I2S_CON2 (0x0038) +#define AFE_MRGIF_CON (0x003c) +#define AFE_DL1_BASE (0x0040) +#define AFE_DL1_CUR (0x0044) +#define AFE_DL1_END (0x0048) +#define AFE_I2S_CON3 (0x004c) +#define AFE_DL2_BASE (0x0050) +#define AFE_DL2_CUR (0x0054) +#define AFE_DL2_END (0x0058) +#define AFE_CONN5 (0x005c) +#define AFE_AWB_BASE (0x0070) +#define AFE_AWB_END (0x0078) +#define AFE_AWB_CUR (0x007c) +#define AFE_VUL_BASE (0x0080) +#define AFE_VUL_END (0x0088) +#define AFE_VUL_CUR (0x008c) +#define AFE_CONN6 (0x00bc) +#define AFE_MEMIF_MSB (0x00cc) +#define AFE_MEMIF_MON0 (0x00d0) +#define AFE_MEMIF_MON1 (0x00d4) +#define AFE_MEMIF_MON2 (0x00d8) +#define AFE_MEMIF_MON3 (0x00dc) +#define AFE_MEMIF_MON4 (0x00e0) +#define AFE_MEMIF_MON5 (0x00e4) +#define AFE_MEMIF_MON6 (0x00e8) +#define AFE_MEMIF_MON7 (0x00ec) +#define AFE_MEMIF_MON8 (0x00f0) +#define AFE_MEMIF_MON9 (0x00f4) +#define AFE_MEMIF_MON10 (0x00f8) +#define AFE_MEMIF_MON11 (0x00fc) +#define AFE_ADDA_DL_SRC2_CON0 (0x0108) +#define AFE_ADDA_DL_SRC2_CON1 (0x010c) +#define AFE_ADDA_UL_SRC_CON0 (0x0114) +#define AFE_ADDA_UL_SRC_CON1 (0x0118) +#define AFE_ADDA_TOP_CON0 (0x0120) +#define AFE_ADDA_UL_DL_CON0 (0x0124) +#define AFE_ADDA_SRC_DEBUG (0x012c) +#define AFE_ADDA_SRC_DEBUG_MON0 (0x0130) +#define AFE_ADDA_SRC_DEBUG_MON1 (0x0134) +#define AFE_ADDA_UL_SRC_MON0 (0x0148) +#define AFE_ADDA_UL_SRC_MON1 (0x014c) +#define AFE_SRAM_BOUND (0x0170) +#define AFE_SECURE_CON (0x0174) +#define AFE_SECURE_CONN0 (0x0178) +#define AFE_SIDETONE_DEBUG (0x01d0) +#define AFE_SIDETONE_MON (0x01d4) +#define AFE_SIDETONE_CON0 (0x01e0) +#define AFE_SIDETONE_COEFF (0x01e4) +#define AFE_SIDETONE_CON1 (0x01e8) +#define AFE_SIDETONE_GAIN (0x01ec) +#define AFE_SGEN_CON0 (0x01f0) +#define AFE_SINEGEN_CON_TDM (0x01f8) +#define AFE_SINEGEN_CON_TDM_IN (0x01fc) +#define AFE_TOP_CON0 (0x0200) +#define AFE_BUS_CFG (0x0240) +#define AFE_BUS_MON0 (0x0244) +#define AFE_ADDA_PREDIS_CON0 (0x0260) +#define AFE_ADDA_PREDIS_CON1 (0x0264) +#define AFE_CONN_MON0 (0x0280) +#define AFE_CONN_MON1 (0x0284) +#define AFE_CONN_MON2 (0x0288) +#define AFE_CONN_MON3 (0x028c) +#define AFE_ADDA_IIR_COEF_02_01 (0x0290) +#define AFE_ADDA_IIR_COEF_04_03 (0x0294) +#define AFE_ADDA_IIR_COEF_06_05 (0x0298) +#define AFE_ADDA_IIR_COEF_08_07 (0x029c) +#define AFE_ADDA_IIR_COEF_10_09 (0x02a0) +#define AFE_VUL_D2_BASE (0x0350) +#define AFE_VUL_D2_END (0x0358) +#define AFE_VUL_D2_CUR (0x035c) +#define AFE_HDMI_OUT_CON0 (0x0370) +#define AFE_HDMI_OUT_BASE (0x0374) +#define AFE_HDMI_OUT_CUR (0x0378) +#define AFE_HDMI_OUT_END (0x037c) +#define AFE_SPDIF_OUT_CON0 (0x0380) +#define AFE_SPDIF_OUT_BASE (0x0384) +#define AFE_SPDIF_OUT_CUR (0x0388) +#define AFE_SPDIF_OUT_END (0x038c) +#define AFE_HDMI_CONN0 (0x0390) +#define AFE_HDMI_CONN1 (0x0398) +#define AFE_CONN_TDMIN_CON (0x039c) +#define AFE_IRQ_MCU_CON (0x03a0) +#define AFE_IRQ_MCU_STATUS (0x03a4) +#define AFE_IRQ_MCU_CLR (0x03a8) +#define AFE_IRQ_MCU_CNT1 (0x03ac) +#define AFE_IRQ_MCU_CNT2 (0x03b0) +#define AFE_IRQ_MCU_EN (0x03b4) +#define AFE_IRQ_MCU_MON2 (0x03b8) +#define AFE_IRQ_MCU_CNT5 (0x03bc) +#define AFE_IRQ1_MCU_CNT_MON (0x03c0) +#define AFE_IRQ2_MCU_CNT_MON (0x03c4) +#define AFE_IRQ1_MCU_EN_CNT_MON (0x03c8) +#define AFE_IRQ5_MCU_CNT_MON (0x03cc) +#define AFE_MEMIF_MINLEN (0x03d0) +#define AFE_MEMIF_MAXLEN (0x03d4) +#define AFE_MEMIF_PBUF_SIZE (0x03d8) +#define AFE_IRQ_MCU_CNT7 (0x03dc) +#define AFE_IRQ7_MCU_CNT_MON (0x03e0) +#define AFE_MEMIF_PBUF2_SIZE (0x03ec) +#define AFE_APLL_TUNER_CFG (0x03f0) +#define AFE_APLL_TUNER_CFG1 (0x03f4) +#define AFE_IRQ_MCU_CON2 (0x03f8) +#define IRQ13_MCU_CNT (0x0408) +#define IRQ13_MCU_CNT_MON (0x040c) +#define AFE_GAIN1_CON0 (0x0410) +#define AFE_GAIN1_CON1 (0x0414) +#define AFE_GAIN1_CON2 (0x0418) +#define AFE_GAIN1_CON3 (0x041c) +#define AFE_GAIN2_CON0 (0x0428) +#define AFE_GAIN2_CON1 (0x042c) +#define AFE_GAIN2_CON2 (0x0430) +#define AFE_GAIN2_CON3 (0x0434) +#define AFE_GAIN2_CUR (0x043c) +#define AFE_CONN11 (0x0448) +#define AFE_CONN12 (0x044c) +#define AFE_CONN13 (0x0450) +#define AFE_CONN14 (0x0454) +#define AFE_CONN15 (0x0458) +#define AFE_CONN16 (0x045c) +#define AFE_CONN7 (0x0460) +#define AFE_CONN8 (0x0464) +#define AFE_CONN9 (0x0468) +#define AFE_CONN10 (0x046c) +#define AFE_CONN21 (0x0470) +#define AFE_CONN22 (0x0474) +#define AFE_CONN23 (0x0478) +#define AFE_CONN24 (0x047c) +#define AFE_IEC_CFG (0x0480) +#define AFE_IEC_NSNUM (0x0484) +#define AFE_IEC_BURST_INFO (0x0488) +#define AFE_IEC_BURST_LEN (0x048c) +#define AFE_IEC_NSADR (0x0490) +#define AFE_CONN_RS (0x0494) +#define AFE_CONN_DI (0x0498) +#define AFE_IEC_CHL_STAT0 (0x04a0) +#define AFE_IEC_CHL_STAT1 (0x04a4) +#define AFE_IEC_CHR_STAT0 (0x04a8) +#define AFE_IEC_CHR_STAT1 (0x04ac) +#define AFE_CONN25 (0x04b0) +#define AFE_CONN26 (0x04b4) +#define FPGA_CFG2 (0x04b8) +#define FPGA_CFG3 (0x04bc) +#define FPGA_CFG0 (0x04c0) +#define FPGA_CFG1 (0x04c4) +#define AFE_SRAM_DELSEL_CON0 (0x04f0) +#define AFE_SRAM_DELSEL_CON1 (0x04f4) +#define AFE_SRAM_DELSEL_CON2 (0x04f8) +#define FPGA_CFG4 (0x04fc) +#define AFE_TDM_GASRC4_ASRC_2CH_CON0 (0x0500) +#define AFE_TDM_GASRC4_ASRC_2CH_CON1 (0x0504) +#define AFE_TDM_GASRC4_ASRC_2CH_CON2 (0x0508) +#define AFE_TDM_GASRC4_ASRC_2CH_CON3 (0x050c) +#define AFE_TDM_GASRC4_ASRC_2CH_CON4 (0x0510) +#define AFE_TDM_GASRC4_ASRC_2CH_CON5 (0x0514) +#define AFE_TDM_GASRC4_ASRC_2CH_CON6 (0x0518) +#define AFE_TDM_GASRC4_ASRC_2CH_CON7 (0x051c) +#define AFE_TDM_GASRC4_ASRC_2CH_CON8 (0x0520) +#define AFE_TDM_GASRC4_ASRC_2CH_CON9 (0x0524) +#define AFE_TDM_GASRC4_ASRC_2CH_CON10 (0x0528) +#define AFE_TDM_GASRC4_ASRC_2CH_CON12 (0x0530) +#define AFE_TDM_GASRC4_ASRC_2CH_CON13 (0x0534) +#define PCM_INTF_CON2 (0x0538) +#define PCM2_INTF_CON (0x053c) +#define AFE_APB_MON (0x0540) +#define AFE_CONN34 (0x0544) +#define AFE_TDM_CON1 (0x0548) +#define AFE_TDM_CON2 (0x054c) +#define PCM_INTF_CON1 (0x0550) +#define AFE_SECURE_MASK_CONN47_1 (0x0554) +#define AFE_SECURE_MASK_CONN48_1 (0x0558) +#define AFE_SECURE_MASK_CONN49_1 (0x055c) +#define AFE_SECURE_MASK_CONN50_1 (0x0560) +#define AFE_SECURE_MASK_CONN51_1 (0x0564) +#define AFE_SECURE_MASK_CONN52_1 (0x0568) +#define AFE_SECURE_MASK_CONN53_1 (0x056c) +#define AFE_SE_SECURE_CON (0x0570) +#define AFE_TDM_IN_CON1 (0x0588) +#define AFE_TDM_IN_CON2 (0x058c) +#define AFE_TDM_IN_MON1 (0x0590) +#define AFE_TDM_IN_MON2 (0x0594) +#define AFE_TDM_IN_MON3 (0x0598) +#define AFE_DMIC0_UL_SRC_CON0 (0x05b4) +#define AFE_DMIC0_UL_SRC_CON1 (0x05b8) +#define AFE_DMIC0_SRC_DEBUG (0x05bc) +#define AFE_DMIC0_SRC_DEBUG_MON0 (0x05c0) +#define AFE_DMIC0_UL_SRC_MON0 (0x05c8) +#define AFE_DMIC0_UL_SRC_MON1 (0x05cc) +#define AFE_DMIC0_IIR_COEF_02_01 (0x05d0) +#define AFE_DMIC0_IIR_COEF_04_03 (0x05d4) +#define AFE_DMIC0_IIR_COEF_06_05 (0x05d8) +#define AFE_DMIC0_IIR_COEF_08_07 (0x05dc) +#define AFE_DMIC0_IIR_COEF_10_09 (0x05e0) +#define AFE_DMIC1_UL_SRC_CON0 (0x0620) +#define AFE_DMIC1_UL_SRC_CON1 (0x0624) +#define AFE_DMIC1_SRC_DEBUG (0x0628) +#define AFE_DMIC1_SRC_DEBUG_MON0 (0x062c) +#define AFE_DMIC1_UL_SRC_MON0 (0x0634) +#define AFE_DMIC1_UL_SRC_MON1 (0x0638) +#define AFE_DMIC1_IIR_COEF_02_01 (0x063c) +#define AFE_DMIC1_IIR_COEF_04_03 (0x0640) +#define AFE_DMIC1_IIR_COEF_06_05 (0x0644) +#define AFE_DMIC1_IIR_COEF_08_07 (0x0648) +#define AFE_DMIC1_IIR_COEF_10_09 (0x064c) +#define AFE_SECURE_MASK_CONN39_1 (0x068c) +#define AFE_SECURE_MASK_CONN40_1 (0x0690) +#define AFE_SECURE_MASK_CONN41_1 (0x0694) +#define AFE_SECURE_MASK_CONN42_1 (0x0698) +#define AFE_SECURE_MASK_CONN43_1 (0x069c) +#define AFE_SECURE_MASK_CONN44_1 (0x06a0) +#define AFE_SECURE_MASK_CONN45_1 (0x06a4) +#define AFE_SECURE_MASK_CONN46_1 (0x06a8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON0 (0x06c0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON1 (0x06c4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON2 (0x06c8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON3 (0x06cc) +#define AFE_TDM_GASRC1_ASRC_2CH_CON4 (0x06d0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON5 (0x06d4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON6 (0x06d8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON7 (0x06dc) +#define AFE_TDM_GASRC1_ASRC_2CH_CON8 (0x06e0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON9 (0x06e4) +#define AFE_TDM_GASRC1_ASRC_2CH_CON10 (0x06e8) +#define AFE_TDM_GASRC1_ASRC_2CH_CON12 (0x06f0) +#define AFE_TDM_GASRC1_ASRC_2CH_CON13 (0x06f4) +#define AFE_TDM_ASRC_CON0 (0x06f8) +#define AFE_TDM_GASRC2_ASRC_2CH_CON0 (0x0700) +#define AFE_TDM_GASRC2_ASRC_2CH_CON1 (0x0704) +#define AFE_TDM_GASRC2_ASRC_2CH_CON2 (0x0708) +#define AFE_TDM_GASRC2_ASRC_2CH_CON3 (0x070c) +#define AFE_TDM_GASRC2_ASRC_2CH_CON4 (0x0710) +#define AFE_TDM_GASRC2_ASRC_2CH_CON5 (0x0714) +#define AFE_TDM_GASRC2_ASRC_2CH_CON6 (0x0718) +#define AFE_TDM_GASRC2_ASRC_2CH_CON7 (0x071c) +#define AFE_TDM_GASRC2_ASRC_2CH_CON8 (0x0720) +#define AFE_TDM_GASRC2_ASRC_2CH_CON9 (0x0724) +#define AFE_TDM_GASRC2_ASRC_2CH_CON10 (0x0728) +#define AFE_TDM_GASRC2_ASRC_2CH_CON12 (0x0730) +#define AFE_TDM_GASRC2_ASRC_2CH_CON13 (0x0734) +#define AFE_TDM_GASRC3_ASRC_2CH_CON0 (0x0740) +#define AFE_TDM_GASRC3_ASRC_2CH_CON1 (0x0744) +#define AFE_TDM_GASRC3_ASRC_2CH_CON2 (0x0748) +#define AFE_TDM_GASRC3_ASRC_2CH_CON3 (0x074c) +#define AFE_TDM_GASRC3_ASRC_2CH_CON4 (0x0750) +#define AFE_TDM_GASRC3_ASRC_2CH_CON5 (0x0754) +#define AFE_TDM_GASRC3_ASRC_2CH_CON6 (0x0758) +#define AFE_TDM_GASRC3_ASRC_2CH_CON7 (0x075c) +#define AFE_TDM_GASRC3_ASRC_2CH_CON8 (0x0760) +#define AFE_TDM_GASRC3_ASRC_2CH_CON9 (0x0764) +#define AFE_TDM_GASRC3_ASRC_2CH_CON10 (0x0768) +#define AFE_TDM_GASRC3_ASRC_2CH_CON12 (0x0770) +#define AFE_TDM_GASRC3_ASRC_2CH_CON13 (0x0774) +#define AFE_DMIC2_UL_SRC_CON0 (0x0780) +#define AFE_DMIC2_UL_SRC_CON1 (0x0784) +#define AFE_DMIC2_SRC_DEBUG (0x0788) +#define AFE_DMIC2_SRC_DEBUG_MON0 (0x078c) +#define AFE_DMIC2_UL_SRC_MON0 (0x0794) +#define AFE_DMIC2_UL_SRC_MON1 (0x0798) +#define AFE_DMIC2_IIR_COEF_02_01 (0x079c) +#define AFE_DMIC2_IIR_COEF_04_03 (0x07a0) +#define AFE_DMIC2_IIR_COEF_06_05 (0x07a4) +#define AFE_DMIC2_IIR_COEF_08_07 (0x07a8) +#define AFE_DMIC2_IIR_COEF_10_09 (0x07ac) +#define AFE_DMIC3_UL_SRC_CON0 (0x07ec) +#define AFE_DMIC3_UL_SRC_CON1 (0x07f0) +#define AFE_DMIC3_SRC_DEBUG (0x07f4) +#define AFE_DMIC3_SRC_DEBUG_MON0 (0x07f8) +#define AFE_DMIC3_UL_SRC_MON0 (0x0800) +#define AFE_DMIC3_UL_SRC_MON1 (0x0804) +#define AFE_DMIC3_IIR_COEF_02_01 (0x0808) +#define AFE_DMIC3_IIR_COEF_04_03 (0x080c) +#define AFE_DMIC3_IIR_COEF_06_05 (0x0810) +#define AFE_DMIC3_IIR_COEF_08_07 (0x0814) +#define AFE_DMIC3_IIR_COEF_10_09 (0x0818) +#define AFE_SECURE_MASK_CONN25_1 (0x0858) +#define AFE_SECURE_MASK_CONN26_1 (0x085c) +#define AFE_SECURE_MASK_CONN27_1 (0x0860) +#define AFE_SECURE_MASK_CONN28_1 (0x0864) +#define AFE_SECURE_MASK_CONN29_1 (0x0868) +#define AFE_SECURE_MASK_CONN30_1 (0x086c) +#define AFE_SECURE_MASK_CONN31_1 (0x0870) +#define AFE_SECURE_MASK_CONN32_1 (0x0874) +#define AFE_SECURE_MASK_CONN33_1 (0x0878) +#define AFE_SECURE_MASK_CONN34_1 (0x087c) +#define AFE_SECURE_MASK_CONN35_1 (0x0880) +#define AFE_SECURE_MASK_CONN36_1 (0x0884) +#define AFE_SECURE_MASK_CONN37_1 (0x0888) +#define AFE_SECURE_MASK_CONN38_1 (0x088c) +#define AFE_IRQ_MCU_SCP_EN (0x0890) +#define AFE_IRQ_MCU_DSP_EN (0x0894) +#define AFE_IRQ3_MCU_CNT_MON (0x0898) +#define AFE_IRQ4_MCU_CNT_MON (0x089c) +#define AFE_IRQ8_MCU_CNT_MON (0x08a0) +#define AFE_IRQ_MCU_CNT3 (0x08a4) +#define AFE_IRQ_MCU_CNT4 (0x08a8) +#define AFE_IRQ_MCU_CNT8 (0x08ac) +#define AFE_IRQ_MCU_CNT11 (0x08b0) +#define AFE_IRQ_MCU_CNT12 (0x08b4) +#define AFE_IRQ11_MCU_CNT_MON (0x08b8) +#define AFE_IRQ12_MCU_CNT_MON (0x08bc) +#define AFE_VUL3_BASE (0x08c0) +#define AFE_VUL3_CUR (0x08c4) +#define AFE_VUL3_END (0x08c8) +#define AFE_VUL3_BASE_MSB (0x08d0) +#define AFE_VUL3_END_MSB (0x08d4) +#define AFE_IRQ10_MCU_CNT_MON (0x08d8) +#define AFE_IRQ_MCU_CNT10 (0x08dc) +#define AFE_IRQ_ACC1_CNT (0x08e0) +#define AFE_IRQ_ACC2_CNT (0x08e4) +#define AFE_IRQ_ACC1_CNT_MON1 (0x08e8) +#define AFE_IRQ_ACC2_CNT_MON (0x08ec) +#define AFE_TSF_CON (0x08f0) +#define AFE_TSF_MON (0x08f4) +#define AFE_IRQ_ACC1_CNT_MON2 (0x08f8) +#define AFE_SPDIFIN_CFG0 (0x0900) +#define AFE_SPDIFIN_CFG1 (0x0904) +#define AFE_SPDIFIN_CHSTS1 (0x0908) +#define AFE_SPDIFIN_CHSTS2 (0x090c) +#define AFE_SPDIFIN_CHSTS3 (0x0910) +#define AFE_SPDIFIN_CHSTS4 (0x0914) +#define AFE_SPDIFIN_CHSTS5 (0x0918) +#define AFE_SPDIFIN_CHSTS6 (0x091c) +#define AFE_SPDIFIN_DEBUG1 (0x0920) +#define AFE_SPDIFIN_DEBUG2 (0x0924) +#define AFE_SPDIFIN_DEBUG3 (0x0928) +#define AFE_SPDIFIN_DEBUG4 (0x092c) +#define AFE_SPDIFIN_EC (0x0930) +#define AFE_SPDIFIN_CKLOCK_CFG (0x0934) +#define AFE_SPDIFIN_BR (0x093c) +#define AFE_SPDIFIN_BR_DBG1 (0x0940) +#define AFE_SPDIFIN_INT_EXT (0x0948) +#define AFE_SPDIFIN_INT_EXT2 (0x094c) +#define SPDIFIN_FREQ_INFO (0x0950) +#define SPDIFIN_FREQ_INFO_2 (0x0954) +#define SPDIFIN_FREQ_INFO_3 (0x0958) +#define SPDIFIN_FREQ_STATUS (0x095c) +#define SPDIFIN_USERCODE1 (0x0960) +#define SPDIFIN_USERCODE2 (0x0964) +#define SPDIFIN_USERCODE3 (0x0968) +#define SPDIFIN_USERCODE4 (0x096c) +#define SPDIFIN_USERCODE5 (0x0970) +#define SPDIFIN_USERCODE6 (0x0974) +#define SPDIFIN_USERCODE7 (0x0978) +#define SPDIFIN_USERCODE8 (0x097c) +#define SPDIFIN_USERCODE9 (0x0980) +#define SPDIFIN_USERCODE10 (0x0984) +#define SPDIFIN_USERCODE11 (0x0988) +#define SPDIFIN_USERCODE12 (0x098c) +#define SPDIFIN_MEMIF_CON0 (0x0990) +#define SPDIFIN_BASE_ADR (0x0994) +#define SPDIFIN_END_ADR (0x0998) +#define SPDIFIN_APLL_TUNER_CFG (0x09a0) +#define SPDIFIN_APLL_TUNER_CFG1 (0x09a4) +#define SPDIFIN_APLL2_TUNER_CFG (0x09a8) +#define SPDIFIN_APLL2_TUNER_CFG1 (0x09ac) +#define SPDIFIN_TYPE_DET (0x09b0) +#define MPHONE_MULTI_CON0 (0x09b4) +#define SPDIFIN_CUR_ADR (0x09b8) +#define AFE_SINEGEN_CON_SPDIFIN (0x09bc) +#define AFE_HDMI_IN_2CH_CON0 (0x09c0) +#define AFE_HDMI_IN_2CH_BASE (0x09c4) +#define AFE_HDMI_IN_2CH_END (0x09c8) +#define AFE_HDMI_IN_2CH_CUR (0x09cc) +#define AFE_MEMIF_BUF_MON0 (0x09d0) +#define AFE_MEMIF_BUF_MON1 (0x09d4) +#define AFE_MEMIF_BUF_MON2 (0x09d8) +#define AFE_MEMIF_BUF_MON3 (0x09dc) +#define AFE_MEMIF_BUF_MON6 (0x09e8) +#define AFE_MEMIF_BUF_MON7 (0x09ec) +#define AFE_MEMIF_BUF_MON8 (0x09f0) +#define AFE_MEMIF_BUF_MON10 (0x09f8) +#define AFE_MEMIF_BUF_MON11 (0x09fc) +#define SYSTOP_STC_CONFIG (0x0a00) +#define AUDIO_STC_STATUS (0x0a04) +#define SYSTOP_W_STC_H (0x0a08) +#define SYSTOP_W_STC_L (0x0a0c) +#define SYSTOP_R_STC_H (0x0a10) +#define SYSTOP_R_STC_L (0x0a14) +#define AUDIO_W_STC_H (0x0a18) +#define AUDIO_W_STC_L (0x0a1c) +#define AUDIO_R_STC_H (0x0a20) +#define AUDIO_R_STC_L (0x0a24) +#define SYSTOP_W_STC2_H (0x0a28) +#define SYSTOP_W_STC2_L (0x0a2c) +#define SYSTOP_R_STC2_H (0x0a30) +#define SYSTOP_R_STC2_L (0x0a34) +#define AUDIO_W_STC2_H (0x0a38) +#define AUDIO_W_STC2_L (0x0a3c) +#define AUDIO_R_STC2_H (0x0a40) +#define AUDIO_R_STC2_L (0x0a44) + +#define AFE_CONN17 (0x0a48) +#define AFE_CONN18 (0x0a4c) +#define AFE_CONN19 (0x0a50) +#define AFE_CONN20 (0x0a54) +#define AFE_CONN27 (0x0a58) +#define AFE_CONN28 (0x0a5c) +#define AFE_CONN29 (0x0a60) +#define AFE_CONN30 (0x0a64) +#define AFE_CONN31 (0x0a68) +#define AFE_CONN32 (0x0a6c) +#define AFE_CONN33 (0x0a70) +#define AFE_CONN35 (0x0a74) +#define AFE_CONN36 (0x0a78) +#define AFE_CONN37 (0x0a7c) +#define AFE_CONN38 (0x0a80) +#define AFE_CONN39 (0x0a84) +#define AFE_CONN40 (0x0a88) +#define AFE_CONN41 (0x0a8c) +#define AFE_CONN42 (0x0a90) +#define AFE_CONN44 (0x0a94) +#define AFE_CONN45 (0x0a98) +#define AFE_CONN46 (0x0a9c) +#define AFE_CONN47 (0x0aa0) +#define AFE_CONN_24BIT (0x0aa4) +#define AFE_CONN0_1 (0x0aa8) +#define AFE_CONN1_1 (0x0aac) +#define AFE_CONN2_1 (0x0ab0) +#define AFE_CONN3_1 (0x0ab4) +#define AFE_CONN4_1 (0x0ab8) +#define AFE_CONN5_1 (0x0abc) +#define AFE_CONN6_1 (0x0ac0) +#define AFE_CONN7_1 (0x0ac4) +#define AFE_CONN8_1 (0x0ac8) +#define AFE_CONN9_1 (0x0acc) +#define AFE_CONN10_1 (0x0ad0) +#define AFE_CONN11_1 (0x0ad4) +#define AFE_CONN12_1 (0x0ad8) +#define AFE_CONN13_1 (0x0adc) +#define AFE_CONN14_1 (0x0ae0) +#define AFE_CONN15_1 (0x0ae4) +#define AFE_CONN16_1 (0x0ae8) +#define AFE_CONN17_1 (0x0aec) +#define AFE_CONN18_1 (0x0af0) +#define AFE_CONN19_1 (0x0af4) +#define AFE_CONN43 (0x0af8) +#define AFE_CONN43_1 (0x0afc) +#define AFE_CONN21_1 (0x0b00) +#define AFE_CONN22_1 (0x0b04) +#define AFE_CONN23_1 (0x0b08) +#define AFE_CONN24_1 (0x0b0c) +#define AFE_CONN25_1 (0x0b10) +#define AFE_CONN26_1 (0x0b14) +#define AFE_CONN27_1 (0x0b18) +#define AFE_CONN28_1 (0x0b1c) +#define AFE_CONN29_1 (0x0b20) +#define AFE_CONN30_1 (0x0b24) +#define AFE_CONN31_1 (0x0b28) +#define AFE_CONN32_1 (0x0b2c) +#define AFE_CONN33_1 (0x0b30) +#define AFE_CONN34_1 (0x0b34) +#define AFE_CONN35_1 (0x0b38) +#define AFE_CONN36_1 (0x0b3c) +#define AFE_CONN37_1 (0x0b40) +#define AFE_CONN38_1 (0x0b44) +#define AFE_CONN39_1 (0x0b48) +#define AFE_CONN40_1 (0x0b4c) +#define AFE_CONN41_1 (0x0b50) +#define AFE_CONN42_1 (0x0b54) +#define AFE_CONN44_1 (0x0b58) +#define AFE_CONN45_1 (0x0b5c) +#define AFE_CONN46_1 (0x0b60) +#define AFE_CONN47_1 (0x0b64) +#define AFE_CONN_RS_1 (0x0b68) +#define AFE_CONN_DI_1 (0x0b6c) +#define AFE_CONN_24BIT_1 (0x0b70) +#define AFE_GAIN1_CUR (0x0b78) +#define AFE_CONN20_1 (0x0b7c) +#define AFE_DL1_BASE_MSB (0x0b80) +#define AFE_DL1_END_MSB (0x0b84) +#define AFE_DL2_BASE_MSB (0x0b88) +#define AFE_DL2_END_MSB (0x0b8c) +#define AFE_AWB_BASE_MSB (0x0b90) +#define AFE_AWB_END_MSB (0x0b94) +#define AFE_VUL_BASE_MSB (0x0ba0) +#define AFE_VUL_END_MSB (0x0ba4) +#define AFE_VUL_D2_BASE_MSB (0x0ba8) +#define AFE_VUL_D2_END_MSB (0x0bac) +#define AFE_HDMI_OUT_BASE_MSB (0x0bb8) +#define AFE_HDMI_OUT_END_MSB (0x0bbc) +#define AFE_HDMI_IN_2CH_BASE_MSB (0x0bc0) +#define AFE_HDMI_IN_2CH_END_MSB (0x0bc4) +#define AFE_SPDIF_OUT_BASE_MSB (0x0bc8) +#define AFE_SPDIF_OUT_END_MSB (0x0bcc) +#define SPDIFIN_BASE_MSB (0x0bd0) +#define SPDIFIN_END_MSB (0x0bd4) +#define AFE_DL1_CUR_MSB (0x0bd8) +#define AFE_DL2_CUR_MSB (0x0bdc) +#define AFE_AWB_CUR_MSB (0x0be8) +#define AFE_VUL_CUR_MSB (0x0bf8) +#define AFE_VUL_D2_CUR_MSB (0x0c04) +#define AFE_HDMI_OUT_CUR_MSB (0x0c0c) +#define AFE_HDMI_IN_2CH_CUR_MSB (0x0c10) +#define AFE_SPDIF_OUT_CUR_MSB (0x0c14) +#define SPDIFIN_CUR_MSB (0x0c18) +#define AFE_CONN_REG (0x0c20) +#define AFE_SECURE_MASK_CONN14_1 (0x0c24) +#define AFE_SECURE_MASK_CONN15_1 (0x0c28) +#define AFE_SECURE_MASK_CONN16_1 (0x0c2c) +#define AFE_SECURE_MASK_CONN17_1 (0x0c30) +#define AFE_SECURE_MASK_CONN18_1 (0x0c34) +#define AFE_SECURE_MASK_CONN19_1 (0x0c38) +#define AFE_SECURE_MASK_CONN20_1 (0x0c3c) +#define AFE_SECURE_MASK_CONN21_1 (0x0c40) +#define AFE_SECURE_MASK_CONN22_1 (0x0c44) +#define AFE_SECURE_MASK_CONN23_1 (0x0c48) +#define AFE_SECURE_MASK_CONN24_1 (0x0c4c) +#define AFE_ADDA_DL_SDM_DCCOMP_CON (0x0c50) +#define AFE_ADDA_DL_SDM_TEST (0x0c54) +#define AFE_ADDA_DL_DC_COMP_CFG0 (0x0c58) +#define AFE_ADDA_DL_DC_COMP_CFG1 (0x0c5c) +#define AFE_ADDA_DL_SDM_FIFO_MON (0x0c60) +#define AFE_ADDA_DL_SRC_LCH_MON (0x0c64) +#define AFE_ADDA_DL_SRC_RCH_MON (0x0c68) +#define AFE_ADDA_DL_SDM_OUT_MON (0x0c6c) +#define AFE_ADDA_DL_SDM_DITHER_CON (0x0c70) + +#define AFE_VUL3_CUR_MSB (0x0c78) +#define AFE_ASRC_2CH_CON0 (0x0c80) +#define AFE_ASRC_2CH_CON1 (0x0c84) +#define AFE_ASRC_2CH_CON2 (0x0c88) +#define AFE_ASRC_2CH_CON3 (0x0c8c) +#define AFE_ASRC_2CH_CON4 (0x0c90) +#define AFE_ASRC_2CH_CON5 (0x0c94) +#define AFE_ASRC_2CH_CON6 (0x0c98) +#define AFE_ASRC_2CH_CON7 (0x0c9c) +#define AFE_ASRC_2CH_CON8 (0x0ca0) +#define AFE_ASRC_2CH_CON9 (0x0ca4) +#define AFE_ASRC_2CH_CON10 (0x0ca8) +#define AFE_ASRC_2CH_CON12 (0x0cb0) +#define AFE_ASRC_2CH_CON13 (0x0cb4) + +#define AFE_PCM_TX_ASRC_2CH_CON0 (0x0cc0) +#define AFE_PCM_TX_ASRC_2CH_CON1 (0x0cc4) +#define AFE_PCM_TX_ASRC_2CH_CON2 (0x0cc8) +#define AFE_PCM_TX_ASRC_2CH_CON3 (0x0ccc) +#define AFE_PCM_TX_ASRC_2CH_CON4 (0x0cd0) +#define AFE_PCM_TX_ASRC_2CH_CON5 (0x0cd4) +#define AFE_PCM_TX_ASRC_2CH_CON6 (0x0cd8) +#define AFE_PCM_TX_ASRC_2CH_CON7 (0x0cdc) +#define AFE_PCM_TX_ASRC_2CH_CON8 (0x0ce0) +#define AFE_PCM_TX_ASRC_2CH_CON9 (0x0ce4) +#define AFE_PCM_TX_ASRC_2CH_CON10 (0x0ce8) +#define AFE_PCM_TX_ASRC_2CH_CON12 (0x0cf0) +#define AFE_PCM_TX_ASRC_2CH_CON13 (0x0cf4) +#define AFE_PCM_RX_ASRC_2CH_CON0 (0x0d00) +#define AFE_PCM_RX_ASRC_2CH_CON1 (0x0d04) +#define AFE_PCM_RX_ASRC_2CH_CON2 (0x0d08) +#define AFE_PCM_RX_ASRC_2CH_CON3 (0x0d0c) +#define AFE_PCM_RX_ASRC_2CH_CON4 (0x0d10) +#define AFE_PCM_RX_ASRC_2CH_CON5 (0x0d14) +#define AFE_PCM_RX_ASRC_2CH_CON6 (0x0d18) +#define AFE_PCM_RX_ASRC_2CH_CON7 (0x0d1c) +#define AFE_PCM_RX_ASRC_2CH_CON8 (0x0d20) +#define AFE_PCM_RX_ASRC_2CH_CON9 (0x0d24) +#define AFE_PCM_RX_ASRC_2CH_CON10 (0x0d28) +#define AFE_PCM_RX_ASRC_2CH_CON12 (0x0d30) +#define AFE_PCM_RX_ASRC_2CH_CON13 (0x0d34) + +#define AFE_ADDA_PREDIS_CON2 (0x0d40) +#define AFE_ADDA_PREDIS_CON3 (0x0d44) +#define AFE_SECURE_MASK_CONN4_1 (0x0d48) +#define AFE_SECURE_MASK_CONN5_1 (0x0d4c) +#define AFE_SECURE_MASK_CONN6_1 (0x0d50) +#define AFE_SECURE_MASK_CONN7_1 (0x0d54) +#define AFE_SECURE_MASK_CONN8_1 (0x0d58) +#define AFE_SECURE_MASK_CONN9_1 (0x0d5c) +#define AFE_SECURE_MASK_CONN10_1 (0x0d60) +#define AFE_SECURE_MASK_CONN11_1 (0x0d64) +#define AFE_SECURE_MASK_CONN12_1 (0x0d68) +#define AFE_SECURE_MASK_CONN13_1 (0x0d6c) +#define AFE_MEMIF_MON12 (0x0d70) +#define AFE_MEMIF_MON13 (0x0d74) +#define AFE_MEMIF_MON14 (0x0d78) +#define AFE_MEMIF_MON15 (0x0d7c) +#define AFE_SECURE_MASK_CONN42 (0x0dbc) +#define AFE_SECURE_MASK_CONN43 (0x0dc0) +#define AFE_SECURE_MASK_CONN44 (0x0dc4) +#define AFE_SECURE_MASK_CONN45 (0x0dc8) +#define AFE_SECURE_MASK_CONN46 (0x0dcc) +#define AFE_HD_ENGEN_ENABLE (0x0dd0) +#define AFE_SECURE_MASK_CONN47 (0x0dd4) +#define AFE_SECURE_MASK_CONN48 (0x0dd8) +#define AFE_SECURE_MASK_CONN49 (0x0ddc) +#define AFE_SECURE_MASK_CONN50 (0x0de0) +#define AFE_SECURE_MASK_CONN51 (0x0de4) +#define AFE_SECURE_MASK_CONN52 (0x0de8) +#define AFE_SECURE_MASK_CONN53 (0x0dec) +#define AFE_SECURE_MASK_CONN0_1 (0x0df0) +#define AFE_SECURE_MASK_CONN1_1 (0x0df4) +#define AFE_SECURE_MASK_CONN2_1 (0x0df8) +#define AFE_SECURE_MASK_CONN3_1 (0x0dfc) + +#define AFE_ADDA_MTKAIF_CFG0 (0x0e00) +#define AFE_ADDA_MTKAIF_SYNCWORD_CFG (0x0e14) +#define AFE_ADDA_MTKAIF_RX_CFG0 (0x0e20) +#define AFE_ADDA_MTKAIF_RX_CFG1 (0x0e24) +#define AFE_ADDA_MTKAIF_RX_CFG2 (0x0e28) +#define AFE_ADDA_MTKAIF_MON0 (0x0e34) +#define AFE_ADDA_MTKAIF_MON1 (0x0e38) +#define AFE_AUD_PAD_TOP (0x0e40) + +#define AFE_CM1_CON4 (0x0e48) +#define AFE_CM2_CON4 (0x0e4c) +#define AFE_CM1_CON0 (0x0e50) +#define AFE_CM1_CON1 (0x0e54) +#define AFE_CM1_CON2 (0x0e58) +#define AFE_CM1_CON3 (0x0e5c) +#define AFE_CM2_CON0 (0x0e60) +#define AFE_CM2_CON1 (0x0e64) +#define AFE_CM2_CON2 (0x0e68) +#define AFE_CM2_CON3 (0x0e6c) +#define AFE_CM2_CONN0 (0x0e70) +#define AFE_CM2_CONN1 (0x0e74) +#define AFE_CM2_CONN2 (0x0e78) + +#define AFE_GENERAL1_ASRC_2CH_CON0 (0x0e80) +#define AFE_GENERAL1_ASRC_2CH_CON1 (0x0e84) +#define AFE_GENERAL1_ASRC_2CH_CON2 (0x0e88) +#define AFE_GENERAL1_ASRC_2CH_CON3 (0x0e8c) +#define AFE_GENERAL1_ASRC_2CH_CON4 (0x0e90) +#define AFE_GENERAL1_ASRC_2CH_CON5 (0x0e94) +#define AFE_GENERAL1_ASRC_2CH_CON6 (0x0e98) +#define AFE_GENERAL1_ASRC_2CH_CON7 (0x0e9c) +#define AFE_GENERAL1_ASRC_2CH_CON8 (0x0ea0) +#define AFE_GENERAL1_ASRC_2CH_CON9 (0x0ea4) +#define AFE_GENERAL1_ASRC_2CH_CON10 (0x0ea8) +#define AFE_GENERAL1_ASRC_2CH_CON12 (0x0eb0) +#define AFE_GENERAL1_ASRC_2CH_CON13 (0x0eb4) +#define GENERAL_ASRC_MODE (0x0eb8) +#define GENERAL_ASRC_EN_ON (0x0ebc) + +#define AFE_CONN48 (0x0ec0) +#define AFE_CONN49 (0x0ec4) +#define AFE_CONN50 (0x0ec8) +#define AFE_CONN51 (0x0ecc) +#define AFE_CONN52 (0x0ed0) +#define AFE_CONN53 (0x0ed4) +#define AFE_CONN48_1 (0x0ee0) +#define AFE_CONN49_1 (0x0ee4) +#define AFE_CONN50_1 (0x0ee8) +#define AFE_CONN51_1 (0x0eec) +#define AFE_CONN52_1 (0x0ef0) +#define AFE_CONN53_1 (0x0ef4) + +#define AFE_GENERAL2_ASRC_2CH_CON0 (0x0f00) +#define AFE_GENERAL2_ASRC_2CH_CON1 (0x0f04) +#define AFE_GENERAL2_ASRC_2CH_CON2 (0x0f08) +#define AFE_GENERAL2_ASRC_2CH_CON3 (0x0f0c) +#define AFE_GENERAL2_ASRC_2CH_CON4 (0x0f10) +#define AFE_GENERAL2_ASRC_2CH_CON5 (0x0f14) +#define AFE_GENERAL2_ASRC_2CH_CON6 (0x0f18) +#define AFE_GENERAL2_ASRC_2CH_CON7 (0x0f1c) +#define AFE_GENERAL2_ASRC_2CH_CON8 (0x0f20) +#define AFE_GENERAL2_ASRC_2CH_CON9 (0x0f24) +#define AFE_GENERAL2_ASRC_2CH_CON10 (0x0f28) +#define AFE_GENERAL2_ASRC_2CH_CON12 (0x0f30) +#define AFE_GENERAL2_ASRC_2CH_CON13 (0x0f34) + +#define AFE_SECURE_MASK_CONN28 (0x0f48) +#define AFE_SECURE_MASK_CONN29 (0x0f4c) +#define AFE_SECURE_MASK_CONN30 (0x0f50) +#define AFE_SECURE_MASK_CONN31 (0x0f54) +#define AFE_SECURE_MASK_CONN32 (0x0f58) +#define AFE_SECURE_MASK_CONN33 (0x0f5c) +#define AFE_SECURE_MASK_CONN34 (0x0f60) +#define AFE_SECURE_MASK_CONN35 (0x0f64) +#define AFE_SECURE_MASK_CONN36 (0x0f68) +#define AFE_SECURE_MASK_CONN37 (0x0f6c) +#define AFE_SECURE_MASK_CONN38 (0x0f70) +#define AFE_SECURE_MASK_CONN39 (0x0f74) +#define AFE_SECURE_MASK_CONN40 (0x0f78) +#define AFE_SECURE_MASK_CONN41 (0x0f7c) +#define AFE_SIDEBAND0 (0x0f80) +#define AFE_SIDEBAND1 (0x0f84) +#define AFE_SECURE_SIDEBAND0 (0x0f88) +#define AFE_SECURE_SIDEBAND1 (0x0f8c) +#define AFE_SECURE_MASK_CONN0 (0x0f90) +#define AFE_SECURE_MASK_CONN1 (0x0f94) +#define AFE_SECURE_MASK_CONN2 (0x0f98) +#define AFE_SECURE_MASK_CONN3 (0x0f9c) +#define AFE_SECURE_MASK_CONN4 (0x0fa0) +#define AFE_SECURE_MASK_CONN5 (0x0fa4) +#define AFE_SECURE_MASK_CONN6 (0x0fa8) +#define AFE_SECURE_MASK_CONN7 (0x0fac) +#define AFE_SECURE_MASK_CONN8 (0x0fb0) +#define AFE_SECURE_MASK_CONN9 (0x0fb4) +#define AFE_SECURE_MASK_CONN10 (0x0fb8) +#define AFE_SECURE_MASK_CONN11 (0x0fbc) +#define AFE_SECURE_MASK_CONN12 (0x0fc0) +#define AFE_SECURE_MASK_CONN13 (0x0fc4) +#define AFE_SECURE_MASK_CONN14 (0x0fc8) +#define AFE_SECURE_MASK_CONN15 (0x0fcc) +#define AFE_SECURE_MASK_CONN16 (0x0fd0) +#define AFE_SECURE_MASK_CONN17 (0x0fd4) +#define AFE_SECURE_MASK_CONN18 (0x0fd8) +#define AFE_SECURE_MASK_CONN19 (0x0fdc) +#define AFE_SECURE_MASK_CONN20 (0x0fe0) +#define AFE_SECURE_MASK_CONN21 (0x0fe4) +#define AFE_SECURE_MASK_CONN22 (0x0fe8) +#define AFE_SECURE_MASK_CONN23 (0x0fec) +#define AFE_SECURE_MASK_CONN24 (0x0ff0) +#define AFE_SECURE_MASK_CONN25 (0x0ff4) +#define AFE_SECURE_MASK_CONN26 (0x0ff8) +#define AFE_SECURE_MASK_CONN27 (0x0ffc) + +#define MAX_REGISTER AFE_SECURE_MASK_CONN27 + +#define AFE_IRQ_STATUS_BITS 0x3ff + +/* AUDIO_TOP_CON0 (0x0000) */ +#define AUD_TCON0_PDN_TML (1U << 27) +#define AUD_TCON0_PDN_DAC_PREDIS (1U << 26) +#define AUD_TCON0_PDN_DAC (1U << 25) +#define AUD_TCON0_PDN_ADC (1U << 24) +#define AUD_TCON0_PDN_TDM_IN (1U << 23) +#define AUD_TCON0_PDN_TDM_OUT (1U << 22) +#define AUD_TCON0_PDN_SPDIF (1U << 21) +#define AUD_TCON0_PDN_APLL_TUNER (1U << 19) +#define AUD_TCON0_PDN_APLL2_TUNER (1U << 18) +#define AUD_TCON0_PDN_INTDIR (1U << 15) +#define AUD_TCON0_PDN_24M (1U << 9) +#define AUD_TCON0_PDN_22M (1U << 8) +#define AUD_TCON0_PDN_I2S_IN (1U << 6) +#define AUD_TCON0_PDN_AFE (1U << 2) + +/* AUDIO_TOP_CON1 (0x0004) */ +#define AUD_TCON1_PDN_TDM_ASRC (1U << 15) +#define AUD_TCON1_PDN_GENERAL2_ASRC (1U << 14) +#define AUD_TCON1_PDN_GENERAL1_ASRC (1U << 13) +#define AUD_TCON1_PDN_CONNSYS_I2S_ASRC (1U << 12) +#define AUD_TCON1_PDN_DMIC3_ADC (1U << 11) +#define AUD_TCON1_PDN_DMIC2_ADC (1U << 10) +#define AUD_TCON1_PDN_DMIC1_ADC (1U << 9) +#define AUD_TCON1_PDN_DMIC0_ADC (1U << 8) +#define AUD_TCON1_PDN_I2S4_BCLK (1U << 7) +#define AUD_TCON1_PDN_I2S3_BCLK (1U << 6) +#define AUD_TCON1_PDN_I2S2_BCLK (1U << 5) +#define AUD_TCON1_PDN_I2S1_BCLK (1U << 4) + +/* AUDIO_TOP_CON3 (0x000C) */ +#define AUD_TCON3_HDMI_BCK_INV (1U << 3) + +/* AFE_I2S_CON (0x0018) */ +#define AFE_I2S_CON_PHASE_SHIFT_FIX (1U << 31) +#define AFE_I2S_CON_FROM_IO_MUX (1U << 28) +#define AFE_I2S_CON_LOW_JITTER_CLK (1U << 12) +#define AFE_I2S_CON_RATE_MASK GENMASK(11, 8) +#define AFE_I2S_CON_FORMAT_I2S (1U << 3) +#define AFE_I2S_CON_SRC_SLAVE (1U << 2) + +/* AFE_ASRC_2CH_CON0 */ +#define ONE_HEART (1U << 31) +#define CHSET_STR_CLR (1U << 4) +#define COEFF_SRAM_CTRL (1U << 1) +#define ASM_ON (1U << 0) + +/* CON2 */ +#define O16BIT (1U << 19) +#define CLR_IIR_HISTORY (1U << 17) +#define IS_MONO (1U << 16) +#define IIR_EN (1U << 11) +#define IIR_STAGE_MASK GENMASK(10, 8) + +/* CON5 */ +#define CALI_CYCLE_MASK GENMASK(31, 16) +#define CALI_64_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x3F) +#define CALI_96_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x5F) +#define CALI_441_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x1B8) + +#define CALI_AUTORST (1U << 15) +#define AUTO_TUNE_FREQ5 (1U << 12) +#define COMP_FREQ_RES (1U << 11) + +#define CALI_SEL_MASK GENMASK(9, 8) +#define CALI_SEL_00 FIELD_PREP(CALI_SEL_MASK, 0) +#define CALI_SEL_01 FIELD_PREP(CALI_SEL_MASK, 1) + +#define CALI_BP_DGL (1U << 7) /* Bypass the deglitch circuit */ +#define AUTO_TUNE_FREQ4 (1U << 3) +#define CALI_AUTO_RESTART (1U << 2) +#define CALI_USE_FREQ_OUT (1U << 1) +#define CALI_ON (1U << 0) + +#define AFE_I2S_CON_WLEN_32BIT (1U << 1) +#define AFE_I2S_CON_EN (1U << 0) + +#define AFE_CONN3_I03_O03_S (1U << 3) +#define AFE_CONN4_I04_O04_S (1U << 4) +#define AFE_CONN4_I03_O04_S (1U << 3) + +/* AFE_I2S_CON1 (0x0034) */ +#define AFE_I2S_CON1_I2S2_TO_PAD (1U << 18) +#define AFE_I2S_CON1_TDMOUT_TO_PAD (0 << 18) +#define AFE_I2S_CON1_RATE GENMASK(11, 8) +#define AFE_I2S_CON1_FORMAT_I2S (1U << 3) +#define AFE_I2S_CON1_WLEN_32BIT (1U << 1) +#define AFE_I2S_CON1_EN (1U << 0) + +/* AFE_I2S_CON2 (0x0038) */ +#define AFE_I2S_CON2_LOW_JITTER_CLK (1U << 12) +#define AFE_I2S_CON2_RATE GENMASK(11, 8) +#define AFE_I2S_CON2_FORMAT_I2S (1U << 3) +#define AFE_I2S_CON2_WLEN_32BIT (1U << 1) +#define AFE_I2S_CON2_EN (1U << 0) + +/* AFE_I2S_CON3 (0x004C) */ +#define AFE_I2S_CON3_LOW_JITTER_CLK (1U << 12) +#define AFE_I2S_CON3_RATE GENMASK(11, 8) +#define AFE_I2S_CON3_FORMAT_I2S (1U << 3) +#define AFE_I2S_CON3_WLEN_32BIT (1U << 1) +#define AFE_I2S_CON3_EN (1U << 0) + +/* AFE_ADDA_DL_SRC2_CON0 (0x0108) */ +#define AFE_ADDA_DL_SAMPLING_RATE GENMASK(31, 28) +#define AFE_ADDA_DL_8X_UPSAMPLE GENMASK(25, 24) +#define AFE_ADDA_DL_MUTE_OFF_CH1 (1U << 12) +#define AFE_ADDA_DL_MUTE_OFF_CH2 (1U << 11) +#define AFE_ADDA_DL_VOICE_DATA (1U << 5) +#define AFE_ADDA_DL_DEGRADE_GAIN (1U << 1) + +/* AFE_ADDA_UL_SRC_CON0 (0x0114) */ +#define AFE_ADDA_UL_SAMPLING_RATE GENMASK(19, 17) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA_UL_DL_ADDA_AFE_ON (1U << 0) +#define AFE_ADDA_UL_DL_DMIC_CLKDIV_ON (1U << 1) + +/* AFE_APLL_TUNER_CFG (0x03f0) */ +#define AFE_APLL_TUNER_CFG_MASK GENMASK(15, 1) +#define AFE_APLL_TUNER_CFG_EN_MASK (1U << 0) + +/* AFE_APLL_TUNER_CFG1 (0x03f4) */ +#define AFE_APLL_TUNER_CFG1_MASK GENMASK(15, 1) +#define AFE_APLL_TUNER_CFG1_EN_MASK (1U << 0) + +/* PCM_INTF_CON1 (0x0550) */ +#define PCM_INTF_CON1_EXT_MODEM (1U << 17) +#define PCM_INTF_CON1_16BIT (0 << 16) +#define PCM_INTF_CON1_24BIT (1U << 16) +#define PCM_INTF_CON1_32BCK (0 << 14) +#define PCM_INTF_CON1_64BCK (1U << 14) +#define PCM_INTF_CON1_MASTER_MODE (0 << 5) +#define PCM_INTF_CON1_SLAVE_MODE (1U << 5) +#define PCM_INTF_CON1_FS_MASK GENMASK(4, 3) +#define PCM_INTF_CON1_FS_8K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 0) +#define PCM_INTF_CON1_FS_16K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 1) +#define PCM_INTF_CON1_FS_32K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 2) +#define PCM_INTF_CON1_FS_48K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 3) +#define PCM_INTF_CON1_SYNC_LEN_MASK GENMASK(13, 9) +#define PCM_INTF_CON1_SYNC_LEN(x) FIELD_PREP(PCM_INTF_CON1_SYNC_LEN_MASK, ((x) - 1)) +#define PCM_INTF_CON1_FORMAT_MASK GENMASK(2, 1) +#define PCM_INTF_CON1_SYNC_OUT_INV (1U << 23) +#define PCM_INTF_CON1_BCLK_OUT_INV (1U << 22) +#define PCM_INTF_CON1_SYNC_IN_INV (1U << 21) +#define PCM_INTF_CON1_BCLK_IN_INV (1U << 20) +#define PCM_INTF_CON1_BYPASS_ASRC (1U << 6) +#define PCM_INTF_CON1_EN (1U << 0) +#define PCM_INTF_CON1_CONFIG_MASK (0xf3fffe) + +/* AFE_DMIC0_UL_SRC_CON0 (0x05b4) + * AFE_DMIC1_UL_SRC_CON0 (0x0620) + * AFE_DMIC2_UL_SRC_CON0 (0x0780) + * AFE_DMIC3_UL_SRC_CON0 (0x07ec) + */ +#define DMIC_TOP_CON_CK_PHASE_SEL_CH1 GENMASK(29, 27) +#define DMIC_TOP_CON_CK_PHASE_SEL_CH2 GENMASK(26, 24) +#define DMIC_TOP_CON_TWO_WIRE_MODE (1U << 23) +#define DMIC_TOP_CON_CH2_ON (1U << 22) +#define DMIC_TOP_CON_CH1_ON (1U << 21) +#define DMIC_TOP_CON_VOICE_MODE_MASK GENMASK(19, 17) +#define DMIC_TOP_CON_VOICE_MODE_8K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 0) +#define DMIC_TOP_CON_VOICE_MODE_16K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 1) +#define DMIC_TOP_CON_VOICE_MODE_32K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 2) +#define DMIC_TOP_CON_VOICE_MODE_48K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 3) +#define DMIC_TOP_CON_LOW_POWER_MODE_MASK GENMASK(15, 14) +#define DMIC_TOP_CON_LOW_POWER_MODE(x) FIELD_PREP(DMIC_TOP_CON_LOW_POWER_MODE_MASK, (x)) +#define DMIC_TOP_CON_IIR_ON (1U << 10) +#define DMIC_TOP_CON_IIR_MODE GENMASK(9, 7) +#define DMIC_TOP_CON_INPUT_MODE (1U << 5) +#define DMIC_TOP_CON_SDM3_LEVEL_MODE (1U << 1) +#define DMIC_TOP_CON_SRC_ON (1U << 0) +#define DMIC_TOP_CON_SDM3_DE_SELECT (0 << 1) +#define DMIC_TOP_CON_CONFIG_MASK (0x3f8ed7a6) + +/* AFE_CONN_24BIT (0x0AA4) */ +#define AFE_CONN_24BIT_O10 (1U << 10) +#define AFE_CONN_24BIT_O09 (1U << 9) +#define AFE_CONN_24BIT_O06 (1U << 6) +#define AFE_CONN_24BIT_O05 (1U << 5) +#define AFE_CONN_24BIT_O04 (1U << 4) +#define AFE_CONN_24BIT_O03 (1U << 3) +#define AFE_CONN_24BIT_O02 (1U << 2) +#define AFE_CONN_24BIT_O01 (1U << 1) +#define AFE_CONN_24BIT_O00 (1U << 0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_22M_PLL_EN (1U << 0) +#define AFE_24M_PLL_EN (1U << 1) + +/* AFE_GAIN1_CON0 (0x0410) */ +#define AFE_GAIN1_CON0_EN_MASK GENMASK(0, 0) +#define AFE_GAIN1_CON0_MODE_MASK GENMASK(7, 4) +#define AFE_GAIN1_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8) + +/* AFE_GAIN1_CON1 (0x0414) */ +#define AFE_GAIN1_CON1_MASK GENMASK(19, 0) + +/* AFE_GAIN1_CUR (0x0B78) */ +#define AFE_GAIN1_CUR_MASK GENMASK(19, 0) + +/* AFE_CM1_CON0 (0x0e50) */ +/* AFE_CM2_CON0 (0x0e60) */ +#define CM_AFE_CM_CH_NUM_MASK GENMASK(3, 0) +#define CM_AFE_CM_CH_NUM(x) FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, ((x) - 1)) +#define CM_AFE_CM_ON (1U << 4) +#define CM_AFE_CM_START_DATA_MASK GENMASK(11, 8) + +#define CM_AFE_CM1_VUL_SEL (1U << 12) +#define CM_AFE_CM1_IN_MODE_MASK GENMASK(19, 16) +#define CM_AFE_CM2_TDM_SEL (1U << 12) +#define CM_AFE_CM2_CLK_SEL (1U << 13) +#define CM_AFE_CM2_GASRC1_OUT_SEL (1U << 17) +#define CM_AFE_CM2_GASRC2_OUT_SEL (1U << 16) + +/* AFE_CM2_CONN* */ +#define CM2_AFE_CM2_CONN_CFG1(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG1_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG1_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG2(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG2_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG2_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG3(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG3_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG3_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG4(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG4_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG4_MASK GENMASK(19, 15) +#define CM2_AFE_CM2_CONN_CFG5(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG5_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG5_MASK GENMASK(24, 20) +#define CM2_AFE_CM2_CONN_CFG6(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG6_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG6_MASK GENMASK(29, 25) +#define CM2_AFE_CM2_CONN_CFG7(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG7_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG7_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG8(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG8_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG8_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG9(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG9_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG9_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG10(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG10_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG10_MASK GENMASK(19, 15) +#define CM2_AFE_CM2_CONN_CFG11(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG11_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG11_MASK GENMASK(24, 20) +#define CM2_AFE_CM2_CONN_CFG12(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG12_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG12_MASK GENMASK(29, 25) +#define CM2_AFE_CM2_CONN_CFG13(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG13_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG13_MASK GENMASK(4, 0) +#define CM2_AFE_CM2_CONN_CFG14(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG14_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG14_MASK GENMASK(9, 5) +#define CM2_AFE_CM2_CONN_CFG15(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG15_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG15_MASK GENMASK(14, 10) +#define CM2_AFE_CM2_CONN_CFG16(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG16_MASK, (x)) +#define CM2_AFE_CM2_CONN_CFG16_MASK GENMASK(19, 15) + +/* AFE_CM1_CON* */ +#define CM_AFE_CM_UPDATE_CNT1_MASK GENMASK(15, 0) +#define CM_AFE_CM_UPDATE_CNT1(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT1_MASK, (x)) +#define CM_AFE_CM_UPDATE_CNT2_MASK GENMASK(31, 16) +#define CM_AFE_CM_UPDATE_CNT2(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT2_MASK, (x)) + +#endif diff --git a/sound/soc/meson/aiu-fifo.h b/sound/soc/meson/aiu-fifo.h index 84ab4577815a..b02cfcc4de7f 100644 --- a/sound/soc/meson/aiu-fifo.h +++ b/sound/soc/meson/aiu-fifo.h @@ -38,8 +38,6 @@ int aiu_fifo_prepare(struct snd_pcm_substream *substream, int aiu_fifo_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai); -int aiu_fifo_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai); int aiu_fifo_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); void aiu_fifo_shutdown(struct snd_pcm_substream *substream, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index 5d1419ed7a62..f2890111c1d2 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -345,7 +345,7 @@ MODULE_DEVICE_TABLE(of, aiu_of_match); static struct platform_driver aiu_pdrv = { .probe = aiu_probe, - .remove_new = aiu_remove, + .remove = aiu_remove, .driver = { .name = "meson-aiu", .of_match_table = aiu_of_match, diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 8c5605c1e34e..59deb332bd35 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -132,7 +132,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, lb->stream_name = lb->name; lb->cpus->of_node = pad->cpus->of_node; lb->cpus->dai_name = "TDM Loopback"; - lb->dpcm_capture = 1; + lb->capture_only = 1; lb->no_pcm = 1; lb->ops = &axg_card_tdm_be_ops; lb->init = axg_card_tdm_dai_lb_init; @@ -176,7 +176,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, /* Disable playback is the interface has no tx slots */ if (!tx) - link->dpcm_playback = 0; + link->capture_only = 1; for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) { snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i); @@ -186,9 +186,9 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, /* Disable capture is the interface has no rx slots */ if (!rx) - link->dpcm_capture = 0; + link->playback_only = 1; - /* ... but the interface should at least have one of them */ + /* ... but the interface should at least have one direction */ if (!tx && !rx) { dev_err(card->dev, "tdm link has no cpu slots\n"); return -EINVAL; @@ -275,7 +275,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, return ret; /* Add loopback if the pad dai has playback */ - if (link->dpcm_playback) { + if (!link->capture_only) { ret = axg_card_add_tdm_loopback(card, index); if (ret) return ret; @@ -339,7 +339,6 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, dai_link->num_c2c_params = 1; } else { dai_link->no_pcm = 1; - snd_soc_dai_link_set_capabilities(dai_link); if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node)) ret = axg_card_parse_tdm(card, np, index); } @@ -361,7 +360,7 @@ MODULE_DEVICE_TABLE(of, axg_card_of_match); static struct platform_driver axg_card_pdrv = { .probe = meson_card_probe, - .remove_new = meson_card_remove, + .remove = meson_card_remove, .driver = { .name = "axg-sound-card", .of_match_table = axg_card_of_match, diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c index f1539e542638..455f6bfc9f8f 100644 --- a/sound/soc/meson/gx-card.c +++ b/sound/soc/meson/gx-card.c @@ -107,7 +107,6 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np, dai_link->num_c2c_params = 1; } else { dai_link->no_pcm = 1; - snd_soc_dai_link_set_capabilities(dai_link); /* Check if the cpu is the i2s encoder and parse i2s data */ if (gx_card_cpu_identify(dai_link->cpus, "I2S Encoder")) ret = gx_card_parse_i2s(card, np, index); @@ -130,7 +129,7 @@ MODULE_DEVICE_TABLE(of, gx_card_of_match); static struct platform_driver gx_card_pdrv = { .probe = meson_card_probe, - .remove_new = meson_card_remove, + .remove = meson_card_remove, .driver = { .name = "gx-sound-card", .of_match_table = gx_card_of_match, diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index ed6c7e2f609c..1a4ef124e4e2 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -186,9 +186,9 @@ int meson_card_set_fe_link(struct snd_soc_card *card, link->dpcm_merged_rate = 1; if (is_playback) - link->dpcm_playback = 1; + link->playback_only = 1; else - link->dpcm_capture = 1; + link->capture_only = 1; return meson_card_set_link_name(card, link, node, "fe"); } diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 310e3ac77424..a41a13ae38a5 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -185,7 +185,7 @@ static struct platform_driver mxs_sgtl5000_audio_driver = { .of_match_table = mxs_sgtl5000_dt_ids, }, .probe = mxs_sgtl5000_probe, - .remove_new = mxs_sgtl5000_remove, + .remove = mxs_sgtl5000_remove, }; module_platform_driver(mxs_sgtl5000_audio_driver); diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index abfaf3cdf5bb..73f36c9dd35c 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -574,7 +574,7 @@ static struct platform_driver asoc_mmp_sspa_driver = { .of_match_table = of_match_ptr(mmp_sspa_of_match), }, .probe = asoc_mmp_sspa_probe, - .remove_new = asoc_mmp_sspa_remove, + .remove = asoc_mmp_sspa_remove, }; module_platform_driver(asoc_mmp_sspa_driver); diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 80e0ea0ec9fb..78f50032afc5 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -286,7 +286,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_dev_probe, - .remove_new = pxa2xx_ac97_dev_remove, + .remove = pxa2xx_ac97_dev_remove, .driver = { .name = "pxa2xx-ac97", .pm = &pxa2xx_ac97_pm_ops, diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 56b4a3654aec..928cf5cb5999 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -155,7 +155,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) if (platform || !codec) { /* DPCM */ - snd_soc_dai_link_set_capabilities(link); link->ignore_suspend = 1; link->nonatomic = 1; } diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 9005c85f8c54..b8f23414eb77 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -300,7 +300,7 @@ static struct platform_driver apq8016_lpass_cpu_platform_driver = { .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id), }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, }; module_platform_driver(apq8016_lpass_cpu_platform_driver); diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 5c874139f39d..e57d29ea4ce7 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -172,7 +172,7 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = { .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id), }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, }; module_platform_driver(ipq806x_lpass_cpu_platform_driver); diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index e6bcdf6ed796..fbead6af3d95 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -315,7 +315,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { .pm = &sc7180_lpass_pm_ops, }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, }; diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index 47c622327a8d..7cd3e291382a 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -445,7 +445,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { .pm = &sc7280_lpass_pm_ops, }, .probe = asoc_qcom_lpass_cpu_platform_probe, - .remove_new = asoc_qcom_lpass_cpu_platform_remove, + .remove = asoc_qcom_lpass_cpu_platform_remove, .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, }; diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 81fde0681f95..90228699ba7d 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -1161,7 +1161,7 @@ static struct platform_driver q6pcm_routing_platform_driver = { .of_match_table = of_match_ptr(q6pcm_routing_device_id), }, .probe = q6pcm_routing_probe, - .remove_new = q6pcm_routing_remove, + .remove = q6pcm_routing_remove, }; module_platform_driver(q6pcm_routing_platform_driver); diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index a15dafb99b33..274bab28209a 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -55,6 +55,14 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; case TERTIARY_MI2S_RX: codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; snd_soc_dai_set_sysclk(cpu_dai, diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index b378f870b3ad..4315da4a47c1 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -866,7 +866,7 @@ static const struct dev_pm_ops rockchip_i2s_pm_ops = { static struct platform_driver rockchip_i2s_driver = { .probe = rockchip_i2s_probe, - .remove_new = rockchip_i2s_remove, + .remove = rockchip_i2s_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rockchip_i2s_match), diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index ee517d7b5b7b..d1f28699652f 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1423,7 +1423,7 @@ static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = { static struct platform_driver rockchip_i2s_tdm_driver = { .probe = rockchip_i2s_tdm_probe, - .remove_new = rockchip_i2s_tdm_remove, + .remove = rockchip_i2s_tdm_remove, .driver = { .name = DRV_NAME, .of_match_table = rockchip_i2s_tdm_match, diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index d16a4a67a6a2..cae91108f7a8 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -703,7 +703,7 @@ static const struct dev_pm_ops rockchip_pdm_pm_ops = { static struct platform_driver rockchip_pdm_driver = { .probe = rockchip_pdm_probe, - .remove_new = rockchip_pdm_remove, + .remove = rockchip_pdm_remove, .driver = { .name = "rockchip-pdm", .of_match_table = of_match_ptr(rockchip_pdm_match), diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 449f62820045..b085d80ea2e4 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -233,7 +233,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match); static struct platform_driver snd_rk_mc_driver = { .probe = snd_rk_mc_probe, - .remove_new = snd_rk_mc_remove, + .remove = snd_rk_mc_remove, .driver = { .name = DRV_NAME, .pm = &snd_soc_pm_ops, diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index eb9d5dee196e..d87c0e4f6f91 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -380,7 +380,7 @@ static const struct dev_pm_ops rk_spdif_pm_ops = { static struct platform_driver rk_spdif_driver = { .probe = rk_spdif_probe, - .remove_new = rk_spdif_remove, + .remove = rk_spdif_remove, .driver = { .name = "rockchip-spdif", .of_match_table = of_match_ptr(rk_spdif_match), diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c index f02873b6ce7f..9619f550608c 100644 --- a/sound/soc/samsung/arndale.c +++ b/sound/soc/samsung/arndale.c @@ -207,7 +207,7 @@ static struct platform_driver arndale_audio_driver = { .of_match_table = arndale_audio_of_match, }, .probe = arndale_audio_probe, - .remove_new = arndale_audio_remove, + .remove = arndale_audio_remove, }; module_platform_driver(arndale_audio_driver); diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 1bcabb114e29..8f6deb06e234 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1741,7 +1741,7 @@ static const struct dev_pm_ops samsung_i2s_pm = { static struct platform_driver samsung_i2s_driver = { .probe = samsung_i2s_probe, - .remove_new = samsung_i2s_remove, + .remove = samsung_i2s_remove, .id_table = samsung_i2s_driver_ids, .driver = { .name = "samsung-i2s", diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 110ae14dd7ea..ed865cc07e2e 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -341,7 +341,7 @@ static struct platform_driver odroid_audio_driver = { .pm = &snd_soc_pm_ops, }, .probe = odroid_audio_probe, - .remove_new = odroid_audio_remove, + .remove = odroid_audio_remove, }; module_platform_driver(odroid_audio_driver); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 573b2dee7f07..a03ba9374c2e 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -590,7 +590,7 @@ static void s3c_pcm_dev_remove(struct platform_device *pdev) static struct platform_driver s3c_pcm_driver = { .probe = s3c_pcm_dev_probe, - .remove_new = s3c_pcm_dev_remove, + .remove = s3c_pcm_dev_remove, .driver = { .name = "samsung-pcm", }, diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index aad0f9b4d4fc..4bbe7bcdb845 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -245,7 +245,7 @@ static struct platform_driver snow_driver = { .of_match_table = snow_of_match, }, .probe = snow_probe, - .remove_new = snow_remove, + .remove = snow_remove, }; module_platform_driver(snow_driver); diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index f44e3180e8d3..235d0063d1b3 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -476,7 +476,7 @@ static void spdif_remove(struct platform_device *pdev) static struct platform_driver samsung_spdif_driver = { .probe = spdif_probe, - .remove_new = spdif_remove, + .remove = spdif_remove, .driver = { .name = "samsung-spdif", }, diff --git a/sound/soc/sdw_utils/Kconfig b/sound/soc/sdw_utils/Kconfig new file mode 100644 index 000000000000..d915083c3889 --- /dev/null +++ b/sound/soc/sdw_utils/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +config SND_SOC_SDW_UTILS + tristate + help + This option enables to use SoundWire common helper functions and + SoundWire codec helper functions in machine driver. diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile new file mode 100644 index 000000000000..28229ed96ffb --- /dev/null +++ b/sound/soc/sdw_utils/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \ + soc_sdw_rt700.o soc_sdw_rt711.o \ + soc_sdw_rt712_sdca.o soc_sdw_rt722_sdca.o \ + soc_sdw_rt5682.o soc_sdw_rt_sdca_jack_common.o \ + soc_sdw_rt_amp.o \ + soc_sdw_bridge_cs35l56.o \ + soc_sdw_cs42l42.o soc_sdw_cs42l43.o \ + soc_sdw_cs_amp.o \ + soc_sdw_maxim.o +obj-$(CONFIG_SND_SOC_SDW_UTILS) += snd-soc-sdw-utils.o diff --git a/sound/soc/intel/boards/bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c similarity index 63% rename from sound/soc/intel/boards/bridge_cs35l56.c rename to sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c index c3995e724aed..fcc3ef685af7 100644 --- a/sound/soc/intel/boards/bridge_cs35l56.c +++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c @@ -1,6 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only -// -// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2024 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. + +/* + * soc_sdw_bridge_cs35l56 - codec helper functions for handling CS35L56 Smart AMP + */ #include #include @@ -9,7 +14,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_widget bridge_widgets[] = { SND_SOC_DAPM_SPK("Bridge Speaker", NULL), @@ -25,7 +30,7 @@ static const char * const bridge_cs35l56_name_prefixes[] = { "AMPR", }; -static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) +static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int i, ret; @@ -73,7 +78,7 @@ static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static const struct snd_soc_pcm_stream bridge_params = { +static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = { .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 48000, .rate_max = 48000, @@ -81,7 +86,7 @@ static const struct snd_soc_pcm_stream bridge_params = { .channels_max = 2, }; -SND_SOC_DAILINK_DEFS(bridge_dai, +SND_SOC_DAILINK_DEFS(asoc_sdw_bridge_dai, DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")), DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"), COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")), @@ -89,28 +94,33 @@ SND_SOC_DAILINK_DEFS(bridge_dai, static const struct snd_soc_dai_link bridge_dai_template = { .name = "cs42l43-cs35l56", - .init = bridge_cs35l56_asp_init, - .c2c_params = &bridge_params, + .init = asoc_sdw_bridge_cs35l56_asp_init, + .c2c_params = &asoc_sdw_bridge_params, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC, - SND_SOC_DAILINK_REG(bridge_dai), + SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai), }; -int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, - int *num_dais, int *num_devs) +int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { (*num_dais)++; (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); } return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, SND_SOC_SDW_UTILS); -int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, - struct snd_soc_codec_conf **codec_conf) +int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { **dai_links = bridge_dai_template; for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) { @@ -124,14 +134,18 @@ int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, SND_SOC_SDW_UTILS); -int bridge_cs35l56_spk_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes); return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/sdw_utils/soc_sdw_cs42l42.c similarity index 82% rename from sound/soc/intel/boards/sof_sdw_cs42l42.c rename to sound/soc/sdw_utils/soc_sdw_cs42l42.c index fc18e4aa3dbe..78a6cb059ac0 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l42.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation - +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver + * soc_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver */ #include @@ -15,7 +16,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route cs42l42_map[] = { /* HP jack connectors - unknown if we have jack detection */ @@ -36,10 +37,10 @@ static struct snd_soc_jack_pin cs42l42_jack_pins[] = { }, }; -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -87,4 +88,4 @@ int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l42_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c similarity index 73% rename from sound/soc/intel/boards/sof_sdw_cs42l43.c rename to sound/soc/sdw_utils/soc_sdw_cs42l43.c index b7e2750c1074..adb1c008e871 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only // Based on sof_sdw_rt5682.c +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver + * soc_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver */ #include #include @@ -16,7 +18,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route cs42l43_hs_map[] = { { "Headphone", NULL, "cs42l43 AMP3_OUT" }, @@ -37,7 +39,7 @@ static const struct snd_soc_dapm_route cs42l43_dmic_map[] = { { "cs42l43 PDM2_DIN", NULL, "DMIC" }, }; -static struct snd_soc_jack_pin sof_jack_pins[] = { +static struct snd_soc_jack_pin soc_jack_pins[] = { { .pin = "Headphone", .mask = SND_JACK_HEADPHONE, @@ -48,10 +50,10 @@ static struct snd_soc_jack_pin sof_jack_pins[] = { }, }; -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_jack *jack = &ctx->sdw_headset; struct snd_soc_card *card = rtd->card; int ret; @@ -73,8 +75,8 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack, sof_jack_pins, - ARRAY_SIZE(sof_jack_pins)); + jack, soc_jack_pins, + ARRAY_SIZE(soc_jack_pins)); if (ret) { dev_err(card->dev, "Failed to create jack: %d\n", ret); return ret; @@ -98,13 +100,15 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, SND_SOC_SDW_UTILS); -int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; - if (!(sof_sdw_quirk & SOF_SIDECAR_AMPS)) { + if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) { /* Will be set by the bridge code in this case */ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:cs42l43-spk", @@ -120,11 +124,12 @@ int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *da return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { /* Do init on playback link only. */ if (!playback) @@ -132,10 +137,11 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, info->amp_num++; - return bridge_cs35l56_spk_init(card, dai_links, info, playback); + return asoc_sdw_bridge_cs35l56_spk_init(card, dai_links, info, playback); } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, SND_SOC_SDW_UTILS); -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -152,4 +158,4 @@ int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c similarity index 66% rename from sound/soc/intel/boards/sof_sdw_cs_amp.c rename to sound/soc/sdw_utils/soc_sdw_cs_amp.c index 10e08207619a..58b059b68016 100644 --- a/sound/soc/intel/boards/sof_sdw_cs_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver + * soc_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver */ #include @@ -10,11 +12,11 @@ #include #include #include -#include "sof_sdw_common.h" +#include #define CODEC_NAME_SIZE 8 -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { const char *dai_name = rtd->dai_link->codecs->dai_name; struct snd_soc_card *card = rtd->card; @@ -44,11 +46,12 @@ int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_cs_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_cs_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { /* Do init on playback link only. */ if (!playback) @@ -58,3 +61,4 @@ int sof_sdw_cs_amp_init(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_cs_amp_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/sdw_utils/soc_sdw_dmic.c similarity index 71% rename from sound/soc/intel/boards/sof_sdw_dmic.c rename to sound/soc/sdw_utils/soc_sdw_dmic.c index 19df0f7a1d85..fc2aae985084 100644 --- a/sound/soc/intel/boards/sof_sdw_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_dmic.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_dmic - Helpers to handle dmic from generic machine driver + * soc_sdw_dmic - Helpers to handle dmic from generic machine driver */ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_widget dmic_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), @@ -19,7 +21,7 @@ static const struct snd_soc_dapm_route dmic_map[] = { {"DMic", NULL, "SoC DMIC"}, }; -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) +int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int ret; @@ -40,4 +42,4 @@ int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_dmic_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/sdw_utils/soc_sdw_maxim.c similarity index 63% rename from sound/soc/intel/boards/sof_sdw_maxim.c rename to sound/soc/sdw_utils/soc_sdw_maxim.c index b7f73177867f..cdcd8df37e1d 100644 --- a/sound/soc/intel/boards/sof_sdw_maxim.c +++ b/sound/soc/sdw_utils/soc_sdw_maxim.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. // -// sof_sdw_maxim - Helpers to handle maxim codecs +// soc_sdw_maxim - Helpers to handle maxim codecs // codec devices from generic machine driver #include @@ -10,18 +12,18 @@ #include #include #include -#include "sof_sdw_common.h" +#include static int maxim_part_id; -#define SOF_SDW_PART_ID_MAX98363 0x8363 -#define SOF_SDW_PART_ID_MAX98373 0x8373 +#define SOC_SDW_PART_ID_MAX98363 0x8363 +#define SOC_SDW_PART_ID_MAX98373 0x8373 static const struct snd_soc_dapm_route max_98373_dapm_routes[] = { { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, }; -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -41,8 +43,9 @@ int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, SND_SOC_SDW_UTILS); -static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) +static int asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -75,40 +78,40 @@ static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enabl return 0; } -static int mx8373_sdw_prepare(struct snd_pcm_substream *substream) +static int asoc_sdw_mx8373_prepare(struct snd_pcm_substream *substream) { int ret; /* according to soc_pcm_prepare dai link prepare is called first */ - ret = sdw_prepare(substream); + ret = asoc_sdw_prepare(substream); if (ret < 0) return ret; - return mx8373_enable_spk_pin(substream, true); + return asoc_sdw_mx8373_enable_spk_pin(substream, true); } -static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream) +static int asoc_sdw_mx8373_hw_free(struct snd_pcm_substream *substream) { int ret; /* according to soc_pcm_hw_free dai link free is called first */ - ret = sdw_hw_free(substream); + ret = asoc_sdw_hw_free(substream); if (ret < 0) return ret; - return mx8373_enable_spk_pin(substream, false); + return asoc_sdw_mx8373_enable_spk_pin(substream, false); } static const struct snd_soc_ops max_98373_sdw_ops = { - .startup = sdw_startup, - .prepare = mx8373_sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = mx8373_sdw_hw_free, - .shutdown = sdw_shutdown, + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_mx8373_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_mx8373_hw_free, + .shutdown = asoc_sdw_shutdown, }; -static int mx8373_sdw_late_probe(struct snd_soc_card *card) +static int asoc_sdw_mx8373_sdw_late_probe(struct snd_soc_card *card) { struct snd_soc_dapm_context *dapm = &card->dapm; @@ -118,22 +121,22 @@ static int mx8373_sdw_late_probe(struct snd_soc_card *card) return snd_soc_dapm_sync(dapm); } -int sof_sdw_maxim_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_maxim_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { info->amp_num++; maxim_part_id = info->part_id; switch (maxim_part_id) { - case SOF_SDW_PART_ID_MAX98363: + case SOC_SDW_PART_ID_MAX98363: /* Default ops are set in function init_dai_link. * called as part of function create_sdw_dailink */ break; - case SOF_SDW_PART_ID_MAX98373: - info->codec_card_late_probe = mx8373_sdw_late_probe; + case SOC_SDW_PART_ID_MAX98373: + info->codec_card_late_probe = asoc_sdw_mx8373_sdw_late_probe; dai_links->ops = &max_98373_sdw_ops; break; default: @@ -142,3 +145,4 @@ int sof_sdw_maxim_init(struct snd_soc_card *card, } return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/sdw_utils/soc_sdw_rt5682.c similarity index 82% rename from sound/soc/intel/boards/sof_sdw_rt5682.c rename to sound/soc/sdw_utils/soc_sdw_rt5682.c index 67737815d016..80b4caa92667 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/sdw_utils/soc_sdw_rt5682.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver + * soc_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver */ #include @@ -15,7 +17,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt5682_map[] = { /*Headphones*/ @@ -35,10 +37,10 @@ static struct snd_soc_jack_pin rt5682_jack_pins[] = { }, }; -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -86,4 +88,4 @@ int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt5682_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/sdw_utils/soc_sdw_rt700.c similarity index 81% rename from sound/soc/intel/boards/sof_sdw_rt700.c rename to sound/soc/sdw_utils/soc_sdw_rt700.c index 0db730071be2..4dbeeeca3434 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/sdw_utils/soc_sdw_rt700.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver + * soc_sdw_rt700 - Helpers to handle RT700 from generic machine driver */ #include @@ -13,7 +15,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt700_map[] = { /* Headphones */ @@ -33,10 +35,10 @@ static struct snd_soc_jack_pin rt700_jack_pins[] = { }, }; -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -83,4 +85,4 @@ int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt700_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c similarity index 70% rename from sound/soc/intel/boards/sof_sdw_rt711.c rename to sound/soc/sdw_utils/soc_sdw_rt711.c index 60ff4d88e2dc..38b4126dd45f 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/sdw_utils/soc_sdw_rt711.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver + * soc_sdw_rt711 - Helpers to handle RT711 from generic machine driver */ #include @@ -15,21 +17,21 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int rt711_add_codec_device_props(struct device *sdw_dev) +static int rt711_add_codec_device_props(struct device *sdw_dev, unsigned long quirk) { - struct property_entry props[MAX_NO_PROPS] = {}; + struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {}; struct fwnode_handle *fwnode; int ret; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(quirk)) return 0; - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk)); fwnode = fwnode_create_software_node(props, NULL); if (IS_ERR(fwnode)) @@ -59,10 +61,10 @@ static struct snd_soc_jack_pin rt711_jack_pins[] = { }, }; -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -110,10 +112,11 @@ int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (!ctx->headset_codec_dev) return 0; @@ -123,13 +126,14 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt711_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt711_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev; int ret; @@ -144,7 +148,7 @@ int sof_sdw_rt711_init(struct snd_soc_card *card, if (!sdw_dev) return -EPROBE_DEFER; - ret = rt711_add_codec_device_props(sdw_dev); + ret = rt711_add_codec_device_props(sdw_dev, ctx->mc_quirk); if (ret < 0) { put_device(sdw_dev); return ret; @@ -153,4 +157,4 @@ int sof_sdw_rt711_init(struct snd_soc_card *card, return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c similarity index 74% rename from sound/soc/intel/boards/sof_sdw_rt712_sdca.c rename to sound/soc/sdw_utils/soc_sdw_rt712_sdca.c index 788796461885..5127210b9a03 100644 --- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c +++ b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver + * soc_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver */ #include @@ -13,7 +15,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * dapm routes for rt712 spk will be registered dynamically according @@ -26,7 +28,7 @@ static const struct snd_soc_dapm_route rt712_spk_map[] = { { "Speaker", NULL, "rt712 SPOR" }, }; -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -43,4 +45,4 @@ int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_rt712_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c similarity index 68% rename from sound/soc/intel/boards/sof_sdw_rt722_sdca.c rename to sound/soc/sdw_utils/soc_sdw_rt722_sdca.c index 083d281bd052..6a402172289f 100644 --- a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c +++ b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver + * soc_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver */ #include @@ -13,13 +15,13 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt722_spk_map[] = { { "Speaker", NULL, "rt722 SPK" }, }; -int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -36,4 +38,4 @@ int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_rt722_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c similarity index 84% rename from sound/soc/intel/boards/sof_sdw_rt_amp.c rename to sound/soc/sdw_utils/soc_sdw_rt_amp.c index d1c0f91ce589..6951dfb56526 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2022 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver + * soc_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver */ #include @@ -14,9 +16,9 @@ #include #include #include -#include "sof_sdw_common.h" -#include "sof_sdw_amp_coeff_tables.h" -#include "../../codecs/rt1308.h" +#include +#include "soc_sdw_rt_amp_coeff_tables.h" +#include "../codecs/rt1308.h" #define CODEC_NAME_SIZE 7 @@ -158,6 +160,13 @@ static const struct snd_soc_dapm_route rt1318_map[] = { { "Speaker", NULL, "rt1318-2 SPOR" }, }; +static const struct snd_soc_dapm_route rt1320_map[] = { + { "Speaker", NULL, "rt1320-1 SPOL" }, + { "Speaker", NULL, "rt1320-1 SPOR" }, + { "Speaker", NULL, "rt1320-2 SPOL" }, + { "Speaker", NULL, "rt1320-2 SPOR" }, +}; + static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_dai *dai, char *codec_name) { @@ -169,11 +178,13 @@ static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_ return rt1308_map; else if (strcmp(codec_name, "rt1316") == 0) return rt1316_map; - else + else if (strcmp(codec_name, "rt1318") == 0) return rt1318_map; + else + return rt1320_map; } -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; const struct snd_soc_dapm_route *rt_amp_map; @@ -199,6 +210,7 @@ int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init, SND_SOC_SDW_UTILS); static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -233,13 +245,14 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -const struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { +const struct snd_soc_ops soc_sdw_rt1308_i2s_ops = { .hw_params = rt1308_i2s_hw_params, }; +EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops, SND_SOC_SDW_UTILS); -int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (ctx->amp_dev1) { device_remove_software_node(ctx->amp_dev1); @@ -253,13 +266,14 @@ int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev1, *sdw_dev2; int ret; @@ -295,3 +309,4 @@ int sof_sdw_rt_amp_init(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h similarity index 97% rename from sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h rename to sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h index 4a3e6fdbd623..4803d134d071 100644 --- a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h @@ -2,11 +2,11 @@ */ /* - * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters + * soc_sdw_rt_amp_coeff_tables.h - related coefficients for RTK amplifier parameters */ -#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H -#define SND_SOC_SOF_SDW_AMP_COEFF_H +#ifndef SND_SOC_SDW_RT_SDW_AMP_COEFF_H +#define SND_SOC_SDW_RT_SDW_AMP_COEFF_H #define RT1308_MAX_BQ_REG 480 #define RT1316_MAX_BQ_REG 580 diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c similarity index 70% rename from sound/soc/intel/boards/sof_sdw_rt_dmic.c rename to sound/soc/sdw_utils/soc_sdw_rt_dmic.c index ea7c1a4bc566..7f24806d809d 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c @@ -1,18 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2024 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver + * soc_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver */ #include #include #include #include -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" +#include -int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct snd_soc_component *component; @@ -39,4 +40,4 @@ int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_dmic_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c similarity index 78% rename from sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c rename to sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c index 4254e30ee4c3..3e6211dc1599 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver + * soc_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver */ #include @@ -15,22 +17,22 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev) +static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev, unsigned long quirk) { - struct property_entry props[MAX_NO_PROPS] = {}; + struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {}; struct fwnode_handle *fwnode; int ret; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(quirk)) return 0; - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk)); fwnode = fwnode_create_software_node(props, NULL); if (IS_ERR(fwnode)) @@ -83,10 +85,10 @@ static const char * const need_sdca_suffix[] = { "rt711", "rt713" }; -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -160,15 +162,16 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (!ctx->headset_codec_dev) return 0; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(ctx->mc_quirk)) return 0; device_remove_software_node(ctx->headset_codec_dev); @@ -177,13 +180,14 @@ int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev; int ret; @@ -198,7 +202,7 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, if (!sdw_dev) return -EPROBE_DEFER; - ret = rt_sdca_jack_add_codec_device_props(sdw_dev); + ret = rt_sdca_jack_add_codec_device_props(sdw_dev, ctx->mc_quirk); if (ret < 0) { put_device(sdw_dev); return ret; @@ -207,4 +211,4 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c new file mode 100644 index 000000000000..a6070f822eb9 --- /dev/null +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -0,0 +1,1170 @@ +// SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2020 Intel Corporation +// Copyright(c) 2024 Advanced Micro Devices, Inc. +/* + * soc-sdw-utils.c - common SoundWire machine driver helper functions + */ + +#include +#include +#include +#include +#include + +static const struct snd_soc_dapm_widget generic_dmic_widgets[] = { + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static const struct snd_soc_dapm_widget generic_jack_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_kcontrol_new generic_jack_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget generic_spk_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new generic_spk_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_widget maxim_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_kcontrol_new maxim_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget rt700_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new rt700_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("AMIC"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +struct asoc_sdw_codec_info codec_info_list[] = { + { + .part_id = 0x700, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt700-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_rt700_rtd_init, + .controls = rt700_controls, + .num_controls = ARRAY_SIZE(rt700_controls), + .widgets = rt700_widgets, + .num_widgets = ARRAY_SIZE(rt700_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x711, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt711-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x711, + .version_id = 2, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt711-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt711_init, + .exit = asoc_sdw_rt711_exit, + .rtd_init = asoc_sdw_rt711_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x712, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt712-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {true, false}, + .dai_name = "rt712-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt712_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 2, + }, + { + .part_id = 0x1712, + .version_id = 3, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt712-sdca-dmic-aif1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x713, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt712-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1713, + .version_id = 3, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt712-sdca-dmic-aif1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1308, + .acpi_id = "10EC1308", + .dais = { + { + .direction = {true, false}, + .dai_name = "rt1308-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + .ops = &soc_sdw_rt1308_i2s_ops, + }, + { + .part_id = 0x1316, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt1316-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1318, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt1318-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1320, + .dais = { + { + .direction = {true, false}, + .dai_name = "rt1320-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x714, + .version_id = 3, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x715, + .version_id = 3, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x714, + .version_id = 2, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x715, + .version_id = 2, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x722, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt722-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {true, false}, + .dai_name = "rt722-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + /* No feedback capability is provided by rt722-sdca codec driver*/ + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt722_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + { + .direction = {false, true}, + .dai_name = "rt722-sdca-aif3", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 3, + }, + { + .part_id = 0x8373, + .dais = { + { + .direction = {true, true}, + .dai_name = "max98373-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_maxim_init, + .rtd_init = asoc_sdw_maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x8363, + .dais = { + { + .direction = {true, false}, + .dai_name = "max98363-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_maxim_init, + .rtd_init = asoc_sdw_maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x5682, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt5682-sdw", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_rt5682_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x3556, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs35l56-sdw1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_cs_amp_init, + .rtd_init = asoc_sdw_cs_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x4242, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs42l42-sdw", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_cs42l42_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x4243, + .codec_name = "cs42l43-codec", + .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, + .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, + .dais = { + { + .direction = {true, false}, + .dai_name = "cs42l43-dp5", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {false, true}, + .dai_name = "cs42l43-dp1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, + .widgets = generic_dmic_widgets, + .num_widgets = ARRAY_SIZE(generic_dmic_widgets), + }, + { + .direction = {false, true}, + .dai_name = "cs42l43-dp2", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + { + .direction = {true, false}, + .dai_name = "cs42l43-dp6", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_cs42l43_spk_init, + .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, + }, + }, + .dai_num = 4, + }, + { + .part_id = 0xaaaa, /* generic codec mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0xaa55, /* headset codec mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x55aa, /* amplifier mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x5555, + .version_id = 0, + .dais = { + { + .dai_name = "sdw-mockup-aif1", + .direction = {false, true}, + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + }, + }, + .dai_num = 1, + }, +}; +EXPORT_SYMBOL_NS(codec_info_list, SND_SOC_SDW_UTILS); + +int asoc_sdw_get_codec_info_list_count(void) +{ + return ARRAY_SIZE(codec_info_list); +}; +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) +{ + unsigned int part_id, sdw_version; + int i; + + part_id = SDW_PART_ID(adr); + sdw_version = SDW_VERSION(adr); + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + /* + * A codec info is for all sdw version with the part id if + * version_id is not specified in the codec info. + */ + if (part_id == codec_info_list[i].part_id && + (!codec_info_list[i].version_id || + sdw_version == codec_info_list[i].version_id)) + return &codec_info_list[i]; + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) +{ + int i; + + if (!acpi_id[0]) + return NULL; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) + return &codec_info_list[i]; + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + for (j = 0; j < codec_info_list[i].dai_num; j++) { + if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { + *dai_index = j; + return &codec_info_list[i]; + } + } + } + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, SND_SOC_SDW_UTILS); + +int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct asoc_sdw_codec_info *codec_info; + struct snd_soc_dai *dai; + int dai_index; + int ret; + int i; + + for_each_rtd_codec_dais(rtd, i, dai) { + codec_info = asoc_sdw_find_codec_info_dai(dai->name, &dai_index); + if (!codec_info) + return -EINVAL; + + /* + * A codec dai can be connected to different dai links for capture and playback, + * but we only need to call the rtd_init function once. + * The rtd_init for each codec dai is independent. So, the order of rtd_init + * doesn't matter. + */ + if (codec_info->dais[dai_index].rtd_init_done) + continue; + + /* + * Add card controls and dapm widgets for the first codec dai. + * The controls and widgets will be used for all codec dais. + */ + + if (i > 0) + goto skip_add_controls_widgets; + + if (codec_info->dais[dai_index].controls) { + ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, + codec_info->dais[dai_index].num_controls); + if (ret) { + dev_err(card->dev, "%#x controls addition failed: %d\n", + codec_info->part_id, ret); + return ret; + } + } + if (codec_info->dais[dai_index].widgets) { + ret = snd_soc_dapm_new_controls(&card->dapm, + codec_info->dais[dai_index].widgets, + codec_info->dais[dai_index].num_widgets); + if (ret) { + dev_err(card->dev, "%#x widgets addition failed: %d\n", + codec_info->part_id, ret); + return ret; + } + } + +skip_add_controls_widgets: + if (codec_info->dais[dai_index].rtd_init) { + ret = codec_info->dais[dai_index].rtd_init(rtd, dai); + if (ret) + return ret; + } + codec_info->dais[dai_index].rtd_init_done = true; + } + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, SND_SOC_SDW_UTILS); + +/* these wrappers are only needed to avoid typecast compilation errors */ +int asoc_sdw_startup(struct snd_pcm_substream *substream) +{ + return sdw_startup_stream(substream); +} +EXPORT_SYMBOL_NS(asoc_sdw_startup, SND_SOC_SDW_UTILS); + +int asoc_sdw_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_prepare_stream(sdw_stream); +} +EXPORT_SYMBOL_NS(asoc_sdw_prepare, SND_SOC_SDW_UTILS); + +int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + int ret; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = sdw_enable_stream(sdw_stream); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sdw_disable_stream(sdw_stream); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); + + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_trigger, SND_SOC_SDW_UTILS); + +int asoc_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link_ch_map *ch_maps; + int ch = params_channels(params); + unsigned int ch_mask; + int num_codecs; + int step; + int i; + + if (!rtd->dai_link->ch_maps) + return 0; + + /* Identical data will be sent to all codecs in playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ch_mask = GENMASK(ch - 1, 0); + step = 0; + } else { + num_codecs = rtd->dai_link->num_codecs; + + if (ch < num_codecs || ch % num_codecs != 0) { + dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", + ch, num_codecs); + return -EINVAL; + } + + ch_mask = GENMASK(ch / num_codecs - 1, 0); + step = hweight_long(ch_mask); + } + + /* + * The captured data will be combined from each cpu DAI if the dai + * link has more than one codec DAIs. Set codec channel mask and + * ASoC will set the corresponding channel numbers for each cpu dai. + */ + for_each_link_ch_maps(rtd->dai_link, i, ch_maps) + ch_maps->ch_mask = ch_mask << (i * step); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_hw_params, SND_SOC_SDW_UTILS); + +int asoc_sdw_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_deprepare_stream(sdw_stream); +} +EXPORT_SYMBOL_NS(asoc_sdw_hw_free, SND_SOC_SDW_UTILS); + +void asoc_sdw_shutdown(struct snd_pcm_substream *substream) +{ + sdw_shutdown_stream(substream); +} +EXPORT_SYMBOL_NS(asoc_sdw_shutdown, SND_SOC_SDW_UTILS); + +static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, + unsigned int sdw_version, + unsigned int mfg_id, + unsigned int part_id, + unsigned int class_id, + int index_in_link) +{ + int i; + + for (i = 0; i < adr_link->num_adr; i++) { + unsigned int sdw1_version, mfg1_id, part1_id, class1_id; + u64 adr; + + /* skip itself */ + if (i == index_in_link) + continue; + + adr = adr_link->adr_d[i].adr; + + sdw1_version = SDW_VERSION(adr); + mfg1_id = SDW_MFG_ID(adr); + part1_id = SDW_PART_ID(adr); + class1_id = SDW_CLASS_ID(adr); + + if (sdw_version == sdw1_version && + mfg_id == mfg1_id && + part_id == part1_id && + class_id == class1_id) + return false; + } + + return true; +} + +const char *asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) +{ + u64 adr = adr_link->adr_d[adr_index].adr; + unsigned int sdw_version = SDW_VERSION(adr); + unsigned int link_id = SDW_DISCO_LINK_ID(adr); + unsigned int unique_id = SDW_UNIQUE_ID(adr); + unsigned int mfg_id = SDW_MFG_ID(adr); + unsigned int part_id = SDW_PART_ID(adr); + unsigned int class_id = SDW_CLASS_ID(adr); + + if (codec_info->codec_name) + return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); + else if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", + link_id, mfg_id, part_id, class_id); + else + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", + link_id, mfg_id, part_id, class_id, unique_id); + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, SND_SOC_SDW_UTILS); + +/* helper to get the link that the codec DAI is used */ +struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, + const char *dai_name) +{ + struct snd_soc_dai_link *dai_link; + int i; + int j; + + for_each_card_prelinks(card, i, dai_link) { + for (j = 0; j < dai_link->num_codecs; j++) { + /* Check each codec in a link */ + if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) + return dai_link; + } + } + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, SND_SOC_SDW_UTILS); + +void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + int ret; + int i, j; + + for (i = 0; i < ctx->codec_info_list_count; i++) { + for (j = 0; j < codec_info_list[i].dai_num; j++) { + codec_info_list[i].dais[j].rtd_init_done = false; + /* Check each dai in codec_info_lis to see if it is used in the link */ + if (!codec_info_list[i].dais[j].exit) + continue; + /* + * We don't need to call .exit function if there is no matched + * dai link found. + */ + dai_link = asoc_sdw_mc_find_codec_dai_used(card, + codec_info_list[i].dais[j].dai_name); + if (dai_link) { + /* Do the .exit function if the codec dai is used in the link */ + ret = codec_info_list[i].dais[j].exit(card, dai_link); + if (ret) + dev_warn(card->dev, + "codec exit failed %d\n", + ret); + break; + } + } + } +} +EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, SND_SOC_SDW_UTILS); + +int asoc_sdw_card_late_probe(struct snd_soc_card *card) +{ + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + if (codec_info_list[i].codec_card_late_probe) { + ret = codec_info_list[i].codec_card_late_probe(card); + if (ret < 0) + return ret; + } + } + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, SND_SOC_SDW_UTILS); + +void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + struct snd_soc_dai_link_component *cpus, int cpus_num, + struct snd_soc_dai_link_component *platform_component, + int num_platforms, struct snd_soc_dai_link_component *codecs, + int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops) +{ + dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); + dai_links->id = (*be_id)++; + dai_links->name = name; + dai_links->platforms = platform_component; + dai_links->num_platforms = num_platforms; + dai_links->no_pcm = 1; + dai_links->cpus = cpus; + dai_links->num_cpus = cpus_num; + dai_links->codecs = codecs; + dai_links->num_codecs = codecs_num; + dai_links->playback_only = playback && !capture; + dai_links->capture_only = !playback && capture; + dai_links->init = init; + dai_links->ops = ops; +} +EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, SND_SOC_SDW_UTILS); + +int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + const char *cpu_dai_name, const char *platform_comp_name, + int num_platforms, const char *codec_name, + const char *codec_dai_name, + int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops) +{ + struct snd_soc_dai_link_component *dlc; + + /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */ + dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); + if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name) + return -ENOMEM; + + dlc[0].dai_name = cpu_dai_name; + dlc[1].name = platform_comp_name; + + dlc[2].name = codec_name; + dlc[2].dai_name = codec_dai_name; + + asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, + &dlc[0], 1, &dlc[1], num_platforms, + &dlc[2], 1, init, ops); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS); + +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link; + int i; + + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + *num_devs += adr_link->num_adr; + + for (i = 0; i < adr_link->num_adr; i++) + *num_ends += adr_link->adr_d[i].num_endpoints; + } + + dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, SND_SOC_SDW_UTILS); + +struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new) +{ + while (dailinks->initialised) { + if (new->aggregated && dailinks->group_id == new->group_id) + return dailinks; + + dailinks++; + } + + INIT_LIST_HEAD(&dailinks->endpoints); + dailinks->group_id = new->group_id; + dailinks->initialised = true; + + return dailinks; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, SND_SOC_SDW_UTILS); + +int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dais, + struct asoc_sdw_endpoint *soc_ends, + int *num_devs) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link; + struct asoc_sdw_endpoint *soc_end = soc_ends; + int num_dais = 0; + int i, j; + int ret; + + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + int num_link_dailinks = 0; + + if (!is_power_of_2(adr_link->mask)) { + dev_err(dev, "link with multiple mask bits: 0x%x\n", + adr_link->mask); + return -EINVAL; + } + + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + struct asoc_sdw_codec_info *codec_info; + const char *codec_name; + + if (!adr_dev->name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_dev->adr); + return -EINVAL; + } + + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); + if (!codec_info) + return -EINVAL; + + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; + + codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); + if (!codec_name) + return -ENOMEM; + + dev_dbg(dev, "Adding prefix %s for %s\n", + adr_dev->name_prefix, codec_name); + + soc_end->name_prefix = adr_dev->name_prefix; + + if (codec_info->count_sidecar && codec_info->add_sidecar) { + ret = codec_info->count_sidecar(card, &num_dais, num_devs); + if (ret) + return ret; + + soc_end->include_sidecar = true; + } + + for (j = 0; j < adr_dev->num_endpoints; j++) { + const struct snd_soc_acpi_endpoint *adr_end; + const struct asoc_sdw_dai_info *dai_info; + struct asoc_sdw_dailink *soc_dai; + int stream; + + adr_end = &adr_dev->endpoints[j]; + dai_info = &codec_info->dais[adr_end->num]; + soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); + + if (dai_info->quirk && !(dai_info->quirk & ctx->mc_quirk)) + continue; + + dev_dbg(dev, + "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", + ffs(adr_link->mask) - 1, adr_dev->adr, + adr_end->num, dai_info->dai_type, + dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', + dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', + adr_end->aggregated ? "group" : "solo", + adr_end->group_id); + + if (adr_end->num >= codec_info->dai_num) { + dev_err(dev, + "%d is too many endpoints for codec: 0x%x\n", + adr_end->num, codec_info->part_id); + return -EINVAL; + } + + for_each_pcm_streams(stream) { + if (dai_info->direction[stream] && + dai_info->dailink[stream] < 0) { + dev_err(dev, + "Invalid dailink id %d for codec: 0x%x\n", + dai_info->dailink[stream], + codec_info->part_id); + return -EINVAL; + } + + if (dai_info->direction[stream]) { + num_dais += !soc_dai->num_devs[stream]; + soc_dai->num_devs[stream]++; + soc_dai->link_mask[stream] |= adr_link->mask; + } + } + + num_link_dailinks += !!list_empty(&soc_dai->endpoints); + list_add_tail(&soc_end->list, &soc_dai->endpoints); + + soc_end->link_mask = adr_link->mask; + soc_end->codec_name = codec_name; + soc_end->codec_info = codec_info; + soc_end->dai_info = dai_info; + soc_end++; + } + } + + ctx->append_dai_type |= (num_link_dailinks > 1); + } + + return num_dais; +} +EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, SND_SOC_SDW_UTILS); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SoundWire ASoC helpers"); diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 7bddfd5e38d6..426632996a0a 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -41,6 +41,7 @@ config SND_SOC_RCAR depends on COMMON_CLK depends on OF select SND_SIMPLE_CARD_UTILS + select SND_DMAENGINE_PCM select REGMAP_MMIO help This option enables R-Car SRU/SCU/SSIU/SSI sound support diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 087e379aa3bc..221ce91f1950 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -2107,7 +2107,7 @@ static struct platform_driver fsi_driver = { .of_match_table = fsi_of_match, }, .probe = fsi_probe, - .remove_new = fsi_remove, + .remove = fsi_remove, .id_table = fsi_id_table, }; diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index cc200f45826c..db618c09d1e0 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -334,7 +334,7 @@ static struct platform_driver hac_pcm_driver = { }, .probe = hac_soc_platform_probe, - .remove_new = hac_soc_platform_remove, + .remove = hac_soc_platform_remove, }; module_platform_driver(hac_pcm_driver); diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index afd69c6eb654..0f190abf00e7 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -262,7 +262,7 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, int id = rsnd_mod_id(src_mod); int shift = (id % 2) ? 16 : 0; - rsnd_mod_confirm_src(src_mod); + rsnd_mod_make_sure(src_mod, RSND_MOD_SRC); rsnd_adg_get_timesel_ratio(priv, io, in_rate, out_rate, @@ -291,7 +291,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) int shift = (id % 4) * 8; u32 mask = 0xFF << shift; - rsnd_mod_confirm_ssi(ssi_mod); + rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI); val = val << shift; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 63b3c8bf0fde..9784718a2b6f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -660,23 +660,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) return rsnd_rdai_get(priv, dai->id); } -/* - * rsnd_soc_dai functions - */ -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) -{ - struct snd_pcm_substream *substream = io->substream; - - /* - * this function should be called... - * - * - if rsnd_dai_pointer_update() returns true - * - without spin lock - */ - - snd_pcm_period_elapsed(substream); -} - static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, struct snd_pcm_substream *substream) { @@ -2104,7 +2087,7 @@ static struct platform_driver rsnd_driver = { .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, - .remove_new = rsnd_remove, + .remove = rsnd_remove, }; module_platform_driver(rsnd_driver); diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 7b499eee5080..2342bbb6fe92 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -7,6 +7,7 @@ #include #include +#include #include "rsnd.h" /* @@ -22,8 +23,6 @@ struct rsnd_dmaen { struct dma_chan *chan; - dma_cookie_t cookie; - unsigned int dma_len; }; struct rsnd_dmapp { @@ -66,20 +65,6 @@ static struct rsnd_mod mem = { /* * Audio DMAC */ -static void __rsnd_dmaen_complete(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - if (rsnd_io_is_working(io)) - rsnd_dai_period_elapsed(io); -} - -static void rsnd_dmaen_complete(void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); -} - static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) @@ -98,13 +83,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dmaengine_terminate_async(dmaen->chan); - - return 0; + return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP); } static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, @@ -120,7 +99,7 @@ static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, * Let's call it under prepare */ if (dmaen->chan) - dma_release_channel(dmaen->chan); + snd_dmaengine_pcm_close_release_chan(io->substream); dmaen->chan = NULL; @@ -153,7 +132,7 @@ static int rsnd_dmaen_prepare(struct rsnd_mod *mod, return -EIO; } - return 0; + return snd_dmaengine_pcm_open(io->substream, dmaen->chan); } static int rsnd_dmaen_start(struct rsnd_mod *mod, @@ -162,12 +141,9 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); - struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - int is_play = rsnd_io_is_play(io); int ret; /* @@ -195,7 +171,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, } } - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.direction = snd_pcm_substream_to_dma_direction(io->substream); cfg.src_addr = dma->src_addr; cfg.dst_addr = dma->dst_addr; cfg.src_addr_width = buswidth; @@ -209,32 +185,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, if (ret < 0) return ret; - desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), - is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return -EIO; - } - - desc->callback = rsnd_dmaen_complete; - desc->callback_param = rsnd_mod_get(dma); - - dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream); - - dmaen->cookie = dmaengine_submit(desc); - if (dmaen->cookie < 0) { - dev_err(dev, "dmaengine_submit() fail\n"); - return -EIO; - } - - dma_async_issue_pending(dmaen->chan); - - return 0; + return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START); } struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, @@ -307,19 +258,7 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct dma_tx_state state; - enum dma_status status; - unsigned int pos = 0; - - status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state); - if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { - if (state.residue > 0 && state.residue <= dmaen->dma_len) - pos = dmaen->dma_len - state.residue; - } - *pointer = bytes_to_frames(runtime, pos); + *pointer = snd_dmaengine_pcm_pointer(io->substream); return 0; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ff294aa2d640..3c164d8e3b16 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -576,7 +576,6 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, #define rsnd_rdai_width_get(rdai) \ rsnd_rdai_width_ctrl(rdai, 0) int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); @@ -871,15 +870,6 @@ void rsnd_cmd_remove(struct rsnd_priv *priv); int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); -#ifdef DEBUG -#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI) -#define rsnd_mod_confirm_src(msrc) rsnd_mod_make_sure(msrc, RSND_MOD_SRC) -#define rsnd_mod_confirm_dvc(mdvc) rsnd_mod_make_sure(mdvc, RSND_MOD_DVC) -#else -#define rsnd_mod_confirm_ssi(mssi) -#define rsnd_mod_confirm_src(msrc) -#define rsnd_mod_confirm_dvc(mdvc) -#endif /* * If you don't need interrupt status debug message, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 8d2a86383ae0..b3d4e8ae07ef 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -706,7 +706,7 @@ rsnd_ssi_interrupt_out: spin_unlock(&priv->lock); if (elapsed) - rsnd_dai_period_elapsed(io); + snd_pcm_period_elapsed(io->substream); if (stop) snd_pcm_stop_xrun(io->substream); diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index 9d103646973a..040ce0431fd2 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -52,6 +52,7 @@ #define SSIFCR_RIE BIT(2) #define SSIFCR_TFRST BIT(1) #define SSIFCR_RFRST BIT(0) +#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST) #define SSIFSR_TDC_MASK 0x3f #define SSIFSR_TDC_SHIFT 24 @@ -130,6 +131,14 @@ struct rz_ssi_priv { bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */ bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ bool dma_rt; + + /* Full duplex communication support */ + struct { + unsigned int rate; + unsigned int channels; + unsigned int sample_width; + unsigned int sample_bits; + } hw_params_cache; }; static void rz_ssi_dma_complete(void *data); @@ -208,6 +217,11 @@ static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, return ret; } +static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) +{ + return strm->substream && strm->running; +} + static void rz_ssi_stream_init(struct rz_ssi_stream *strm, struct snd_pcm_substream *substream) { @@ -303,59 +317,10 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, return 0; } -static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) -{ - bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); - u32 ssicr, ssifcr; - - ssicr = rz_ssi_reg_readl(ssi, SSICR); - ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF; - - /* FIFO interrupt thresholds */ - if (rz_ssi_is_dma_enabled(ssi)) - rz_ssi_reg_writel(ssi, SSISCR, 0); - else - rz_ssi_reg_writel(ssi, SSISCR, - SSISCR_TDES(strm->fifo_sample_size / 2 - 1) | - SSISCR_RDFS(0)); - - /* enable IRQ */ - if (is_play) { - ssicr |= SSICR_TUIEN | SSICR_TOIEN; - ssifcr |= SSIFCR_TIE | SSIFCR_RFRST; - } else { - ssicr |= SSICR_RUIEN | SSICR_ROIEN; - ssifcr |= SSIFCR_RIE | SSIFCR_TFRST; - } - - rz_ssi_reg_writel(ssi, SSICR, ssicr); - rz_ssi_reg_writel(ssi, SSIFCR, ssifcr); - - /* Clear all error flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, - (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ), 0); - - strm->running = 1; - ssicr |= is_play ? SSICR_TEN : SSICR_REN; - rz_ssi_reg_writel(ssi, SSICR, ssicr); - - return 0; -} - -static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) { int timeout; - strm->running = 0; - - /* Disable TX/RX */ - rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); - - /* Cancel all remaining DMA transactions */ - if (rz_ssi_is_dma_enabled(ssi)) - dmaengine_terminate_async(strm->dma_ch); - /* Disable irqs */ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | SSICR_RUIEN | SSICR_ROIEN, 0); @@ -380,6 +345,82 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) /* Hold FIFOs in reset */ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_TFRST | SSIFCR_RFRST); +} + +static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); + bool is_full_duplex; + u32 ssicr, ssifcr; + + is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture); + ssicr = rz_ssi_reg_readl(ssi, SSICR); + ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); + if (!is_full_duplex) { + ssifcr &= ~0xF; + } else { + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + rz_ssi_set_idle(ssi); + ssifcr &= ~SSIFCR_FIFO_RST; + } + + /* FIFO interrupt thresholds */ + if (rz_ssi_is_dma_enabled(ssi)) + rz_ssi_reg_writel(ssi, SSISCR, 0); + else + rz_ssi_reg_writel(ssi, SSISCR, + SSISCR_TDES(strm->fifo_sample_size / 2 - 1) | + SSISCR_RDFS(0)); + + /* enable IRQ */ + if (is_play) { + ssicr |= SSICR_TUIEN | SSICR_TOIEN; + ssifcr |= SSIFCR_TIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_RFRST; + } else { + ssicr |= SSICR_RUIEN | SSICR_ROIEN; + ssifcr |= SSIFCR_RIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_TFRST; + } + + rz_ssi_reg_writel(ssi, SSICR, ssicr); + rz_ssi_reg_writel(ssi, SSIFCR, ssifcr); + + /* Clear all error flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, + (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | + SSISR_RUIRQ), 0); + + strm->running = 1; + if (is_full_duplex) + ssicr |= SSICR_TEN | SSICR_REN; + else + ssicr |= is_play ? SSICR_TEN : SSICR_REN; + + rz_ssi_reg_writel(ssi, SSICR, ssicr); + + return 0; +} + +static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + strm->running = 0; + + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) + return 0; + + /* Disable TX/RX */ + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + + /* Cancel all remaining DMA transactions */ + if (rz_ssi_is_dma_enabled(ssi)) + dmaengine_terminate_async(strm->dma_ch); + + rz_ssi_set_idle(ssi); return 0; } @@ -512,66 +553,90 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) static irqreturn_t rz_ssi_interrupt(int irq, void *data) { - struct rz_ssi_stream *strm = NULL; + struct rz_ssi_stream *strm_playback = NULL; + struct rz_ssi_stream *strm_capture = NULL; struct rz_ssi_priv *ssi = data; u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); if (ssi->playback.substream) - strm = &ssi->playback; - else if (ssi->capture.substream) - strm = &ssi->capture; - else + strm_playback = &ssi->playback; + if (ssi->capture.substream) + strm_capture = &ssi->capture; + + if (!strm_playback && !strm_capture) return IRQ_HANDLED; /* Left over TX/RX interrupt */ if (irq == ssi->irq_int) { /* error or idle */ - if (ssisr & SSISR_TUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_TOIRQ) - strm->oerr_num++; - if (ssisr & SSISR_RUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_ROIRQ) - strm->oerr_num++; + bool is_stopped = false; + int i, count; - if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ | - SSISR_ROIRQ)) { - /* Error handling */ - /* You must reset (stop/restart) after each interrupt */ - rz_ssi_stop(ssi, strm); + if (rz_ssi_is_dma_enabled(ssi)) + count = 4; + else + count = 1; - /* Clear all flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | - SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ, 0); + if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ)) + is_stopped = true; - /* Add/remove more data */ - strm->transfer(ssi, strm); + if (ssi->capture.substream && is_stopped) { + if (ssisr & SSISR_RUIRQ) + strm_capture->uerr_num++; + if (ssisr & SSISR_ROIRQ) + strm_capture->oerr_num++; - /* Resume */ - rz_ssi_start(ssi, strm); + rz_ssi_stop(ssi, strm_capture); } + + if (ssi->playback.substream && is_stopped) { + if (ssisr & SSISR_TUIRQ) + strm_playback->uerr_num++; + if (ssisr & SSISR_TOIRQ) + strm_playback->oerr_num++; + + rz_ssi_stop(ssi, strm_playback); + } + + /* Clear all flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ | + SSISR_ROIRQ | SSISR_RUIRQ, 0); + + /* Add/remove more data */ + if (ssi->capture.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_capture->transfer(ssi, strm_capture); + } + + if (ssi->playback.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_playback->transfer(ssi, strm_playback); + } + + /* Resume */ + if (ssi->playback.substream && is_stopped) + rz_ssi_start(ssi, &ssi->playback); + if (ssi->capture.substream && is_stopped) + rz_ssi_start(ssi, &ssi->capture); } - if (!strm->running) + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) return IRQ_HANDLED; /* tx data empty */ - if (irq == ssi->irq_tx) - strm->transfer(ssi, &ssi->playback); + if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback)) + strm_playback->transfer(ssi, &ssi->playback); /* rx data full */ - if (irq == ssi->irq_rx) { - strm->transfer(ssi, &ssi->capture); + if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) { + strm_capture->transfer(ssi, &ssi->capture); rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); } if (irq == ssi->irq_rt) { - struct snd_pcm_substream *substream = strm->substream; - - if (rz_ssi_stream_is_play(ssi, substream)) { - strm->transfer(ssi, &ssi->playback); + if (ssi->playback.substream) { + strm_playback->transfer(ssi, &ssi->playback); } else { - strm->transfer(ssi, &ssi->capture); + strm_capture->transfer(ssi, &ssi->capture); rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); } } @@ -731,9 +796,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Soft Reset */ - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); - rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); - udelay(5); + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) { + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); + rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); + udelay(5); + } rz_ssi_stream_init(strm, substream); @@ -824,14 +892,41 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + if (ssi->hw_params_cache.rate != rate || + ssi->hw_params_cache.channels != channels || + ssi->hw_params_cache.sample_width != sample_width || + ssi->hw_params_cache.sample_bits != sample_bits) + return false; + + return true; +} + +static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + ssi->hw_params_cache.rate = rate; + ssi->hw_params_cache.channels = channels; + ssi->hw_params_cache.sample_width = sample_width; + ssi->hw_params_cache.sample_bits = sample_bits; +} + static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); unsigned int sample_bits = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); if (sample_bits != 16) { dev_err(ssi->dev, "Unsupported sample width: %d\n", @@ -845,8 +940,20 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return rz_ssi_clk_setup(ssi, params_rate(params), - params_channels(params)); + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) { + if (rz_ssi_is_valid_hw_params(ssi, rate, channels, + strm->sample_width, sample_bits)) + return 0; + + dev_err(ssi->dev, "Full duplex needs same HW params\n"); + return -EINVAL; + } + + rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, + sample_bits); + + return rz_ssi_clk_setup(ssi, rate, channels); } static const struct snd_soc_dai_ops rz_ssi_dai_ops = { @@ -1097,7 +1204,7 @@ static struct platform_driver rz_ssi_driver = { .of_match_table = rz_ssi_of_match, }, .probe = rz_ssi_probe, - .remove_new = rz_ssi_remove, + .remove = rz_ssi_remove, }; module_platform_driver(rz_ssi_driver); diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index d0b5c543fd2f..7e771a164a80 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -788,7 +788,7 @@ static struct platform_driver siu_driver = { .name = "siu-pcm-audio", }, .probe = siu_probe, - .remove_new = siu_remove, + .remove = siu_remove, }; module_platform_driver(siu_driver); diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 4e4fe29ade50..079e4ff5a14e 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -168,7 +168,7 @@ static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) * it. The caller is responsible to either call device_add(&ac97->dev) to * register the device, or to call put_device(&ac97->dev) to free the device. * - * Returns: A snd_ac97 device or a PTR_ERR in case of an error. + * Returns: A snd_ac97 device or an ERR_PTR in case of an error. */ struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component) { @@ -207,7 +207,7 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_component); * the device and check if it matches the expected ID. If it doesn't match an * error will be returned and device will not be registered. * - * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success. + * Returns: An ERR_PTR on failure or a valid snd_ac97 struct on success. */ struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, unsigned int id, unsigned int id_mask) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 724fe1f033b5..20248a29d167 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -326,8 +326,8 @@ static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, } /* see for_each_rtd_components */ - rtd->components[rtd->num_components] = component; - rtd->num_components++; + rtd->num_components++; // increment flex array count at first + rtd->components[rtd->num_components - 1] = component; return 0; } @@ -494,7 +494,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_component *component; struct device *dev; int ret; int stream; @@ -521,10 +520,10 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( * for rtd */ rtd = devm_kzalloc(dev, - sizeof(*rtd) + - sizeof(component) * (dai_link->num_cpus + - dai_link->num_codecs + - dai_link->num_platforms), + struct_size(rtd, components, + dai_link->num_cpus + + dai_link->num_codecs + + dai_link->num_platforms), GFP_KERNEL); if (!rtd) { device_unregister(dev); @@ -3372,10 +3371,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np, * SND_SOC_DAIFMT_INV_MASK area */ snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix); - bit = !!of_get_property(np, prop, NULL); + bit = of_property_read_bool(np, prop); snprintf(prop, sizeof(prop), "%sframe-inversion", prefix); - frame = !!of_get_property(np, prop, NULL); + frame = of_property_read_bool(np, prop); switch ((bit << 4) + frame) { case 0x11: @@ -3412,12 +3411,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, * check "[prefix]frame-master" */ snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); - bit = !!of_get_property(np, prop, NULL); + bit = of_property_read_bool(np, prop); if (bit && bitclkmaster) *bitclkmaster = of_parse_phandle(np, prop, 0); snprintf(prop, sizeof(prop), "%sframe-master", prefix); - frame = !!of_get_property(np, prop, NULL); + frame = of_property_read_bool(np, prop); if (frame && framemaster) *framemaster = of_parse_phandle(np, prop, 0); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 9e47053419c1..4e08892d24c6 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -479,44 +479,6 @@ bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir) return stream->channels_min; } -/* - * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs - */ -void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link) -{ - bool supported[SNDRV_PCM_STREAM_LAST + 1]; - int direction; - - for_each_pcm_streams(direction) { - struct snd_soc_dai_link_component *cpu; - struct snd_soc_dai_link_component *codec; - struct snd_soc_dai *dai; - bool supported_cpu = false; - bool supported_codec = false; - int i; - - for_each_link_cpus(dai_link, i, cpu) { - dai = snd_soc_find_dai_with_mutex(cpu); - if (dai && snd_soc_dai_stream_valid(dai, direction)) { - supported_cpu = true; - break; - } - } - for_each_link_codecs(dai_link, i, codec) { - dai = snd_soc_find_dai_with_mutex(codec); - if (dai && snd_soc_dai_stream_valid(dai, direction)) { - supported_codec = true; - break; - } - } - supported[direction] = supported_cpu && supported_codec; - } - - dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK]; - dai_link->dpcm_capture = supported[SNDRV_PCM_STREAM_CAPTURE]; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities); - void snd_soc_dai_action(struct snd_soc_dai *dai, int stream, int action) { @@ -685,26 +647,6 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, return ret; } -int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *dai; - int i, ret; - - for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->ops && - dai->driver->ops->bespoke_trigger) { - ret = dai->driver->ops->bespoke_trigger(substream, - cmd, dai); - if (ret < 0) - return soc_dai_ret(dai, ret); - } - } - - return 0; -} - void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream, snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32c556c62557..9330f1a3f758 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2254,7 +2254,7 @@ static const struct file_operations dapm_bias_fops = { void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent) { - if (!parent || IS_ERR(parent)) + if (IS_ERR_OR_NULL(parent)) return; dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); @@ -2751,8 +2751,7 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, if (!w) return 0; - dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, - dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, snd_pcm_direction_name(dir)); snd_soc_dapm_widget_for_each_sink_path(w, p) { ret = dapm_update_dai_chan(p, p->sink, channels); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index bad823718ae4..7a59121fc323 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -49,23 +49,104 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, return ret; } -static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd, - int stream) +/* is the current PCM operation for this FE ? */ +#if 0 +static int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) { - snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream)); + if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) + return 1; + return 0; +} +#endif + +/* is the current PCM operation for this BE ? */ +static int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || + ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) && + be->dpcm[stream].runtime_update)) + return 1; + return 0; } -#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \ - snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags) - -static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd, - int stream) +static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, + int stream, + const enum snd_soc_dpcm_state *states, + int num_states) { - snd_pcm_stream_unlock_irq(snd_soc_dpcm_get_substream(rtd, stream)); + struct snd_soc_dpcm *dpcm; + int state; + int ret = 1; + int i; + + for_each_dpcm_fe(be, stream, dpcm) { + + if (dpcm->fe == fe) + continue; + + state = dpcm->fe->dpcm[stream].state; + for (i = 0; i < num_states; i++) { + if (state == states[i]) { + ret = 0; + break; + } + } + } + + /* it's safe to do this BE DAI */ + return ret; } -#define snd_soc_dpcm_stream_unlock_irqrestore(rtd, stream, flags) \ - snd_pcm_stream_unlock_irqrestore(snd_soc_dpcm_get_substream(rtd, stream), flags) +/* + * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE + * are not running, paused or suspended for the specified stream direction. + */ +static int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + const enum snd_soc_dpcm_state state[] = { + SND_SOC_DPCM_STATE_START, + SND_SOC_DPCM_STATE_PAUSED, + SND_SOC_DPCM_STATE_SUSPEND, + }; + + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); +} + +/* + * We can only change hw params a BE DAI if any of it's FE are not prepared, + * running, paused or suspended for the specified stream direction. + */ +static int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + const enum snd_soc_dpcm_state state[] = { + SND_SOC_DPCM_STATE_START, + SND_SOC_DPCM_STATE_PAUSED, + SND_SOC_DPCM_STATE_SUSPEND, + SND_SOC_DPCM_STATE_PREPARE, + }; + + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); +} + +/* + * We can only prepare a BE DAI if any of it's FE are not prepared, + * running or paused for the specified stream direction. + */ +static int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + const enum snd_soc_dpcm_state state[] = { + SND_SOC_DPCM_STATE_START, + SND_SOC_DPCM_STATE_PAUSED, + SND_SOC_DPCM_STATE_PREPARE, + }; + + return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); +} #define DPCM_MAX_BE_USERS 8 @@ -222,7 +303,7 @@ static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream) char *name; name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name, - stream ? "capture" : "playback"); + snd_pcm_direction_name(stream)); if (name) { dpcm->debugfs_state = debugfs_create_dir( name, dpcm->fe->debugfs_dpcm_root); @@ -260,14 +341,14 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream); - snd_soc_dpcm_stream_lock_irq(fe, stream); + snd_pcm_stream_lock_irq(substream); if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) { dpcm_fe_dai_do_trigger(substream, fe->dpcm[stream].trigger_pending - 1); fe->dpcm[stream].trigger_pending = 0; } fe->dpcm[stream].runtime_update = state; - snd_soc_dpcm_stream_unlock_irq(fe, stream); + snd_pcm_stream_unlock_irq(substream); } static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be, @@ -1272,13 +1353,13 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, dpcm->be = be; dpcm->fe = fe; dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; - snd_soc_dpcm_stream_lock_irq(fe, stream); + snd_pcm_stream_lock_irq(fe_substream); list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); - snd_soc_dpcm_stream_unlock_irq(fe, stream); + snd_pcm_stream_unlock_irq(fe_substream); dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", - stream ? "capture" : "playback", fe->dai_link->name, + snd_pcm_direction_name(stream), fe->dai_link->name, stream ? "<-" : "->", be->dai_link->name); dpcm_create_debugfs_state(dpcm, stream); @@ -1306,7 +1387,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, continue; dev_dbg(fe->dev, "reparent %s path %s %s %s\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), dpcm->fe->dai_link->name, stream ? "<-" : "->", dpcm->be->dai_link->name); @@ -1320,21 +1401,22 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; + struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream); LIST_HEAD(deleted_dpcms); snd_soc_dpcm_mutex_assert_held(fe); - snd_soc_dpcm_stream_lock_irq(fe, stream); + snd_pcm_stream_lock_irq(substream); for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), dpcm->be->dai_link->name); if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) continue; dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n", - stream ? "capture" : "playback", fe->dai_link->name, + snd_pcm_direction_name(stream), fe->dai_link->name, stream ? "<-" : "->", dpcm->be->dai_link->name); /* BEs still alive need new FE */ @@ -1343,7 +1425,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) list_del(&dpcm->list_be); list_move(&dpcm->list_fe, &deleted_dpcms); } - snd_soc_dpcm_stream_unlock_irq(fe, stream); + snd_pcm_stream_unlock_irq(substream); while (!list_empty(&deleted_dpcms)) { dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm, @@ -1441,10 +1523,10 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, if (paths > 0) dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, - stream ? "capture" : "playback"); + snd_pcm_direction_name(stream)); else if (paths == 0) dev_dbg(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, - stream ? "capture" : "playback"); + snd_pcm_direction_name(stream)); return paths; } @@ -1487,7 +1569,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), dpcm->be->dai_link->name, fe->dai_link->name); dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE); @@ -1605,7 +1687,7 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, if (be->dpcm[stream].users == 0) { dev_err(be->dev, "ASoC: no users %s at close - state %d\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), be->dpcm[stream].state); continue; } @@ -1645,7 +1727,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) if (!be_substream) { dev_err(be->dev, "ASoC: no backend %s stream\n", - stream ? "capture" : "playback"); + snd_pcm_direction_name(stream)); continue; } @@ -1656,7 +1738,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) /* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { dev_err(be->dev, "ASoC: too many users %s at open %d\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), be->dpcm[stream].state); continue; } @@ -1669,7 +1751,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) continue; dev_dbg(be->dev, "ASoC: open %s BE %s\n", - stream ? "capture" : "playback", be->dai_link->name); + snd_pcm_direction_name(stream), be->dai_link->name); be_substream->runtime = fe_substream->runtime; err = __soc_pcm_open(be, be_substream); @@ -1677,7 +1759,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) dev_err(be->dev, "ASoC: no users %s at unwind %d\n", - stream ? "capture" : "playback", + snd_pcm_direction_name(stream), be->dpcm[stream].state); be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; @@ -2155,7 +2237,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, be = dpcm->be; be_substream = snd_soc_dpcm_get_substream(be, stream); - snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags); + snd_pcm_stream_lock_irqsave_nested(be_substream, flags); /* is this op for this BE ? */ if (!snd_soc_dpcm_be_can_update(fe, be, stream)) @@ -2302,7 +2384,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, break; } next: - snd_soc_dpcm_stream_unlock_irqrestore(be, stream, flags); + snd_pcm_stream_unlock_irqrestore(be_substream, flags); if (ret) break; } @@ -2388,14 +2470,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) break; } break; - case SND_SOC_DPCM_TRIGGER_BESPOKE: - /* bespoke trigger() - handles both FE and BEs */ - - dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd); - break; default: dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, fe->dai_link->name); @@ -2525,26 +2599,12 @@ out: static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) { - struct snd_pcm_substream *substream = - snd_soc_dpcm_get_substream(fe, stream); - enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int err; dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n", - stream ? "capture" : "playback", fe->dai_link->name); + snd_pcm_direction_name(stream), fe->dai_link->name); - if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { - /* call bespoke trigger - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n", - fe->dai_link->name); - - err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); - } else { - dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n", - fe->dai_link->name); - - err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); - } + err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); dpcm_be_dai_hw_free(fe, stream); @@ -2558,14 +2618,11 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) { - struct snd_pcm_substream *substream = - snd_soc_dpcm_get_substream(fe, stream); struct snd_soc_dpcm *dpcm; - enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret = 0; dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", - stream ? "capture" : "playback", fe->dai_link->name); + snd_pcm_direction_name(stream), fe->dai_link->name); /* Only start the BE if the FE is ready */ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || @@ -2605,23 +2662,9 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) return 0; - if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { - /* call trigger on the frontend - FE takes care of all BE triggers */ - dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n", - fe->dai_link->name); - - ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); - if (ret < 0) - goto hw_free; - } else { - dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n", - fe->dai_link->name); - - ret = dpcm_be_dai_trigger(fe, stream, - SNDRV_PCM_TRIGGER_START); - if (ret < 0) - goto hw_free; - } + ret = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) + goto hw_free; return 0; @@ -2795,6 +2838,7 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai; + struct snd_soc_dai_link_ch_map *ch_maps; int has_playback = 0; int has_capture = 0; int i; @@ -2805,43 +2849,51 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, } if (dai_link->dynamic || dai_link->no_pcm) { - int stream; - if (dai_link->dpcm_playback) { - stream = SNDRV_PCM_STREAM_PLAYBACK; + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - if (snd_soc_dai_stream_valid(cpu_dai, stream)) { - has_playback = 1; - break; - } - } - if (!has_playback) { - dev_err(rtd->card->dev, - "No CPU DAIs support playback for stream %s\n", - dai_link->stream_name); - return -EINVAL; - } + if (snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) + has_playback = 1; + + if (snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) + has_capture = 1; } - if (dai_link->dpcm_capture) { - stream = SNDRV_PCM_STREAM_CAPTURE; - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - if (snd_soc_dai_stream_valid(cpu_dai, stream)) { - has_capture = 1; - break; - } + /* + * REMOVE ME + * + * dpcm_xxx flag will be removed soon, Indicates warning if dpcm_xxx flag was used + * as availability limitation + */ + if (has_playback && has_capture) { + if ( dai_link->dpcm_playback && + !dai_link->dpcm_capture && + !dai_link->playback_only) { + dev_warn(rtd->card->dev, + "both playback/capture are available," + " but not using playback_only flag (%s)\n", + dai_link->stream_name); + dev_warn(rtd->card->dev, + "dpcm_playback/capture are no longer needed," + " please use playback/capture_only instead\n"); + has_capture = 0; } - if (!has_capture) { - dev_err(rtd->card->dev, - "No CPU DAIs support capture for stream %s\n", - dai_link->stream_name); - return -EINVAL; + if (!dai_link->dpcm_playback && + dai_link->dpcm_capture && + !dai_link->capture_only) { + dev_warn(rtd->card->dev, + "both playback/capture are available," + " but not using capture_only flag (%s)\n", + dai_link->stream_name); + dev_warn(rtd->card->dev, + "dpcm_playback/capture are no longer needed," + " please use playback/capture_only instead\n"); + has_playback = 0; } } } else { - struct snd_soc_dai_link_ch_map *ch_maps; struct snd_soc_dai *codec_dai; /* Adapt stream for codec2codec links */ @@ -3016,27 +3068,6 @@ out: return ret; } -/* is the current PCM operation for this FE ? */ -int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) -{ - if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) - return 1; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update); - -/* is the current PCM operation for this BE ? */ -int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream) -{ - if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || - ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) && - be->dpcm[stream].runtime_update)) - return 1; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update); - /* get the substream for this BE */ struct snd_pcm_substream * snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream) @@ -3044,84 +3075,3 @@ struct snd_pcm_substream * return be->pcm->streams[stream].substream; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream); - -static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, - int stream, - const enum snd_soc_dpcm_state *states, - int num_states) -{ - struct snd_soc_dpcm *dpcm; - int state; - int ret = 1; - int i; - - for_each_dpcm_fe(be, stream, dpcm) { - - if (dpcm->fe == fe) - continue; - - state = dpcm->fe->dpcm[stream].state; - for (i = 0; i < num_states; i++) { - if (state == states[i]) { - ret = 0; - break; - } - } - } - - /* it's safe to do this BE DAI */ - return ret; -} - -/* - * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE - * are not running, paused or suspended for the specified stream direction. - */ -int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream) -{ - const enum snd_soc_dpcm_state state[] = { - SND_SOC_DPCM_STATE_START, - SND_SOC_DPCM_STATE_PAUSED, - SND_SOC_DPCM_STATE_SUSPEND, - }; - - return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); -} -EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); - -/* - * We can only change hw params a BE DAI if any of it's FE are not prepared, - * running, paused or suspended for the specified stream direction. - */ -int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream) -{ - const enum snd_soc_dpcm_state state[] = { - SND_SOC_DPCM_STATE_START, - SND_SOC_DPCM_STATE_PAUSED, - SND_SOC_DPCM_STATE_SUSPEND, - SND_SOC_DPCM_STATE_PREPARE, - }; - - return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); -} -EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); - -/* - * We can only prepare a BE DAI if any of it's FE are not prepared, - * running or paused for the specified stream direction. - */ -int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe, - struct snd_soc_pcm_runtime *be, int stream) -{ - const enum snd_soc_dpcm_state state[] = { - SND_SOC_DPCM_STATE_START, - SND_SOC_DPCM_STATE_PAUSED, - SND_SOC_DPCM_STATE_PREPARE, - }; - - return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state)); -} -EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_prepared); diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c index d62a02ec5896..a2b08568f4e8 100644 --- a/sound/soc/soc-topology-test.c +++ b/sound/soc/soc-topology-test.c @@ -244,12 +244,12 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) kunit_comp->kunit = test; kunit_comp->expect = -EINVAL; /* expect failure */ - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -286,12 +286,12 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test) kunit_comp->kunit = test; kunit_comp->expect = 0; /* expect success */ - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -348,12 +348,12 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) kunit_comp->kunit = test; kunit_comp->expect = -EINVAL; /* expect failure */ - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -396,12 +396,12 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test) kunit_comp->fw.data = (u8 *)data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -451,12 +451,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test) kunit_comp->fw.data = (u8 *)data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -506,12 +506,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test) kunit_comp->fw.data = (u8 *)data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -561,12 +561,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test) kunit_comp->fw.data = (u8 *)data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -617,12 +617,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes kunit_comp->fw.data = (u8 *)data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -665,12 +665,12 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test) kunit_comp->fw.data = data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -715,12 +715,12 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test) kunit_comp->fw.data = data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_register_card(&kunit_comp->card); @@ -767,12 +767,12 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test) kunit_comp->fw.data = data; kunit_comp->fw.size = size; - kunit_comp->card.dev = test_dev, - kunit_comp->card.name = "kunit-card", - kunit_comp->card.owner = THIS_MODULE, - kunit_comp->card.dai_link = kunit_dai_links, - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links), - kunit_comp->card.fully_routed = true, + kunit_comp->card.dev = test_dev; + kunit_comp->card.name = "kunit-card"; + kunit_comp->card.owner = THIS_MODULE; + kunit_comp->card.dai_link = kunit_dai_links; + kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); + kunit_comp->card.fully_routed = true; /* run test */ ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index af5d42b57be7..af3158cdc8d5 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1894,7 +1894,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; ret = set_stream_info(tplg, stream, caps); if (ret < 0) - goto err; + return ret; } if (d->capture) { @@ -1902,7 +1902,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE]; ret = set_stream_info(tplg, stream, caps); if (ret < 0) - goto err; + return ret; } if (d->flag_mask) @@ -1914,13 +1914,10 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai); if (ret < 0) { dev_err(tplg->dev, "ASoC: DAI loading failed\n"); - goto err; + return ret; } return 0; - -err: - return ret; } /* load physical DAI elements */ diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 2729c6eb3feb..f4cafe801017 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -23,6 +23,7 @@ config SND_SOC_SOF_AMD_COMMON select SND_AMD_ACP_CONFIG select SND_SOC_SOF_XTENSA select SND_SOC_SOF_ACP_PROBES + select SND_SOC_ACPI_AMD_MATCH select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by @@ -87,4 +88,14 @@ config SND_SOC_SOF_AMD_ACP63 AMD ACP6.3 version based platforms. Say Y if you want to enable SOF on ACP6.3 based platform. If unsure select "N". + +config SND_SOC_SOF_AMD_ACP70 + tristate "SOF support for ACP7.0 platform" + depends on SND_SOC_SOF_PCI + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support on + AMD ACP7.0 version based platforms. + Say Y if you want to enable SOF on ACP7.0 based platform. + endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 63fe0d55fd0e..6ae39fd5a836 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -2,7 +2,7 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023, 2024 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-y := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) += acp-probes.o @@ -10,9 +10,11 @@ snd-sof-amd-renoir-y := pci-rn.o renoir.o snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o snd-sof-amd-acp63-y := pci-acp63.o acp63.o +snd-sof-amd-acp70-y := pci-acp70.o acp70.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o +obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 81bb93e98358..dbcaac84cb73 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -153,6 +153,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * break; } if (mach && mach->link_mask) { + mach->mach_params.subsystem_rev = acp_data->pci_rev; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); @@ -173,6 +174,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; + struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; const struct sof_dev_desc *desc = sof_pdata->desc; struct snd_soc_acpi_mach *mach = NULL; @@ -186,6 +188,7 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) } } + mach->mach_params.subsystem_rev = acp_data->pci_rev; sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->fw_filename = mach->fw_filename; diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 072b703f9b3f..ecdcae07ace7 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023, 2024 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey */ @@ -23,6 +23,17 @@ #define ACP_DMA_CH_STS 0xE8 #define ACP_DMA_CH_GROUP 0xEC #define ACP_DMA_CH_RST_STS 0xF0 +#define ACP70_DMA_CNTL_0 0x00 +#define ACP70_DMA_DSCR_STRT_IDX_0 0x28 +#define ACP70_DMA_DSCR_CNT_0 0x50 +#define ACP70_DMA_PRIO_0 0x78 +#define ACP70_DMA_CUR_DSCR_0 0xA0 +#define ACP70_DMA_ERR_STS_0 0xF0 +#define ACP70_DMA_DESC_BASE_ADDR 0x118 +#define ACP70_DMA_DESC_MAX_NUM_DSCR 0x11C +#define ACP70_DMA_CH_STS 0x120 +#define ACP70_DMA_CH_GROUP 0x124 +#define ACP70_DMA_CH_RST_STS 0x128 /* Registers from ACP_DSP_0 block */ #define ACP_DSP0_RUNSTALL 0x414 @@ -56,11 +67,13 @@ #define ACP3X_PGFSM_BASE 0x141C #define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 +#define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 #define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C +#define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 @@ -69,22 +82,30 @@ #define ACP6X_EXTERNAL_INTR_CNTL 0x1A04 #define ACP6X_EXT_INTR_STAT 0x1A0C #define ACP6X_EXT_INTR_STAT1 0x1A10 +#define ACP70_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB +#define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL +#define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT +#define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1 #define ACP3X_DSP_SW_INTR_BASE 0x1814 #define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 +#define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 #define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP3X_ERROR_STATUS 0x18C4 #define ACP6X_ERROR_STATUS 0x1A4C +#define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS #define ACP3X_AXI2DAGB_SEM_0 0x1880 #define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 +#define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0 /* ACP common registers to report errors related to I2S & SoundWire interfaces */ #define ACP3X_SW_I2S_ERROR_REASON 0x18C8 #define ACP6X_SW0_I2S_ERROR_REASON 0x18B4 +#define ACP7X_SW0_I2S_ERROR_REASON ACP6X_SW0_I2S_ERROR_REASON #define ACP_SW1_I2S_ERROR_REASON 0x1A50 /* Registers from ACP_SHA block */ @@ -101,6 +122,7 @@ #define ACP_SCRATCH_REG_0 0x10000 #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 +#define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL /* Cache window registers */ #define ACP_DSP0_CACHE_OFFSET0 0x0420 diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 2d5e58846499..19f10dd77e4b 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -219,7 +219,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) dev_err(sdev->dev, "acp dma transfer status: %d\n", ret); } - if (desc->rev > 3) { + if (adata->pci_rev > ACP_RN_PCI_ID) { /* Cache Window enable */ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_OFFSET0, desc->sram_pte_offset); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_SIZE0, SRAM1_SIZE | BIT(31)); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 85b58c8ccd0d..d579c3849392 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -64,13 +64,24 @@ static void init_dma_descriptor(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; unsigned int addr; + unsigned int acp_dma_desc_base_addr, acp_dma_desc_max_num_dscr; addr = desc->sram_pte_offset + sdev->debug_box.offset + offsetof(struct scratch_reg_conf, dma_desc); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT); + switch (acp_data->pci_rev) { + case ACP70_PCI_ID: + acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR; + acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR; + break; + default: + acp_dma_desc_base_addr = ACP_DMA_DESC_BASE_ADDR; + acp_dma_desc_max_num_dscr = ACP_DMA_DESC_MAX_NUM_DSCR; + } + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_desc_base_addr, addr); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_desc_max_num_dscr, ACP_MAX_DESC_CNT); } static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short idx, @@ -92,29 +103,51 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, unsigned int idx, unsigned int dscr_count) { struct snd_sof_dev *sdev = adata->dev; + struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int val, status; + unsigned int acp_dma_cntl_0, acp_dma_ch_rst_sts, acp_dma_dscr_err_sts_0; + unsigned int acp_dma_dscr_cnt_0, acp_dma_prio_0, acp_dma_dscr_strt_idx_0; int ret; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), + switch (acp_data->pci_rev) { + case ACP70_PCI_ID: + acp_dma_cntl_0 = ACP70_DMA_CNTL_0; + acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS; + acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0; + acp_dma_dscr_cnt_0 = ACP70_DMA_DSCR_CNT_0; + acp_dma_prio_0 = ACP70_DMA_PRIO_0; + acp_dma_dscr_strt_idx_0 = ACP70_DMA_DSCR_STRT_IDX_0; + break; + default: + acp_dma_cntl_0 = ACP_DMA_CNTL_0; + acp_dma_ch_rst_sts = ACP_DMA_CH_RST_STS; + acp_dma_dscr_err_sts_0 = ACP_DMA_ERR_STS_0; + acp_dma_dscr_cnt_0 = ACP_DMA_DSCR_CNT_0; + acp_dma_prio_0 = ACP_DMA_PRIO_0; + acp_dma_dscr_strt_idx_0 = ACP_DMA_DSCR_STRT_IDX_0; + } + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_cntl_0 + ch * sizeof(u32), ACP_DMA_CH_RST | ACP_DMA_CH_GRACEFUL_RST_EN); - ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_RST_STS, val, + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, acp_dma_ch_rst_sts, val, val & (1 << ch), ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); if (ret < 0) { status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->acp_error_stat); - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_ERR_STS_0 + ch * sizeof(u32)); + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, acp_dma_dscr_err_sts_0 + + ch * sizeof(u32)); dev_err(sdev->dev, "ACP_DMA_ERR_STS :0x%x ACP_ERROR_STATUS :0x%x\n", val, status); return ret; } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, (ACP_DMA_CNTL_0 + ch * sizeof(u32)), 0); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_CNT_0 + ch * sizeof(u32), dscr_count); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_STRT_IDX_0 + ch * sizeof(u32), idx); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_PRIO_0 + ch * sizeof(u32), 0); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), ACP_DMA_CH_RUN); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, (acp_dma_cntl_0 + ch * sizeof(u32)), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_dscr_cnt_0 + ch * sizeof(u32), dscr_count); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_dscr_strt_idx_0 + ch * sizeof(u32), idx); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_prio_0 + ch * sizeof(u32), 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_cntl_0 + ch * sizeof(u32), ACP_DMA_CH_RUN); return ret; } @@ -236,7 +269,6 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, unsigned int image_length) { struct snd_sof_dev *sdev = adata->dev; - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); unsigned int tx_count, fw_qualifier, val; int ret; @@ -265,8 +297,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); - /* psp_send_cmd only required for vangogh platform (rev - 5) */ - if (desc->rev == 5 && !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) { + /* psp_send_cmd only required for vangogh platform */ + if (adata->pci_rev == ACP_VANGOGH_PCI_ID && + !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) { /* Modify IRAM and DRAM size */ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2); if (ret) @@ -285,8 +318,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, return ret; } - /* psp_send_cmd only required for renoir platform (rev - 3) */ - if (desc->rev == 3) { + /* psp_send_cmd only required for renoir platform*/ + if (adata->pci_rev == ACP_RN_PCI_ID) { ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND); if (ret) return ret; @@ -405,7 +438,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ - if (desc->rev >= 6) + if (adata->pci_rev >= ACP_RMB_PCI_ID) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); irq_flag = 1; @@ -431,6 +464,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) static int acp_power_on(struct snd_sof_dev *sdev) { const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + struct acp_dev_data *adata = sdev->pdata->hw_pdata; unsigned int base = desc->pgfsm_base; unsigned int val; unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask; @@ -441,16 +475,21 @@ static int acp_power_on(struct snd_sof_dev *sdev) if (val == ACP_POWERED_ON) return 0; - switch (desc->rev) { - case 3: - case 5: + switch (adata->pci_rev) { + case ACP_RN_PCI_ID: + case ACP_VANGOGH_PCI_ID: acp_pgfsm_status_mask = ACP3X_PGFSM_STATUS_MASK; acp_pgfsm_cntl_mask = ACP3X_PGFSM_CNTL_POWER_ON_MASK; break; - case 6: + case ACP_RMB_PCI_ID: + case ACP63_PCI_ID: acp_pgfsm_status_mask = ACP6X_PGFSM_STATUS_MASK; acp_pgfsm_cntl_mask = ACP6X_PGFSM_CNTL_POWER_ON_MASK; break; + case ACP70_PCI_ID: + acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK; + acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK; + break; default: return -EINVAL; } @@ -559,8 +598,11 @@ static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev) int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) { + struct acp_dev_data *acp_data; int ret; + bool enable = false; + acp_data = sdev->pdata->hw_pdata; /* When acp_reset() function is invoked, it will apply ACP SOFT reset and * DSP reset. ACP Soft reset sequence will cause all ACP IP registers will * be reset to default values which will break the ClockStop Mode functionality. @@ -575,8 +617,9 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) dev_err(sdev->dev, "ACP Reset failed\n"); return ret; } - - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00); + if (acp_data->pci_rev == ACP70_PCI_ID) + enable = true; + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); return 0; } @@ -713,6 +756,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) pci_set_master(pci); adata->addr = addr; adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; + adata->pci_rev = pci->revision; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 61b28df8c908..800594440f73 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -29,6 +29,8 @@ #define ACP3X_PGFSM_STATUS_MASK 0x03 #define ACP6X_PGFSM_CNTL_POWER_ON_MASK 0x07 #define ACP6X_PGFSM_STATUS_MASK 0x0F +#define ACP70_PGFSM_CNTL_POWER_ON_MASK 0x1F +#define ACP70_PGFSM_STATUS_MASK 0xFF #define ACP_POWERED_ON 0x00 #define ACP_ASSERT_RESET 0x01 @@ -42,6 +44,7 @@ #define ACP3X_SRAM_PTE_OFFSET 0x02050000 #define ACP5X_SRAM_PTE_OFFSET 0x02050000 #define ACP6X_SRAM_PTE_OFFSET 0x03800000 +#define ACP70_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 #define ACP_DMA_CH_RUN 0x02 @@ -63,17 +66,20 @@ #define ACP_DRAM_BASE_ADDRESS 0x01000000 #define ACP_DRAM_PAGE_COUNT 128 #define ACP_SRAM_BASE_ADDRESS 0x3806000 +#define ACP7X_SRAM_BASE_ADDRESS 0x380C000 #define ACP_DSP_TO_HOST_IRQ 0x04 #define ACP_RN_PCI_ID 0x01 #define ACP_VANGOGH_PCI_ID 0x50 #define ACP_RMB_PCI_ID 0x6F #define ACP63_PCI_ID 0x63 +#define ACP70_PCI_ID 0x70 #define HOST_BRIDGE_CZN 0x1630 #define HOST_BRIDGE_VGH 0x1645 #define HOST_BRIDGE_RMB 0x14B5 #define HOST_BRIDGE_ACP63 0x14E8 +#define HOST_BRIDGE_ACP70 0x1507 #define ACP_SHA_STAT 0x8000 #define ACP_PSP_TIMEOUT_US 1000000 #define ACP_EXT_INTR_ERROR_STAT 0x20000000 @@ -190,7 +196,6 @@ struct acp_dsp_stream { }; struct sof_amd_acp_desc { - unsigned int rev; const char *name; unsigned int host_bridge_id; u32 pgfsm_base; @@ -256,6 +261,7 @@ struct acp_dev_data { bool is_dram_in_use; bool is_sram_in_use; bool sdw_en_stat; + unsigned int pci_rev; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -326,6 +332,9 @@ int sof_rembrandt_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_acp63_ops; int sof_acp63_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_acp70_ops; +int sof_acp70_ops_init(struct snd_sof_dev *sdev); + struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); diff --git a/sound/soc/sof/amd/acp70.c b/sound/soc/sof/amd/acp70.c new file mode 100644 index 000000000000..7d1842f42c90 --- /dev/null +++ b/sound/soc/sof/amd/acp70.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2024 Advanced Micro Devices, Inc. +// +// Authors: Vijendar Mukunda + +/* + * Hardware interface for Audio DSP on ACP7.0 version based platform + */ + +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_HS_INSTANCE 0 +#define I2S_BT_INSTANCE 1 +#define I2S_SP_INSTANCE 2 +#define PDM_DMIC_INSTANCE 3 +#define I2S_HS_VIRTUAL_INSTANCE 4 + +static struct snd_soc_dai_driver acp70_sof_dai[] = { + [I2S_HS_INSTANCE] = { + .id = I2S_HS_INSTANCE, + .name = "acp-sof-hs", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_HS_VIRTUAL_INSTANCE] = { + .id = I2S_HS_VIRTUAL_INSTANCE, + .name = "acp-sof-hs-virtual", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + }, +}; + +/* Phoenix ops */ +struct snd_sof_dsp_ops sof_acp70_ops; +EXPORT_SYMBOL_NS(sof_acp70_ops, SND_SOC_SOF_AMD_COMMON); + +int sof_acp70_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_acp70_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_acp70_ops.drv = acp70_sof_dai; + sof_acp70_ops.num_drv = ARRAY_SIZE(acp70_sof_dai); + + return 0; +} diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c index 986f5928caed..b54ed61b79ed 100644 --- a/sound/soc/sof/amd/pci-acp63.c +++ b/sound/soc/sof/amd/pci-acp63.c @@ -28,7 +28,6 @@ #define ACP6x_REG_END 0x125C000 static const struct sof_amd_acp_desc acp63_chip_info = { - .rev = 6, .host_bridge_id = HOST_BRIDGE_ACP63, .pgfsm_base = ACP6X_PGFSM_BASE, .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB, @@ -50,6 +49,7 @@ static const struct sof_amd_acp_desc acp63_chip_info = { static const struct sof_dev_desc acp63_desc = { .machines = snd_soc_acpi_amd_acp63_sof_machines, + .alt_machines = snd_soc_acpi_amd_acp63_sof_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c new file mode 100644 index 000000000000..a5d8b6a95a22 --- /dev/null +++ b/sound/soc/sof/amd/pci-acp70.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vijendar Mukunda + +/*. + * PCI interface for ACP7.0 device + */ + +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP70_FUTURE_REG_ACLK_0 0x1854 +#define ACP70_REG_START 0x1240000 +#define ACP70_REG_END 0x125C000 + +static const struct sof_amd_acp_desc acp70_chip_info = { + .host_bridge_id = HOST_BRIDGE_ACP70, + .pgfsm_base = ACP70_PGFSM_BASE, + .ext_intr_enb = ACP70_EXTERNAL_INTR_ENB, + .ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL, + .ext_intr_stat = ACP70_EXT_INTR_STAT, + .ext_intr_stat1 = ACP70_EXT_INTR_STAT1, + .dsp_intr_base = ACP70_DSP_SW_INTR_BASE, + .acp_sw0_i2s_err_reason = ACP7X_SW0_I2S_ERROR_REASON, + .sram_pte_offset = ACP70_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP70_AXI2DAGB_SEM_0, + .fusion_dsp_offset = ACP70_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP70_FUTURE_REG_ACLK_0, + .reg_start_addr = ACP70_REG_START, + .reg_end_addr = ACP70_REG_END, +}; + +static const struct sof_dev_desc acp70_desc = { + .machines = snd_soc_acpi_amd_acp70_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &acp70_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), + .ipc_default = SOF_IPC_TYPE_3, + .default_fw_path = { + [SOF_IPC_TYPE_3] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_3] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_3] = "sof-acp_7_0.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_acp70_ops, + .ops_init = sof_acp70_ops_init, +}; + +static int acp70_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + if (pci->revision != ACP70_PCI_ID) + return -ENODEV; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +}; + +static void acp70_pci_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id acp70_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&acp70_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, acp70_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_acp70_driver = { + .name = KBUILD_MODNAME, + .id_table = acp70_pci_ids, + .probe = acp70_pci_probe, + .remove = acp70_pci_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_amd_acp70_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("ACP70 SOF Driver"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index a366f904e6f3..c45256bf4fda 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -28,7 +28,6 @@ #define ACP6X_FUTURE_REG_ACLK_0 0x1854 static const struct sof_amd_acp_desc rembrandt_chip_info = { - .rev = 6, .host_bridge_id = HOST_BRIDGE_RMB, .pgfsm_base = ACP6X_PGFSM_BASE, .ext_intr_stat = ACP6X_EXT_INTR_STAT, diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 2b7c53470ce8..386a0f1e7ee0 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -28,7 +28,6 @@ #define ACP3X_FUTURE_REG_ACLK_0 0x1860 static const struct sof_amd_acp_desc renoir_chip_info = { - .rev = 3, .host_bridge_id = HOST_BRIDGE_CZN, .pgfsm_base = ACP3X_PGFSM_BASE, .ext_intr_stat = ACP3X_EXT_INTR_STAT, diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c index eba580840100..cb845f81795e 100644 --- a/sound/soc/sof/amd/pci-vangogh.c +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -26,7 +26,6 @@ #define ACP5X_FUTURE_REG_ACLK_0 0x1864 static const struct sof_amd_acp_desc vangogh_chip_info = { - .rev = 5, .name = "vangogh", .host_bridge_id = HOST_BRIDGE_VGH, .pgfsm_base = ACP5X_PGFSM_BASE, diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 9f24e3c283dd..f09ee0dea2cc 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -658,7 +658,7 @@ MODULE_DEVICE_TABLE(of, sof_of_imx8_ids); /* DT driver definition */ static struct platform_driver snd_sof_of_imx8_driver = { .probe = sof_of_probe, - .remove_new = sof_of_remove, + .remove = sof_of_remove, .driver = { .name = "sof-audio-of-imx8", .pm = &sof_of_pm, diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index cdd1e79ef9f6..01d3ad3314f3 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -505,7 +505,7 @@ MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids); /* DT driver definition */ static struct platform_driver snd_sof_of_imx8m_driver = { .probe = sof_of_probe, - .remove_new = sof_of_remove, + .remove = sof_of_remove, .driver = { .name = "sof-audio-of-imx8m", .pm = &sof_of_pm, diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c index 2585b1beef23..e5eee1c9f6da 100644 --- a/sound/soc/sof/imx/imx8ulp.c +++ b/sound/soc/sof/imx/imx8ulp.c @@ -507,7 +507,7 @@ MODULE_DEVICE_TABLE(of, sof_of_imx8ulp_ids); /* DT driver definition */ static struct platform_driver snd_sof_of_imx8ulp_driver = { .probe = sof_of_probe, - .remove_new = sof_of_remove, + .remove = sof_of_remove, .driver = { .name = "sof-audio-of-imx8ulp", .pm = &sof_of_pm, diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 3396bd46b778..2c43558d96b9 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -281,6 +281,23 @@ config SND_SOC_SOF_LUNARLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_PTL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_IPC4 + select SND_SOC_SOF_INTEL_LNL + +config SND_SOC_SOF_PANTHERLAKE + tristate "SOF support for Pantherlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_PTL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Pantherlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index b56fa5530b8b..f40daa616803 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -34,6 +34,7 @@ snd-sof-pci-intel-icl-y := pci-icl.o icl.o snd-sof-pci-intel-tgl-y := pci-tgl.o tgl.o snd-sof-pci-intel-mtl-y := pci-mtl.o mtl.o snd-sof-pci-intel-lnl-y := pci-lnl.o lnl.o +snd-sof-pci-intel-ptl-y := pci-ptl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o @@ -43,3 +44,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_PTL) += snd-sof-pci-intel-ptl.o diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7f18080e4e19..322ff118f0f6 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -684,7 +684,7 @@ static int sof_broadwell_probe(struct platform_device *pdev) /* acpi_driver definition */ static struct platform_driver snd_sof_acpi_intel_bdw_driver = { .probe = sof_broadwell_probe, - .remove_new = sof_acpi_remove, + .remove = sof_acpi_remove, .driver = { .name = "sof-audio-acpi-intel-bdw", .pm = &sof_acpi_pm, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 7a57e162fb1c..f531710cf94e 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -465,7 +465,7 @@ static int sof_baytrail_probe(struct platform_device *pdev) /* acpi_driver definition */ static struct platform_driver snd_sof_acpi_intel_byt_driver = { .probe = sof_baytrail_probe, - .remove_new = sof_acpi_remove, + .remove = sof_acpi_remove, .driver = { .name = "sof-audio-acpi-intel-byt", .pm = &sof_acpi_pm, diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 1315f5bc3e31..4c88522d4048 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -69,6 +69,7 @@ static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask) interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA); break; case SOF_INTEL_ACE_2_0: + case SOF_INTEL_ACE_3_0: interface_mask[SOF_DAI_DSP_ACCESS] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 8213debde497..3ac63ce67ab1 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -216,9 +216,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags) /* stream found ? */ if (!hext_stream) { - dev_err(sdev->dev, "error: no free %s streams\n", - direction == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture"); + dev_err(sdev->dev, "error: no free %s streams\n", snd_pcm_direction_name(direction)); return hext_stream; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5a40b8fbbbd3..70fc08c8fc99 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -444,6 +444,10 @@ static int mclk_id_override = -1; module_param_named(mclk_id, mclk_id_override, int, 0444); MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id"); +static int bt_link_mask_override; +module_param_named(bt_link_mask, bt_link_mask_override, int, 0444); +MODULE_PARM_DESC(bt_link_mask, "SOF BT offload link mask"); + static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; @@ -511,6 +515,8 @@ static int check_dmic_num(struct snd_sof_dev *sdev) if (nhlt) dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); + dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); + /* allow for module parameter override */ if (dmic_num_override != -1) { dev_dbg(sdev->dev, @@ -527,7 +533,7 @@ static int check_dmic_num(struct snd_sof_dev *sdev) return dmic_num; } -static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev) +static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev, u8 device_type) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct nhlt_acpi_table *nhlt; @@ -538,9 +544,11 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev) return ssp_mask; if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) { - ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S); + ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, device_type); if (ssp_mask) - dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask); + dev_info(sdev->dev, "NHLT device %s(%d) detected, ssp_mask %#x\n", + device_type == NHLT_DEVICE_BT ? "BT" : "I2S", + device_type, ssp_mask); } return ssp_mask; @@ -558,82 +566,6 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num) return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num); } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) - -static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename, - const char *idisp_str, - const char *dmic_str) -{ - const char *tplg_filename = NULL; - char *filename, *tmp; - const char *split_ext; - - filename = kstrdup(sof_tplg_filename, GFP_KERNEL); - if (!filename) - return NULL; - - /* this assumes a .tplg extension */ - tmp = filename; - split_ext = strsep(&tmp, "."); - if (split_ext) - tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s%s%s.tplg", - split_ext, idisp_str, dmic_str); - kfree(filename); - - return tplg_filename; -} - -static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev, - const char **tplg_filename, - const char *idisp_str, - int *dmic_found, - bool tplg_fixup) -{ - const char *dmic_str; - int dmic_num; - - /* first check for DMICs (using NHLT or module parameter) */ - dmic_num = check_dmic_num(sdev); - - switch (dmic_num) { - case 1: - dmic_str = "-1ch"; - break; - case 2: - dmic_str = "-2ch"; - break; - case 3: - dmic_str = "-3ch"; - break; - case 4: - dmic_str = "-4ch"; - break; - default: - dmic_num = 0; - dmic_str = ""; - break; - } - - if (tplg_fixup) { - const char *default_tplg_filename = *tplg_filename; - const char *fixed_tplg_filename; - - fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, - idisp_str, dmic_str); - if (!fixed_tplg_filename) - return -ENOMEM; - *tplg_filename = fixed_tplg_filename; - } - - dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); - *dmic_found = dmic_num; - - return 0; -} -#endif - static int hda_init_caps(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -1045,10 +977,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, struct snd_soc_acpi_mach *hda_mach; struct snd_sof_pdata *pdata = sdev->pdata; const char *tplg_filename; - const char *idisp_str; - int dmic_num = 0; int codec_num = 0; - int ret; int i; /* codec detection */ @@ -1071,33 +1000,30 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, * - one external HDAudio codec */ if (!*mach && codec_num <= 2) { - bool tplg_fixup; + bool tplg_fixup = false; hda_mach = snd_soc_acpi_intel_hda_machines; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); - if (codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) - idisp_str = "-idisp"; - else - idisp_str = ""; - - /* topology: use the info from hda_machines */ - if (pdata->tplg_filename) { - tplg_fixup = false; - tplg_filename = pdata->tplg_filename; - } else { + /* + * topology: use the info from hda_machines since tplg file name + * is not overwritten + */ + if (!pdata->tplg_filename) tplg_fixup = true; - tplg_filename = hda_mach->sof_tplg_filename; - } - ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num, - tplg_fixup); - if (ret < 0) - return; - hda_mach->mach_params.dmic_num = dmic_num; - pdata->tplg_filename = tplg_filename; + if (tplg_fixup && + codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) { + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-idisp", + hda_mach->sof_tplg_filename); + if (!tplg_filename) + return; + + hda_mach->sof_tplg_filename = tplg_filename; + } if (codec_num == 2 || (codec_num == 1 && !HDA_IDISP_CODEC(bus->codec_mask))) { @@ -1125,7 +1051,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (*mach) { mach_params = &(*mach)->mach_params; mach_params->codec_mask = bus->codec_mask; - mach_params->common_hdmi_codec_drv = true; } } #else @@ -1205,45 +1130,10 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev break; } if (mach && mach->link_mask) { - int dmic_num = 0; - bool tplg_fixup; - const char *tplg_filename; - mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); - if (pdata->tplg_filename) { - tplg_fixup = false; - } else { - tplg_fixup = true; - tplg_filename = mach->sof_tplg_filename; - } - - /* - * DMICs use up to 4 pins and are typically pin-muxed with SoundWire - * link 2 and 3, or link 1 and 2, thus we only try to enable dmics - * if all conditions are true: - * a) 2 or fewer links are used by SoundWire - * b) the NHLT table reports the presence of microphones - */ - if (hweight_long(mach->link_mask) <= 2) { - int ret; - - ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "", - &dmic_num, tplg_fixup); - if (ret < 0) - return NULL; - } - if (tplg_fixup) - pdata->tplg_filename = tplg_filename; - mach->mach_params.dmic_num = dmic_num; - - dev_dbg(sdev->dev, - "SoundWire machine driver %s topology %s\n", - mach->drv_name, - pdata->tplg_filename); - return mach; } @@ -1300,6 +1190,19 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach) return 0; } +static char *remove_file_ext(const char *tplg_filename) +{ + char *filename, *tmp; + + filename = kstrdup(tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* remove file extension if exist */ + tmp = filename; + return strsep(&tmp, "."); +} + struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -1311,21 +1214,75 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) const char *tplg_filename; const char *tplg_suffix; bool amp_name_valid; + bool i2s_mach_found = false; + bool sdw_mach_found = false; /* Try I2S or DMIC if it is supported */ - if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) + if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) { mach = snd_soc_acpi_find_machine(desc->machines); + if (mach) + i2s_mach_found = true; + } + /* + * If I2S fails and no external HDaudio codec is detected, + * try SoundWire if it is supported + */ + if (!mach && !HDA_EXT_CODEC(bus->codec_mask) && + (interface_mask & BIT(SOF_DAI_INTEL_ALH))) { + mach = hda_sdw_machine_select(sdev); + if (mach) + sdw_mach_found = true; + } + + /* + * Choose HDA generic machine driver if mach is NULL. + * Otherwise, set certain mach params. + */ + hda_generic_machine_select(sdev, &mach); + if (!mach) { + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + return NULL; + } + + /* report BT offload link mask to machine driver */ + mach->mach_params.bt_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_BT); + + dev_info(sdev->dev, "BT link detected in NHLT tables: %#x\n", + mach->mach_params.bt_link_mask); + + /* allow for module parameter override */ + if (bt_link_mask_override) { + dev_dbg(sdev->dev, "overriding BT link detected in NHLT tables %#x by kernel param %#x\n", + mach->mach_params.bt_link_mask, bt_link_mask_override); + mach->mach_params.bt_link_mask = bt_link_mask_override; + } + + if (hweight_long(mach->mach_params.bt_link_mask) > 1) { + dev_warn(sdev->dev, "invalid BT link mask %#x found, reset the mask\n", + mach->mach_params.bt_link_mask); + mach->mach_params.bt_link_mask = 0; + } + + /* + * Fixup tplg file name by appending dmic num, ssp num, codec/amplifier + * name string if quirk flag is set. + */ if (mach) { - bool add_extension = false; bool tplg_fixup = false; + bool dmic_fixup = false; /* * If tplg file name is overridden, use it instead of * the one set in mach table */ if (!sof_pdata->tplg_filename) { - sof_pdata->tplg_filename = mach->sof_tplg_filename; + /* remove file extension if it exists */ + tplg_filename = remove_file_ext(mach->sof_tplg_filename); + if (!tplg_filename) + return NULL; + + sof_pdata->tplg_filename = tplg_filename; tplg_fixup = true; } @@ -1343,20 +1300,36 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) /* report to machine driver if any DMICs are found */ mach->mach_params.dmic_num = check_dmic_num(sdev); + if (sdw_mach_found) { + /* + * DMICs use up to 4 pins and are typically pin-muxed with SoundWire + * link 2 and 3, or link 1 and 2, thus we only try to enable dmics + * if all conditions are true: + * a) 2 or fewer links are used by SoundWire + * b) the NHLT table reports the presence of microphones + */ + if (hweight_long(mach->link_mask) <= 2) + dmic_fixup = true; + else + mach->mach_params.dmic_num = 0; + } else { + if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER) + dmic_fixup = true; + } + if (tplg_fixup && - mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER && + dmic_fixup && mach->mach_params.dmic_num) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s%d%s", sof_pdata->tplg_filename, - "-dmic", + i2s_mach_found ? "-dmic" : "-", mach->mach_params.dmic_num, "ch"); if (!tplg_filename) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } if (mach->link_mask) { @@ -1365,7 +1338,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } /* report SSP link mask to machine driver */ - mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev); + mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_I2S); if (tplg_fixup && mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER && @@ -1396,7 +1369,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num); @@ -1435,7 +1407,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } @@ -1457,10 +1428,9 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } - if (tplg_fixup && add_extension) { + if (tplg_fixup) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s", sof_pdata->tplg_filename, @@ -1479,22 +1449,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } } - /* - * If I2S fails and no external HDaudio codec is detected, - * try SoundWire if it is supported - */ - if (!mach && !HDA_EXT_CODEC(bus->codec_mask) && - (interface_mask & BIT(SOF_DAI_INTEL_ALH))) - mach = hda_sdw_machine_select(sdev); - - /* - * Choose HDA generic machine driver if mach is NULL. - * Otherwise, set certain mach params. - */ - hda_generic_machine_select(sdev, &mach); - if (!mach) - dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); - return mach; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3c9e1d59e1ab..b74a472435b5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -920,6 +920,7 @@ extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc mtl_chip_info; extern const struct sof_intel_dsp_desc arl_s_chip_info; extern const struct sof_intel_dsp_desc lnl_chip_info; +extern const struct sof_intel_dsp_desc ptl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 4b5665f82170..3d5a1f8b17e5 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -22,6 +22,7 @@ /* LunarLake ops */ struct snd_sof_dsp_ops sof_lnl_ops; +EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_LNL); static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -181,6 +182,7 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) return 0; }; +EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_LNL); /* Check if an SDW IRQ occurred */ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) @@ -245,3 +247,28 @@ const struct sof_intel_dsp_desc lnl_chip_info = { .disable_interrupts = lnl_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_ACE_2_0, }; + +const struct sof_intel_dsp_desc ptl_chip_info = { + .cores_num = 5, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = LNL_DSP_REG_HFDSC, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .enable_sdw_irq = lnl_enable_sdw_irq, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_3_0, +}; +EXPORT_SYMBOL_NS(ptl_chip_info, SND_SOC_SOF_INTEL_LNL); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 1bf274509ee6..2b9d22ccf345 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -245,6 +245,18 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) u32 cpa; u32 pgs; int ret; + u32 dsppwrctl; + u32 dsppwrsts; + const struct sof_intel_dsp_desc *chip; + + chip = get_chip_info(sdev->pdata); + if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) { + dsppwrctl = PTL_HFPWRCTL2; + dsppwrsts = PTL_HFPWRSTS2; + } else { + dsppwrctl = MTL_HFPWRCTL; + dsppwrsts = MTL_HFPWRSTS; + } /* Set the DSP subsystem power on */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, @@ -264,14 +276,14 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) } /* Power up gated-DSP-0 domain in order to access the DSP shim register block. */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, dsppwrctl, MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG); usleep_range(1000, 1010); /* poll with timeout to check if operation successful */ pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK; - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts, + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, dsppwrsts, dsphfpwrsts, (dsphfpwrsts & pgs) == pgs, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 7acaa7e724f4..9ab4b21c960e 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -12,9 +12,11 @@ #define MTL_HFDSSCS_CPA_MASK BIT(24) #define MTL_HFSNDWIE 0x114C #define MTL_HFPWRCTL 0x1D18 +#define PTL_HFPWRCTL2 0x1D20 #define MTL_HfPWRCTL_WPIOXPG(x) BIT((x) + 8) #define MTL_HFPWRCTL_WPDSPHPXPG BIT(0) #define MTL_HFPWRSTS 0x1D1C +#define PTL_HFPWRSTS2 0x1D24 #define MTL_HFPWRSTS_DSPHPXPGS_MASK BIT(0) #define MTL_HFINTIPPTR 0x1108 #define MTL_IRQ_INTEN_L_HOST_IPC_MASK BIT(0) diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c new file mode 100644 index 000000000000..69195b5e7b1a --- /dev/null +++ b/sound/soc/sof/intel/pci-ptl.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2024 Intel Corporation. +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc ptl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_ptl_machines, + .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &ptl_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_4), + .ipc_default = SOF_IPC_TYPE_4, + .dspless_mode_supported = true, + .default_fw_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ptl", + }, + .default_lib_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ptl", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_4] = "sof-ptl.ri", + }, + .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", + .ops = &sof_lnl_ops, + .ops_init = sof_lnl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, HDA_PTL, &ptl_desc) }, /* PTL */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_ptl_driver = { + .name = "sof-audio-pci-intel-ptl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_ptl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SOF support for PantherLake platforms"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_LNL); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_MTL); +MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 9328d2bbfd03..8709b750a11e 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -22,6 +22,7 @@ enum sof_intel_hw_ip_version { SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */ SOF_INTEL_ACE_1_0, /* MeteorLake */ SOF_INTEL_ACE_2_0, /* LunarLake */ + SOF_INTEL_ACE_3_0, /* PantherLake */ }; /* diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 74522400207e..9466f7d2e535 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -656,7 +656,7 @@ MODULE_DEVICE_TABLE(of, sof_of_mt8186_ids); /* DT driver definition */ static struct platform_driver snd_sof_of_mt8186_driver = { .probe = sof_of_probe, - .remove_new = sof_of_remove, + .remove = sof_of_remove, .shutdown = sof_of_shutdown, .driver = { .name = "sof-audio-of-mt8186", diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 82d221f53a46..5b4423ed8023 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -612,7 +612,7 @@ MODULE_DEVICE_TABLE(of, sof_of_mt8195_ids); /* DT driver definition */ static struct platform_driver snd_sof_of_mt8195_driver = { .probe = sof_of_probe, - .remove_new = sof_of_remove, + .remove = sof_of_remove, .shutdown = sof_of_shutdown, .driver = { .name = "sof-audio-of-mt8195", diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index baad4c1445aa..35a7462d8b69 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -100,7 +100,7 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run dpcm_end_walk_at_be); if (ret < 0) { dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name, - dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + snd_pcm_direction_name(dir)); return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 49be02234fc3..01b819dd8498 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -314,12 +314,12 @@ struct sof_token_info { /** * struct snd_sof_pcm_stream_pipeline_list - List of pipelines associated with a PCM stream - * @count: number of pipeline widgets in the @pipe_widgets array * @pipelines: array of pipelines + * @count: number of pipeline widgets in the @pipe_widgets array */ struct snd_sof_pcm_stream_pipeline_list { - u32 count; struct snd_sof_pipeline **pipelines; + u32 count; }; /* PCM stream, mapped to FW component */ @@ -347,12 +347,14 @@ struct snd_sof_pcm_stream { /* ALSA SOF PCM device */ struct snd_sof_pcm { struct snd_soc_component *scomp; - struct snd_soc_tplg_pcm pcm; struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; bool prepared[2]; /* PCM_PARAMS set successfully */ bool pending_stop[2]; /* only used if (!pcm_ops->platform_stop_during_hw_free) */ + + /* Must be last - ends in a flex-array member. */ + struct snd_soc_tplg_pcm pcm; }; struct snd_sof_led_control { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 4d6a1517f9b3..843be3b6415d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -132,16 +132,17 @@ struct snd_sof_pdata; /** * struct snd_sof_platform_stream_params - platform dependent stream parameters - * @stream_tag: Stream tag to use - * @use_phy_addr: Use the provided @phy_addr for configuration * @phy_addr: Platform dependent address to be used, if @use_phy_addr * is true + * @stream_tag: Stream tag to use + * @use_phy_addr: Use the provided @phy_addr for configuration * @no_ipc_position: Disable position update IPC from firmware + * @cont_update_posn: Continuous position update. */ struct snd_sof_platform_stream_params { + u32 phy_addr; u16 stream_tag; bool use_phy_address; - u32 phy_addr; bool no_ipc_position; bool cont_update_posn; }; @@ -411,8 +412,8 @@ struct snd_sof_debugfs_map { /* mailbox descriptor, used for host <-> DSP IPC */ struct snd_sof_mailbox { - u32 offset; size_t size; + u32 offset; }; /* IPC message descriptor for host <-> DSP IO */ @@ -424,11 +425,12 @@ struct snd_sof_ipc_msg { size_t reply_size; int reply_error; - /* notification, firmware initiated messages */ - void *rx_data; + bool ipc_complete; wait_queue_head_t waitq; - bool ipc_complete; + + /* notification, firmware initiated messages */ + void *rx_data; }; /** diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 496162df5270..b3fca5fd87d6 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1349,7 +1349,7 @@ static int sof_parse_pin_binding(struct snd_sof_widget *swidget, /* copy pin binding array to swidget only if it is defined in topology */ if (pin_binding[0]) { - pb = kmemdup(pin_binding, num_pins * sizeof(char *), GFP_KERNEL); + pb = kmemdup_array(pin_binding, num_pins, sizeof(char *), GFP_KERNEL); if (!pb) { ret = -ENOMEM; goto err; @@ -1889,9 +1889,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ return -ENOMEM; slink->num_hw_configs = le32_to_cpu(cfg->num_hw_configs); - slink->hw_configs = kmemdup(cfg->hw_config, - sizeof(*slink->hw_configs) * slink->num_hw_configs, - GFP_KERNEL); + slink->hw_configs = kmemdup_array(cfg->hw_config, + slink->num_hw_configs, sizeof(*slink->hw_configs), + GFP_KERNEL); if (!slink->hw_configs) { kfree(slink); return -ENOMEM; diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c index 688419c6b092..814a1cde1d35 100644 --- a/sound/soc/sprd/sprd-mcdt.c +++ b/sound/soc/sprd/sprd-mcdt.c @@ -993,7 +993,7 @@ MODULE_DEVICE_TABLE(of, sprd_mcdt_of_match); static struct platform_driver sprd_mcdt_driver = { .probe = sprd_mcdt_probe, - .remove_new = sprd_mcdt_remove, + .remove = sprd_mcdt_remove, .driver = { .name = "sprd-mcdt", .of_match_table = sprd_mcdt_of_match, diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c index 4a4dd431b82b..a603dd17931c 100644 --- a/sound/soc/starfive/jh7110_pwmdac.c +++ b/sound/soc/starfive/jh7110_pwmdac.c @@ -516,7 +516,7 @@ static struct platform_driver jh7110_pwmdac_driver = { .pm = pm_ptr(&jh7110_pwmdac_pm_ops), }, .probe = jh7110_pwmdac_probe, - .remove_new = jh7110_pwmdac_remove, + .remove = jh7110_pwmdac_remove, }; module_platform_driver(jh7110_pwmdac_driver); diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 1e0ff6720747..d38090e68df5 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -660,7 +660,7 @@ static struct platform_driver jh7110_tdm_driver = { .pm = pm_ptr(&jh7110_tdm_pm_ops), }, .probe = jh7110_tdm_probe, - .remove_new = jh7110_tdm_dev_remove, + .remove = jh7110_tdm_dev_remove, }; module_platform_driver(jh7110_tdm_driver); diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index fb5dd9a68bea..9351727dce1a 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -398,7 +398,7 @@ static struct platform_driver stm32_adfsdm_driver = { .of_match_table = stm32_adfsdm_of_match, }, .probe = stm32_adfsdm_probe, - .remove_new = stm32_adfsdm_remove, + .remove = stm32_adfsdm_remove, }; module_platform_driver(stm32_adfsdm_driver); diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 46098e111142..faa00103ee7f 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -823,7 +823,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* Enable i2s */ dev_dbg(cpu_dai->dev, "start I2S %s\n", - playback_flg ? "playback" : "capture"); + snd_pcm_direction_name(substream->stream)); cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, @@ -869,7 +869,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: dev_dbg(cpu_dai->dev, "stop I2S %s\n", - playback_flg ? "playback" : "capture"); + snd_pcm_direction_name(substream->stream)); if (playback_flg) regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, @@ -1216,7 +1216,7 @@ static struct platform_driver stm32_i2s_driver = { .pm = &stm32_i2s_pm_ops, }, .probe = stm32_i2s_probe, - .remove_new = stm32_i2s_remove, + .remove = stm32_i2s_remove, }; module_platform_driver(stm32_i2s_driver); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ad2492efb1cd..7bc4a96b7503 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1619,7 +1619,7 @@ static struct platform_driver stm32_sai_sub_driver = { .pm = &stm32_sai_sub_pm_ops, }, .probe = stm32_sai_sub_probe, - .remove_new = stm32_sai_sub_remove, + .remove = stm32_sai_sub_remove, }; module_platform_driver(stm32_sai_sub_driver); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 9eed3c57e3f1..d1b32ba1e1a2 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -1072,7 +1072,7 @@ static struct platform_driver stm32_spdifrx_driver = { .pm = &stm32_spdifrx_pm_ops, }, .probe = stm32_spdifrx_probe, - .remove_new = stm32_spdifrx_remove, + .remove = stm32_spdifrx_remove, }; module_platform_driver(stm32_spdifrx_driver); diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 25af47b63bdd..330bc0c09f56 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1828,7 +1828,7 @@ static struct platform_driver sun4i_codec_driver = { .of_match_table = sun4i_codec_of_match, }, .probe = sun4i_codec_probe, - .remove_new = sun4i_codec_remove, + .remove = sun4i_codec_remove, }; module_platform_driver(sun4i_codec_driver); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 3af0b2aab291..40de99a34bc3 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1684,7 +1684,7 @@ static const struct dev_pm_ops sun4i_i2s_pm_ops = { static struct platform_driver sun4i_i2s_driver = { .probe = sun4i_i2s_probe, - .remove_new = sun4i_i2s_remove, + .remove = sun4i_i2s_remove, .driver = { .name = "sun4i-i2s", .of_match_table = sun4i_i2s_match, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index f41c30955857..0aa416423246 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -726,7 +726,7 @@ static struct platform_driver sun4i_spdif_driver = { .pm = &sun4i_spdif_pm, }, .probe = sun4i_spdif_probe, - .remove_new = sun4i_spdif_remove, + .remove = sun4i_spdif_remove, }; module_platform_driver(sun4i_spdif_driver); diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index 884394ddaf86..3e751b5694fe 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -426,7 +426,7 @@ static struct platform_driver sun50i_dmic_driver = { .pm = &sun50i_dmic_pm, }, .probe = sun50i_dmic_probe, - .remove_new = sun50i_dmic_remove, + .remove = sun50i_dmic_remove, }; module_platform_driver(sun50i_dmic_driver); diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index b5dafb749c3f..8c645e04d571 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -1713,7 +1713,7 @@ static struct platform_driver sun8i_codec_driver = { .pm = &sun8i_codec_pm_ops, }, .probe = sun8i_codec_probe, - .remove_new = sun8i_codec_remove, + .remove = sun8i_codec_remove, }; module_platform_driver(sun8i_codec_driver); diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index 22af5135d77a..d914dba56013 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -1034,7 +1034,7 @@ static struct platform_driver tegra186_asrc_driver = { .pm = &tegra186_asrc_pm_ops, }, .probe = tegra186_asrc_platform_probe, - .remove_new = tegra186_asrc_platform_remove, + .remove = tegra186_asrc_platform_remove, }; module_platform_driver(tegra186_asrc_driver) diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 21cd41fec7a9..508128b7783e 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -542,7 +542,7 @@ static struct platform_driver tegra186_dspk_driver = { .pm = &tegra186_dspk_pm_ops, }, .probe = tegra186_dspk_platform_probe, - .remove_new = tegra186_dspk_platform_remove, + .remove = tegra186_dspk_platform_remove, }; module_platform_driver(tegra186_dspk_driver); diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 8011afe93c96..08c58e8f3c22 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -448,7 +448,7 @@ static struct platform_driver tegra20_ac97_driver = { .of_match_table = tegra20_ac97_of_match, }, .probe = tegra20_ac97_platform_probe, - .remove_new = tegra20_ac97_platform_remove, + .remove = tegra20_ac97_platform_remove, }; module_platform_driver(tegra20_ac97_driver); diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index f11618e8f13e..3b9823d1a87a 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -500,7 +500,7 @@ static struct platform_driver tegra20_i2s_driver = { .pm = &tegra20_i2s_pm_ops, }, .probe = tegra20_i2s_platform_probe, - .remove_new = tegra20_i2s_platform_remove, + .remove = tegra20_i2s_platform_remove, }; module_platform_driver(tegra20_i2s_driver); diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 9f9334e48049..a866aeb2719d 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -856,7 +856,7 @@ static const struct dev_pm_ops tegra_admaif_pm_ops = { static struct platform_driver tegra_admaif_driver = { .probe = tegra_admaif_probe, - .remove_new = tegra_admaif_remove, + .remove = tegra_admaif_remove, .driver = { .name = "tegra210-admaif", .of_match_table = tegra_admaif_of_match, diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index d2530443a221..109f763fe211 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -532,7 +532,7 @@ static struct platform_driver tegra210_adx_driver = { .pm = &tegra210_adx_pm_ops, }, .probe = tegra210_adx_platform_probe, - .remove_new = tegra210_adx_platform_remove, + .remove = tegra210_adx_platform_remove, }; module_platform_driver(tegra210_adx_driver); diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index ab3c6b2544d2..1920b996e9aa 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -1416,7 +1416,7 @@ static const struct dev_pm_ops tegra_ahub_pm_ops = { static struct platform_driver tegra_ahub_driver = { .probe = tegra_ahub_probe, - .remove_new = tegra_ahub_remove, + .remove = tegra_ahub_remove, .driver = { .name = "tegra210-ahub", .of_match_table = tegra_ahub_of_match, diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index 91e405909e0f..38a2d6ec033b 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -589,7 +589,7 @@ static struct platform_driver tegra210_amx_driver = { .pm = &tegra210_amx_pm_ops, }, .probe = tegra210_amx_platform_probe, - .remove_new = tegra210_amx_platform_remove, + .remove = tegra210_amx_platform_remove, }; module_platform_driver(tegra210_amx_driver); diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index e53c0278ae9a..d9b577f146dc 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -559,7 +559,7 @@ static struct platform_driver tegra210_dmic_driver = { .pm = &tegra210_dmic_pm_ops, }, .probe = tegra210_dmic_probe, - .remove_new = tegra210_dmic_remove, + .remove = tegra210_dmic_remove, }; module_platform_driver(tegra210_dmic_driver) diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index fe4fde844d86..a3908b15dfdc 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -85,7 +85,7 @@ static int tegra210_i2s_set_clock_rate(struct device *dev, } static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt, - bool is_playback) + int stream) { struct device *dev = compnt->dev; struct tegra210_i2s *i2s = dev_get_drvdata(dev); @@ -95,7 +95,7 @@ static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt, unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val; int err; - if (is_playback) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { reset_reg = TEGRA210_I2S_RX_SOFT_RESET; cif_reg = TEGRA210_I2S_RX_CIF_CTRL; stream_reg = TEGRA210_I2S_RX_CTRL; @@ -118,7 +118,7 @@ static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt, 10, 10000); if (err) { dev_err(dev, "timeout: failed to reset I2S for %s\n", - is_playback ? "playback" : "capture"); + snd_pcm_direction_name(stream)); return err; } @@ -137,16 +137,16 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w, struct device *dev = compnt->dev; struct tegra210_i2s *i2s = dev_get_drvdata(dev); unsigned int val, status_reg; - bool is_playback; + int stream; int err; switch (w->reg) { case TEGRA210_I2S_RX_ENABLE: - is_playback = true; + stream = SNDRV_PCM_STREAM_PLAYBACK; status_reg = TEGRA210_I2S_RX_STATUS; break; case TEGRA210_I2S_TX_ENABLE: - is_playback = false; + stream = SNDRV_PCM_STREAM_CAPTURE; status_reg = TEGRA210_I2S_TX_STATUS; break; default: @@ -159,11 +159,11 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w, 10, 10000); if (err) { dev_err(dev, "timeout: previous I2S %s is still active\n", - is_playback ? "playback" : "capture"); + snd_pcm_direction_name(stream)); return err; } - return tegra210_i2s_sw_reset(compnt, is_playback); + return tegra210_i2s_sw_reset(compnt, stream); } static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev) @@ -1019,7 +1019,7 @@ static struct platform_driver tegra210_i2s_driver = { .pm = &tegra210_i2s_pm_ops, }, .probe = tegra210_i2s_probe, - .remove_new = tegra210_i2s_remove, + .remove = tegra210_i2s_remove, }; module_platform_driver(tegra210_i2s_driver) diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index 024614f6ec0b..e07e2f1d2f70 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -674,7 +674,7 @@ static struct platform_driver tegra210_mixer_driver = { .pm = &tegra210_mixer_pm_ops, }, .probe = tegra210_mixer_platform_probe, - .remove_new = tegra210_mixer_platform_remove, + .remove = tegra210_mixer_platform_remove, }; module_platform_driver(tegra210_mixer_driver); diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index b89f5edafa03..4ead52564ab6 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -766,7 +766,7 @@ static struct platform_driver tegra210_mvc_driver = { .pm = &tegra210_mvc_pm_ops, }, .probe = tegra210_mvc_platform_probe, - .remove_new = tegra210_mvc_platform_remove, + .remove = tegra210_mvc_platform_remove, }; module_platform_driver(tegra210_mvc_driver) diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index 136ed17f3650..e2bc604e8b79 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -407,7 +407,7 @@ static struct platform_driver tegra210_ope_driver = { .pm = &tegra210_ope_pm_ops, }, .probe = tegra210_ope_probe, - .remove_new = tegra210_ope_remove, + .remove = tegra210_ope_remove, }; module_platform_driver(tegra210_ope_driver) diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index 028747c44f37..e16bbb44cc77 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -3631,7 +3631,7 @@ static struct platform_driver tegra210_sfc_driver = { .pm = &tegra210_sfc_pm_ops, }, .probe = tegra210_sfc_platform_probe, - .remove_new = tegra210_sfc_platform_remove, + .remove = tegra210_sfc_platform_remove, }; module_platform_driver(tegra210_sfc_driver) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d2e8078e444a..c9b52f54cea8 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -608,7 +608,7 @@ static const struct dev_pm_ops tegra30_ahub_pm_ops = { static struct platform_driver tegra30_ahub_driver = { .probe = tegra30_ahub_probe, - .remove_new = tegra30_ahub_remove, + .remove = tegra30_ahub_remove, .driver = { .name = DRV_NAME, .of_match_table = tegra30_ahub_of_match, diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index a8ff51d12edb..0d3badfbe143 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -560,7 +560,7 @@ static struct platform_driver tegra30_i2s_driver = { .pm = &tegra30_i2s_pm_ops, }, .probe = tegra30_i2s_platform_probe, - .remove_new = tegra30_i2s_platform_remove, + .remove = tegra30_i2s_platform_remove, }; module_platform_driver(tegra30_i2s_driver); diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index feba9d42bbc5..8b48813c2c59 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -248,7 +248,7 @@ static struct platform_driver tegra_audio_graph_card = { .of_match_table = graph_of_tegra_match, }, .probe = tegra_audio_graph_probe, - .remove_new = simple_util_remove, + .remove = simple_util_remove, }; module_platform_driver(tegra_audio_graph_card); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 4bdbcd2635ef..05d59e03b1c5 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -213,7 +213,7 @@ int tegra_pcm_construct(struct snd_soc_component *component, * Fallback for backwards-compatibility with older device trees that * have the iommus property in the virtual, top-level "sound" node. */ - if (!of_get_property(dev->of_node, "iommus", NULL)) + if (!of_property_present(dev->of_node, "iommus")) dev = rtd->card->snd_card->dev; return tegra_pcm_dma_allocate(dev, rtd, tegra_pcm_hardware.buffer_bytes_max); diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 76bda188e992..94645f275495 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -595,7 +595,7 @@ static struct platform_driver ams_delta_driver = { .name = DRV_NAME, }, .probe = ams_delta_probe, - .remove_new = ams_delta_remove, + .remove = ams_delta_remove, }; module_platform_driver(ams_delta_driver); diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 0f15a743c798..d682b98d6848 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -920,7 +920,7 @@ MODULE_DEVICE_TABLE(of, davinci_i2s_match); static struct platform_driver davinci_mcbsp_driver = { .probe = davinci_i2s_probe, - .remove_new = davinci_i2s_remove, + .remove = davinci_i2s_remove, .driver = { .name = "davinci-mcbsp", .of_match_table = of_match_ptr(davinci_i2s_match), diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 2b1ed91a736c..a0b8cca31cba 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2535,7 +2535,7 @@ static const struct dev_pm_ops davinci_mcasp_pm_ops = { static struct platform_driver davinci_mcasp_driver = { .probe = davinci_mcasp_probe, - .remove_new = davinci_mcasp_remove, + .remove = davinci_mcasp_remove, .driver = { .name = "davinci-mcasp", .pm = &davinci_mcasp_pm_ops, diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 2110ffe5281c..411970399271 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -1430,7 +1430,7 @@ static struct platform_driver asoc_mcbsp_driver = { }, .probe = asoc_mcbsp_probe, - .remove_new = asoc_mcbsp_remove, + .remove = asoc_mcbsp_remove, }; module_platform_driver(asoc_mcbsp_driver); diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 01cc3b961999..a041ce8e23a4 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -347,7 +347,7 @@ static struct platform_driver uniphier_aio_driver = { .of_match_table = of_match_ptr(uniphier_aio_of_match), }, .probe = uniphier_aio_probe, - .remove_new = uniphier_aio_remove, + .remove = uniphier_aio_remove, }; module_platform_driver(uniphier_aio_driver); diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index fba13a212bdb..889f64b2c01f 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -256,7 +256,7 @@ static struct platform_driver uniphier_aio_driver = { .of_match_table = of_match_ptr(uniphier_aio_of_match), }, .probe = uniphier_aio_probe, - .remove_new = uniphier_aio_remove, + .remove = uniphier_aio_remove, }; module_platform_driver(uniphier_aio_driver); diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index d90b3e4b0104..662e45882c90 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -560,7 +560,7 @@ static struct platform_driver evea_codec_driver = { .of_match_table = of_match_ptr(evea_of_match), }, .probe = evea_probe, - .remove_new = evea_remove, + .remove = evea_remove, }; module_platform_driver(evea_codec_driver); diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index e0ab4534fe3e..ae6d326167d1 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -157,7 +157,7 @@ static struct platform_driver snd_soc_mop500_driver = { .of_match_table = snd_soc_mop500_match, }, .probe = mop500_probe, - .remove_new = mop500_remove, + .remove = mop500_remove, }; module_platform_driver(snd_soc_mop500_driver); diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 3fd13e8dd110..a2dd739fdf2d 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -816,7 +816,7 @@ static struct platform_driver msp_i2s_driver = { .of_match_table = ux500_msp_i2s_match, }, .probe = ux500_msp_drv_probe, - .remove_new = ux500_msp_drv_remove, + .remove = ux500_msp_drv_remove, }; module_platform_driver(msp_i2s_driver); diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 158fc21a86c1..17ef05309469 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -713,7 +713,7 @@ MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match); static struct platform_driver xlnx_formatter_pcm_driver = { .probe = xlnx_formatter_pcm_probe, - .remove_new = xlnx_formatter_pcm_remove, + .remove = xlnx_formatter_pcm_remove, .driver = { .name = DRV_NAME, .of_match_table = xlnx_formatter_pcm_of_match, diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index d52d5fc7b5b8..7febb3830dc2 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -325,7 +325,7 @@ static struct platform_driver xlnx_spdif_driver = { .of_match_table = xlnx_spdif_of_match, }, .probe = xlnx_spdif_probe, - .remove_new = xlnx_spdif_remove, + .remove = xlnx_spdif_remove, }; module_platform_driver(xlnx_spdif_driver); diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 6e2b72d7a65d..4eaa9011405f 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -635,7 +635,7 @@ static const struct dev_pm_ops xtfpga_i2s_pm_ops = { static struct platform_driver xtfpga_i2s_driver = { .probe = xtfpga_i2s_probe, - .remove_new = xtfpga_i2s_remove, + .remove = xtfpga_i2s_remove, .driver = { .name = "xtfpga-i2s", .of_match_table = of_match_ptr(xtfpga_i2s_of_match), diff --git a/tools/sound/dapm-graph b/tools/sound/dapm-graph index 57d78f6df041..f14bdfedee8f 100755 --- a/tools/sound/dapm-graph +++ b/tools/sound/dapm-graph @@ -8,6 +8,8 @@ set -eu +STYLE_COMPONENT_ON="color=dodgerblue;style=bold" +STYLE_COMPONENT_OFF="color=gray40;style=filled;fillcolor=gray90" STYLE_NODE_ON="shape=box,style=bold,color=green4" STYLE_NODE_OFF="shape=box,style=filled,color=gray30,fillcolor=gray95" @@ -132,11 +134,17 @@ process_dapm_widget() # Collect any links. We could use "in" links or "out" links, # let's use "in" links if echo "${line}" | grep -q '^in '; then + local w_route=$(echo "$line" | awk -F\" '{print $2}') local w_src=$(echo "$line" | awk -F\" '{print $6 "_" $4}' | sed 's/^(null)_/ROOT_/') dbg_echo " - Input route from: ${w_src}" - echo " \"${w_src}\" -> \"$w_tag\"" >> "${links_file}" + dbg_echo " - Route: ${w_route}" + local w_edge_attrs="" + if [ "${w_route}" != "static" ]; then + w_edge_attrs=" [label=\"${w_route}\"]" + fi + echo " \"${w_src}\" -> \"$w_tag\"${w_edge_attrs}" >> "${links_file}" fi done @@ -150,16 +158,20 @@ process_dapm_widget() # # $1 = temporary work dir # $2 = component directory -# $3 = forced component name (extracted for path if empty) +# $3 = "ROOT" for the root card directory, empty otherwise process_dapm_component() { local tmp_dir="${1}" local c_dir="${2}" local c_name="${3}" + local is_component=0 local dot_file="${tmp_dir}/main.dot" local links_file="${tmp_dir}/links.dot" + local c_attribs="" if [ -z "${c_name}" ]; then + is_component=1 + # Extract directory name into component name: # "./cs42l51.0-004a/dapm" -> "cs42l51.0-004a" c_name="$(basename $(dirname "${c_dir}"))" @@ -167,11 +179,23 @@ process_dapm_component() dbg_echo " * Component: ${c_name}" - echo "" >> "${dot_file}" - echo " subgraph \"${c_name}\" {" >> "${dot_file}" - echo " cluster = true" >> "${dot_file}" - echo " label = \"${c_name}\"" >> "${dot_file}" - echo " color=dodgerblue" >> "${dot_file}" + if [ ${is_component} = 1 ]; then + if [ -f "${c_dir}/bias_level" ]; then + c_onoff=$(sed -n -e 1p "${c_dir}/bias_level" | awk '{print $1}') + dbg_echo " - bias_level: ${c_onoff}" + if [ "$c_onoff" = "On" ]; then + c_attribs="${STYLE_COMPONENT_ON}" + elif [ "$c_onoff" = "Off" ]; then + c_attribs="${STYLE_COMPONENT_OFF}" + fi + fi + + echo "" >> "${dot_file}" + echo " subgraph \"${c_name}\" {" >> "${dot_file}" + echo " cluster = true" >> "${dot_file}" + echo " label = \"${c_name}\"" >> "${dot_file}" + echo " ${c_attribs}" >> "${dot_file}" + fi # Create empty file to ensure it will exist in all cases >"${links_file}" @@ -181,7 +205,9 @@ process_dapm_component() process_dapm_widget "${tmp_dir}" "${c_name}" "${w_file}" done - echo " }" >> "${dot_file}" + if [ ${is_component} = 1 ]; then + echo " }" >> "${dot_file}" + fi cat "${links_file}" >> "${dot_file}" } @@ -200,7 +226,7 @@ process_dapm_tree() echo "digraph G {" > "${dot_file}" echo " fontname=\"sans-serif\"" >> "${dot_file}" echo " node [fontname=\"sans-serif\"]" >> "${dot_file}" - + echo " edge [fontname=\"sans-serif\"]" >> "${dot_file}" # Process root directory (no component) process_dapm_component "${tmp_dir}" "${dapm_dir}/dapm" "ROOT"