diff options
395 files changed, 17556 insertions, 6477 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1373.yaml b/Documentation/devicetree/bindings/sound/adi,adau1373.yaml new file mode 100644 index 000000000000..97552bf5d951 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau1373.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/adi,adau1373.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADAU1373 CODEC + +maintainers: + - Nuno Sá <nuno.sa@analog.com> + +description: | + Analog Devices ADAU1373 Low power codec with speaker and headphone amplifiers. + https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1373.pdf + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - adi,adau1373 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + powerdown-gpios: + description: GPIO used for hardware power-down. + maxItems: 1 + + adi,micbias1-microvolt: + description: + This property sets the microphone bias voltage for the first microphone. + enum: [1800000, 2200000, 2600000, 2900000] + default: 2900000 + + adi,micbias2-microvolt: + description: + This property sets the microphone bias voltage for the second microphone. + enum: [1800000, 2200000, 2600000, 2900000] + default: 2900000 + + adi,input1-differential: + description: This property sets the first analog input as differential. + type: boolean + + adi,input2-differential: + description: This property sets the second analog input as differential. + type: boolean + + adi,input3-differential: + description: This property sets the third analog input as differential. + type: boolean + + adi,input4-differential: + description: This property sets the fourth analog input as differential. + type: boolean + + adi,lineout-differential: + description: This property sets the line output as differential. + type: boolean + + adi,lineout-gnd-sense: + description: This property enables the line output ground sense control. + type: boolean + + adi,drc-settings: + description: + This setting is used to control the dynamic range of the signal. The + device provides a maximum of three full band DRCs with 13 entries each. + $ref: /schemas/types.yaml#/definitions/uint8-array + oneOf: + - minItems: 13 + maxItems: 13 + - minItems: 26 + maxItems: 26 + - minItems: 39 + maxItems: 39 + +required: + - "#sound-dai-cells" + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@1a { + compatible = "adi,adau1373"; + reg = <0x1a>; + #sound-dai-cells = <0>; + powerdown-gpios = <&gpio 100 GPIO_ACTIVE_LOW>; + adi,input2-differential; + adi,input1-differential; + adi,lineout-differential; + adi,micbias2-microvolt = <1800000>; + adi,drc-settings = /bits/ 8 < + 0xff 0xff 0x1 0x2 0xa 0xa 0xd 0x1 0xff 0xff 0x5 0xd 0xff + >; + }; + }; +... diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml index 78273647f766..ebc9097f936a 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml @@ -22,6 +22,7 @@ properties: - allwinner,sun8i-a23-codec - allwinner,sun8i-h3-codec - allwinner,sun8i-v3s-codec + - allwinner,sun50i-h616-codec reg: maxItems: 1 @@ -40,14 +41,20 @@ properties: - const: codec dmas: - items: - - description: RX DMA Channel - - description: TX DMA Channel + oneOf: + - items: + - description: RX DMA Channel + - description: TX DMA Channel + - items: + - description: TX DMA Channel dma-names: - items: - - const: rx - - const: tx + oneOf: + - items: + - const: rx + - const: tx + - items: + - const: tx resets: maxItems: 1 @@ -229,6 +236,40 @@ allOf: - Mic - Speaker + - if: + properties: + compatible: + enum: + - allwinner,sun50i-h616-codec + + then: + properties: + allwinner,audio-routing: + items: + enum: + - LINEOUT + - Line Out + + dmas: + items: + - description: TX DMA Channel + + dma-names: + items: + - const: tx + + else: + properties: + dmas: + items: + - description: RX DMA Channel + - description: TX DMA Channel + + dma-names: + items: + - const: rx + - const: tx + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml index 71f52f7e55f6..9899d9d1958d 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml @@ -37,8 +37,14 @@ properties: pa-gpios: maxItems: 1 hp-det-gpio: + deprecated: true + maxItems: 1 + hp-det-gpios: maxItems: 1 mic-det-gpio: + deprecated: true + maxItems: 1 + mic-det-gpios: maxItems: 1 required: diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml index ac5f2e0f42cb..3b0b743e49c4 100644 --- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml +++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml @@ -17,8 +17,9 @@ description: properties: compatible: enum: - - awinic,aw88395 + - awinic,aw88081 - awinic,aw88261 + - awinic,aw88395 - awinic,aw88399 reg: @@ -56,6 +57,7 @@ allOf: compatible: contains: enum: + - awinic,aw88081 - awinic,aw88261 then: properties: diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml new file mode 100644 index 000000000000..7f8338e8ae36 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs42l84.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS42L84 audio CODEC + +maintainers: + - Martin PoviÅ¡er <povik+lin@cutebit.org> + +description: | + The CS42L84 is a headphone jack codec made by Cirrus Logic and embedded + in personal computers sold by Apple. It was first seen in 2021 Macbook + Pro models. It has stereo DAC for playback, mono ADC for capture, and + is somewhat similar to CS42L42 but with a different regmap. + +properties: + compatible: + enum: + - cirrus,cs42l84 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + interrupts: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>; + interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml index 214f135b7777..e4b2eb5fae2f 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml @@ -4,12 +4,13 @@ $id: http://devicetree.org/schemas/sound/everest,es8316.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Everest ES8311 and ES8316 audio CODECs +title: Everest ES8311, ES8316 and ES8323 audio CODECs maintainers: - Daniel Drake <drake@endlessm.com> - Katsuhiro Suzuki <katsuhiro@katsuster.net> - Matteo Martelli <matteomartelli3@gmail.com> + - Binbin Zhou <zhoubinbin@loongson.cn> allOf: - $ref: dai-common.yaml# @@ -19,6 +20,7 @@ properties: enum: - everest,es8311 - everest,es8316 + - everest,es8323 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/everest,es8326.yaml b/Documentation/devicetree/bindings/sound/everest,es8326.yaml index d51431df7acf..b5594a9d508e 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8326.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8326.yaml @@ -24,6 +24,10 @@ properties: items: - const: mclk + interrupts: + maxItems: 1 + description: interrupt output for headset detection + "#sound-dai-cells": const: 0 diff --git a/Documentation/devicetree/bindings/sound/everest,es8328.yaml b/Documentation/devicetree/bindings/sound/everest,es8328.yaml index a0f4670fa38c..ed18e40dcaac 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8328.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8328.yaml @@ -50,6 +50,10 @@ properties: HPVDD-supply: description: Regulator providing analog output voltage 3.3V + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - clocks diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.yaml b/Documentation/devicetree/bindings/sound/fsl,esai.yaml index f99ed20fa684..27c34ce4c2e2 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,esai.yaml @@ -18,11 +18,15 @@ description: properties: compatible: - enum: - - fsl,imx35-esai - - fsl,imx6ull-esai - - fsl,imx8qm-esai - - fsl,vf610-esai + oneOf: + - enum: + - fsl,imx35-esai + - fsl,imx6ull-esai + - fsl,vf610-esai + - items: + - enum: + - fsl,imx8qm-esai + - const: fsl,imx6ull-esai reg: maxItems: 1 @@ -65,6 +69,9 @@ properties: - const: rx - const: tx + power-domains: + maxItems: 1 + fsl,fifo-depth: $ref: /schemas/types.yaml#/definitions/uint32 default: 64 @@ -101,6 +108,17 @@ unevaluatedProperties: false allOf: - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + const: fsl,imx8qm-esai + then: + required: + - power-domains + else: + properties: + power-domains: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml index 204f361cea27..5654e9f61aba 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml @@ -16,16 +16,23 @@ description: | properties: compatible: - enum: - - fsl,imx35-spdif - - fsl,vf610-spdif - - fsl,imx6sx-spdif - - fsl,imx8qm-spdif - - fsl,imx8qxp-spdif - - fsl,imx8mq-spdif - - fsl,imx8mm-spdif - - fsl,imx8mn-spdif - - fsl,imx8ulp-spdif + oneOf: + - items: + - enum: + - fsl,imx35-spdif + - fsl,imx6sx-spdif + - fsl,imx8mm-spdif + - fsl,imx8mn-spdif + - fsl,imx8mq-spdif + - fsl,imx8qm-spdif + - fsl,imx8qxp-spdif + - fsl,imx8ulp-spdif + - fsl,vf610-spdif + - items: + - enum: + - fsl,imx6sl-spdif + - fsl,imx6sx-spdif + - const: fsl,imx35-spdif reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt deleted file mode 100644 index 758de8e27561..000000000000 --- a/Documentation/devicetree/bindings/sound/inno-rk3036.txt +++ /dev/null @@ -1,20 +0,0 @@ -Inno audio codec for RK3036 - -Inno audio codec is integrated inside RK3036 SoC. - -Required properties: -- compatible : Should be "rockchip,rk3036-codec". -- reg : The registers of codec. -- clock-names : Should be "acodec_pclk". -- clocks : The clock of codec. -- rockchip,grf : The phandle of grf device node. - -Example: - - acodec: acodec-ana@20030000 { - compatible = "rk3036-codec"; - reg = <0x20030000 0x4000>; - rockchip,grf = <&grf>; - clock-names = "acodec_pclk"; - clocks = <&cru ACLK_VCODEC>; - }; diff --git a/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml b/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml new file mode 100644 index 000000000000..1e2a038d0048 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/irondevice,sma1307.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Iron Device SMA1307 Audio Amplifier + +maintainers: + - Kiseok Jo <kiseok.jo@irondevice.com> + +description: + SMA1307 boosted digital speaker amplifier with feedback-loop. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - irondevice,sma1307a + - irondevice,sma1307aq + description: + If a 'q' is added, it indicated the product is AEC-Q100 + qualified for automotive applications. SMA1307A supports + both WLCSP and QFN packages. However, SMA1307AQ only + supports the QFN package. + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + +required: + - compatible + - reg + - '#sound-dai-cells' + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + amplifier@1e { + compatible = "irondevice,sma1307a"; + reg = <0x1e>; + #sound-dai-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml new file mode 100644 index 000000000000..da79510bb2d9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/loongson,ls2k1000-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-2K1000 I2S controller + +maintainers: + - Binbin Zhou <zhoubinbin@loongson.cn> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: loongson,ls2k1000-i2s + + reg: + items: + - description: Loongson I2S controller Registers. + - description: APB DMA config register for Loongson I2S controller. + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + dmas: + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - dmas + - dma-names + - '#sound-dai-cells' + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/loongson,ls2k-clk.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2s@1fe2d000 { + compatible = "loongson,ls2k1000-i2s"; + reg = <0x1fe2d000 0x14>, + <0x1fe00438 0x8>; + interrupt-parent = <&liointc0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + dmas = <&apbdma2 0>, <&apbdma3 0>; + dma-names = "tx", "rx"; + #sound-dai-cells = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/sound/maxim,max98390.yaml b/Documentation/devicetree/bindings/sound/maxim,max98390.yaml index deaa6886c42f..d35dd8408c61 100644 --- a/Documentation/devicetree/bindings/sound/maxim,max98390.yaml +++ b/Documentation/devicetree/bindings/sound/maxim,max98390.yaml @@ -9,6 +9,9 @@ title: Maxim Integrated MAX98390 Speaker Amplifier with Integrated Dynamic Speak maintainers: - Steve Lee <steves.lee@maximintegrated.com> +allOf: + - $ref: dai-common.yaml# + properties: compatible: const: maxim,max98390 @@ -32,11 +35,14 @@ properties: reset-gpios: maxItems: 1 + '#sound-dai-cells': + const: 0 + required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml index f94ad0715e32..ba482747f0e6 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml @@ -29,6 +29,13 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of MT8188 ASoC platform. + mediatek,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the MT8188 ADSP platform, which is the optional Audio DSP + hardware that provides additional audio functionalities if present. + The AFE will link to ADSP when the phandle is provided. + patternProperties: "^dai-link-[0-9]+$": type: object diff --git a/Documentation/devicetree/bindings/sound/mt6359.yaml b/Documentation/devicetree/bindings/sound/mt6359.yaml index 23d411fc4200..128698630c86 100644 --- a/Documentation/devicetree/bindings/sound/mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mt6359.yaml @@ -23,8 +23,8 @@ properties: Indicates how many data pins are used to transmit two channels of PDM signal. 0 means two wires, 1 means one wire. Default value is 0. enum: - - 0 # one wire - - 1 # two wires + - 0 # two wires + - 1 # one wire mediatek,mic-type-0: $ref: /schemas/types.yaml#/definitions/uint32 @@ -53,9 +53,9 @@ additionalProperties: false examples: - | - mt6359codec: mt6359codec { - mediatek,dmic-mode = <0>; - mediatek,mic-type-0 = <2>; + mt6359codec: audio-codec { + mediatek,dmic-mode = <0>; + mediatek,mic-type-0 = <2>; }; ... diff --git a/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml b/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml new file mode 100644 index 000000000000..44d72a2ddfc9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/neofidelity,ntp8835.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NeoFidelity NTP8835/NTP8835C Amplifiers + +maintainers: + - Igor Prusov <ivprusov@salutedevices.com> + +description: | + The NTP8835 is a single chip full digital audio amplifier + including power stages for stereo amplifier systems. + NTP8835 is integrated with versatile digital audio signal + processing functions, high-performance, high-fidelity fully + digital PWM modulator and two high-power full-bridge MOSFET + power stages. NTP8835C has identical programming interface, + but has different output signal characteristics. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - neofidelity,ntp8835 + - neofidelity,ntp8835c + + reg: + enum: + - 0x2a + - 0x2b + - 0x2c + - 0x2d + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: wck + - const: bck + - const: scl + - const: mclk + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@2b { + compatible = "neofidelity,ntp8835"; + #sound-dai-cells = <0>; + reg = <0x2b>; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + clocks = <&clkc 551>, <&clkc 552>, <&clkc 553>, <&clkc 554>; + clock-names = "wck", "bck", "scl", "mclk"; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml new file mode 100644 index 000000000000..952768b35902 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/neofidelity,ntp8918.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NeoFidelity NTP8918 Amplifier + +maintainers: + - Igor Prusov <ivprusov@salutedevices.com> + +description: + The NTP8918 is a single chip full digital audio amplifier + including power stage for stereo amplifier system. + The NTP8918 is integrated with versatile digital audio signal + processing functions, high-performance, high-fidelity fully + digital PWM modulator and two high-power full-bridge MOSFET + power stages. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - neofidelity,ntp8918 + + reg: + enum: + - 0x2a + - 0x2b + - 0x2c + - 0x2d + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + clocks: + maxItems: 3 + + clock-names: + items: + - const: wck + - const: scl + - const: bck + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@2a { + compatible = "neofidelity,ntp8918"; + #sound-dai-cells = <0>; + reg = <0x2a>; + clocks = <&clkc 150>, <&clkc 151>, <&clkc 152>; + clock-names = "wck", "scl", "bck"; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml b/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml new file mode 100644 index 000000000000..71c6a5a2f5bc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nxp,uda1342.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP uda1342 audio CODECs + +maintainers: + - Binbin Zhou <zhoubinbin@loongson.cn> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: nxp,uda1342 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + - '#sound-dai-cells' + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + compatible = "nxp,uda1342"; + reg = <0x1a>; + #sound-dai-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml index b8540b30741e..92f95eb74b19 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-rx-macro + - qcom,sm8750-lpass-rx-macro - qcom,x1e80100-lpass-rx-macro - const: qcom,sm8550-lpass-rx-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml index 3e2ae16c6aba..914798a89878 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml @@ -22,6 +22,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-tx-macro + - qcom,sm8750-lpass-tx-macro - qcom,x1e80100-lpass-tx-macro - const: qcom,sm8550-lpass-tx-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 6b483fa3c428..f41deaa6f4df 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-va-macro + - qcom,sm8750-lpass-va-macro - qcom,x1e80100-lpass-va-macro - const: qcom,sm8550-lpass-va-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index 6f5644a89feb..9082e363c709 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-wsa-macro + - qcom,sm8750-lpass-wsa-macro - qcom,x1e80100-lpass-wsa-macro - const: qcom,sm8550-lpass-wsa-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 2e2e01493a5f..b9e33a7429b0 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -25,6 +25,7 @@ properties: - enum: - qcom,sm8550-sndcard - qcom,sm8650-sndcard + - qcom,sm8750-sndcard - const: qcom,sm8450-sndcard - enum: - qcom,apq8096-sndcard diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml new file mode 100644 index 000000000000..3f4f59287c1c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5640.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5640/RT5639 audio CODEC + +maintainers: + - Neil Armstrong <neil.armstrong@linaro.org> + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes) for RT5639/RT5640: + * DMIC1 + * DMIC2 + * MICBIAS1 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * HPOL + * HPOR + * LOUTL + * LOUTR + * SPOLP + * SPOLN + * SPORP + * SPORN + + Additional pins on the device for RT5640: + * MONOP + * MONON + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - realtek,rt5640 + - realtek,rt5639 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: The CODEC's interrupt output. + + realtek,in1-differential: + description: + Indicate MIC1 input is differential, rather than single-ended. + type: boolean + + realtek,in2-differential: + description: + Indicate MIC2 input is differential, rather than single-ended. + type: boolean + + realtek,in3-differential: + description: + Indicate MIC3 input is differential, rather than single-ended. + type: boolean + + realtek,lout-differential: + description: + Indicate LOUT output is differential, rather than single-ended. + type: boolean + + realtek,dmic1-data-pin: + description: Specify which pin to be used as DMIC1 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 is not used + - 1 # using IN2P pin as dmic1 data pin + - 2 # using GPIO3 pin as dmic1 data pin + + realtek,dmic2-data-pin: + description: Specify which pin to be used as DMIC2 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic2 is not used + - 1 # using IN2N pin as dmic2 data pin + - 2 # using GPIO4 pin as dmic2 data pin + + realtek,jack-detect-source: + description: The Jack Detect source. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # Jack Detect function is not used + - 1 # Use GPIO1 for jack-detect + - 2 # Use JD1_IN4P for jack-detect + - 3 # Use JD2_IN4N for jack-detect + - 4 # Use GPIO2 for jack-detect + - 5 # Use GPIO3 for jack-detect + - 6 # Use GPIO4 for jack-detect + + realtek,jack-detect-not-inverted: + description: + Normal jack-detect switches give an inverted signal, set this bool + in the rare case you've a jack-detect switch which is not inverted. + type: boolean + + realtek,over-current-threshold-microamp: + description: micbias over-current detection threshold in µA + enum: + - 600 + - 1500 + - 2000 + + realtek,over-current-scale-factor: + description: micbias over-current detection scale-factor + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # Scale current by 0.5 + - 1 # Scale current by 0.75 + - 2 # Scale current by 1.0 + - 3 # Scale current by 1.5 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "realtek,rt5640"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index dfd768b1ad7d..3f07b072d995 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -109,7 +109,7 @@ For more detail information, see below - Register Description - CTUn Scale Value exx Register (CTUn_SVxxR) - ${LINUX}/sound/soc/sh/rcar/ctu.c + ${LINUX}/sound/soc/renesas/rcar/ctu.c - comment of header You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it. diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml new file mode 100644 index 000000000000..7570cc1375ca --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/rockchip,rk3036-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip RK3036 internal codec + +maintainers: + - Heiko Stuebner <heiko@sntech.de> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: rockchip,rk3036-codec + + reg: + maxItems: 1 + + clocks: + items: + - description: clock for audio codec + + clock-names: + items: + - const: acodec_pclk + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the syscon node for the GRF register. + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - rockchip,grf + - "#sound-dai-cells" + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/rk3036-cru.h> + acodec: audio-codec@20030000 { + compatible = "rockchip,rk3036-codec"; + reg = <0x20030000 0x4000>; + rockchip,grf = <&grf>; + clock-names = "acodec_pclk"; + clocks = <&cru ACLK_VCODEC>; + #sound-dai-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt deleted file mode 100644 index 0c398581d52b..000000000000 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ /dev/null @@ -1,97 +0,0 @@ -RT5640/RT5639 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible : One of "realtek,rt5640" or "realtek,rt5639". - -- reg : The I2C address of the device. - -- interrupts : The CODEC's interrupt output. - -Optional properties: - -- clocks: The phandle of the master clock to the CODEC -- clock-names: Should be "mclk" - -- realtek,in1-differential -- realtek,in2-differential -- realtek,in3-differential - Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended. - -- realtek,lout-differential - Boolean. Indicate LOUT output is differential, rather than stereo. - -- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. - -- realtek,dmic1-data-pin - 0: dmic1 is not used - 1: using IN1P pin as dmic1 data pin - 2: using GPIO3 pin as dmic1 data pin - -- realtek,dmic2-data-pin - 0: dmic2 is not used - 1: using IN1N pin as dmic2 data pin - 2: using GPIO4 pin as dmic2 data pin - -- realtek,jack-detect-source - u32. Valid values: - 0: jack-detect is not used - 1: Use GPIO1 for jack-detect - 2: Use JD1_IN4P for jack-detect - 3: Use JD2_IN4N for jack-detect - 4: Use GPIO2 for jack-detect - 5: Use GPIO3 for jack-detect - 6: Use GPIO4 for jack-detect - -- realtek,jack-detect-not-inverted - bool. Normal jack-detect switches give an inverted signal, set this bool - in the rare case you've a jack-detect switch which is not inverted. - -- realtek,over-current-threshold-microamp - u32, micbias over-current detection threshold in µA, valid values are - 600, 1500 and 2000µA. - -- realtek,over-current-scale-factor - u32, micbias over-current detection scale-factor, valid values are: - 0: Scale current by 0.5 - 1: Scale current by 0.75 - 2: Scale current by 1.0 - 3: Scale current by 1.5 - -Pins on the device (for linking into audio routes) for RT5639/RT5640: - - * DMIC1 - * DMIC2 - * MICBIAS1 - * IN1P - * IN1N - * IN2P - * IN2N - * IN3P - * IN3N - * HPOL - * HPOR - * LOUTL - * LOUTR - * SPOLP - * SPOLN - * SPORP - * SPORN - -Additional pins on the device for RT5640: - - * MONOP - * MONON - -Example: - -rt5640 { - compatible = "realtek,rt5640"; - reg = <0x1c>; - interrupt-parent = <&gpio>; - interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_HIGH>; - realtek,ldo1-en-gpios = - <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml index 194ac1d4f4f5..9b1bda4852e1 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml @@ -29,6 +29,10 @@ properties: $ref: /schemas/types.yaml#/definitions/string-array maxItems: 2 + idle-state: + description: If present specifies the state when the mux is powered down + $ref: /schemas/mux/mux-controller.yaml#/properties/idle-state + sound-name-prefix: true required: @@ -43,4 +47,5 @@ examples: compatible = "simple-audio-mux"; mux-gpios = <&gpio 3 0>; state-labels = "Label_A", "Label_B"; + idle-state = <0>; }; diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml index 59ac2d1d1ccf..533d0a1da56e 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.yaml +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml @@ -207,8 +207,14 @@ properties: simple-audio-card,pin-switches: $ref: "#/definitions/pin-switches" simple-audio-card,hp-det-gpio: + deprecated: true + maxItems: 1 + simple-audio-card,hp-det-gpios: maxItems: 1 simple-audio-card,mic-det-gpio: + deprecated: true + maxItems: 1 + simple-audio-card,mic-det-gpios: maxItems: 1 patternProperties: @@ -256,8 +262,14 @@ patternProperties: pin-switches: $ref: "#/definitions/pin-switches" hp-det-gpio: + deprecated: true + maxItems: 1 + hp-det-gpios: maxItems: 1 mic-det-gpio: + deprecated: true + maxItems: 1 + mic-det-gpios: maxItems: 1 patternProperties: diff --git a/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml b/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml new file mode 100644 index 000000000000..c15c01bbb884 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sprd,pcm-platform.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum DMA platform + +maintainers: + - Orson Zhai <orsonzhai@gmail.com> + - Baolin Wang <baolin.wang7@gmail.com> + - Chunyan Zhang <zhang.lyra@gmail.com> + +properties: + compatible: + const: sprd,pcm-platform + + dmas: + maxItems: 10 + + dma-names: + items: + - const: normal_p_l + - const: normal_p_r + - const: normal_c_l + - const: normal_c_r + - const: voice_c + - const: fast_p + - const: loop_c + - const: loop_p + - const: voip_c + - const: voip_p + +required: + - compatible + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + platform { + compatible = "sprd,pcm-platform"; + dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, + <&agcp_dma 3 3>, <&agcp_dma 4 4>, + <&agcp_dma 5 5>, <&agcp_dma 6 6>, + <&agcp_dma 7 7>, <&agcp_dma 8 8>, + <&agcp_dma 9 9>, <&agcp_dma 10 10>; + dma-names = "normal_p_l", "normal_p_r", + "normal_c_l", "normal_c_r", + "voice_c", "fast_p", + "loop_c", "loop_p", + "voip_c", "voip_p"; + }; +... diff --git a/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml b/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml new file mode 100644 index 000000000000..3b66bedeff97 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sprd,sc9860-mcdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum Multi-Channel Data Transfer controller + +description: + The Multi-channel data transfer controller is used for sound stream + transmission between the audio subsystem and other AP/CP subsystem. It + supports 10 DAC channels and 10 ADC channels, and each channel can be + configured with DMA mode or interrupt mode. + +maintainers: + - Orson Zhai <orsonzhai@gmail.com> + - Baolin Wang <baolin.wang7@gmail.com> + - Chunyan Zhang <zhang.lyra@gmail.com> + +properties: + compatible: + const: sprd,sc9860-mcdt + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + + mcdt@41490000 { + compatible = "sprd,sc9860-mcdt"; + reg = <0x41490000 0x170>; + interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; + }; +... diff --git a/Documentation/devicetree/bindings/sound/sprd-mcdt.txt b/Documentation/devicetree/bindings/sound/sprd-mcdt.txt deleted file mode 100644 index 274ba0acbfd6..000000000000 --- a/Documentation/devicetree/bindings/sound/sprd-mcdt.txt +++ /dev/null @@ -1,19 +0,0 @@ -Spreadtrum Multi-Channel Data Transfer Binding - -The Multi-channel data transfer controller is used for sound stream -transmission between audio subsystem and other AP/CP subsystem. It -supports 10 DAC channel and 10 ADC channel, and each channel can be -configured with DMA mode or interrupt mode. - -Required properties: -- compatible: Should be "sprd,sc9860-mcdt". -- reg: Should contain registers address and length. -- interrupts: Should contain one interrupt shared by all channel. - -Example: - -mcdt@41490000 { - compatible = "sprd,sc9860-mcdt"; - reg = <0 0x41490000 0 0x170>; - interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/sound/sprd-pcm.txt b/Documentation/devicetree/bindings/sound/sprd-pcm.txt deleted file mode 100644 index fbbcade2181d..000000000000 --- a/Documentation/devicetree/bindings/sound/sprd-pcm.txt +++ /dev/null @@ -1,23 +0,0 @@ -* Spreadtrum DMA platform bindings - -Required properties: -- compatible: Should be "sprd,pcm-platform". -- dmas: Specify the list of DMA controller phandle and DMA request line ordered pairs. -- dma-names: Identifier string for each DMA request line in the dmas property. - These strings correspond 1:1 with the ordered pairs in dmas. - -Example: - - audio_platform:platform@0 { - compatible = "sprd,pcm-platform"; - dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, - <&agcp_dma 3 3>, <&agcp_dma 4 4>, - <&agcp_dma 5 5>, <&agcp_dma 6 6>, - <&agcp_dma 7 7>, <&agcp_dma 8 8>, - <&agcp_dma 9 9>, <&agcp_dma 10 10>; - dma-names = "normal_p_l", "normal_p_r", - "normal_c_l", "normal_c_r", - "voice_c", "fast_p", - "loop_c", "loop_p", - "voip_c", "voip_p"; - }; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml index 8978f6bd63e5..b4f44f9c7c7d 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml @@ -13,13 +13,11 @@ description: The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. Only some SPI instances support I2S. -allOf: - - $ref: dai-common.yaml# - properties: compatible: enum: - st,stm32h7-i2s + - st,stm32mp25-i2s "#sound-dai-cells": const: 0 @@ -33,6 +31,7 @@ properties: - description: clock feeding the internal clock generator. - description: I2S parent clock for sampling rates multiple of 8kHz. - description: I2S parent clock for sampling rates multiple of 11.025kHz. + minItems: 2 clock-names: items: @@ -40,6 +39,7 @@ properties: - const: i2sclk - const: x8k - const: x11k + minItems: 2 interrupts: maxItems: 1 @@ -79,6 +79,36 @@ required: - dmas - dma-names +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + const: st,stm32h7-i2s + + then: + properties: + clocks: + minItems: 4 + + clock-names: + minItems: 4 + + - if: + properties: + compatible: + contains: + const: st,stm32mp25-i2s + + then: + properties: + clocks: + maxItems: 2 + + clock-names: + maxItems: 2 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml index 68f97b462598..4a7129d0b157 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml @@ -20,6 +20,7 @@ properties: enum: - st,stm32f4-sai - st,stm32h7-sai + - st,stm32mp25-sai reg: items: @@ -43,9 +44,11 @@ properties: const: 1 clocks: + minItems: 1 maxItems: 3 clock-names: + minItems: 1 maxItems: 3 access-controllers: @@ -156,7 +159,13 @@ allOf: items: - const: x8k - const: x11k - else: + + - if: + properties: + compatible: + contains: + const: st,stm32mph7-sai + then: properties: clocks: items: @@ -170,6 +179,21 @@ allOf: - const: x8k - const: x11k + - if: + properties: + compatible: + contains: + const: st,stm32mp25-sai + then: + properties: + clocks: + items: + - description: pclk feeds the peripheral bus interface. + + clock-names: + items: + - const: pclk + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml index 3dedc81ec12f..56c5738ea4c5 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml @@ -50,6 +50,10 @@ properties: resets: maxItems: 1 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + access-controllers: minItems: 1 maxItems: 2 diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 7ebc61426225..b0531b935b3e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1017,6 +1017,8 @@ patternProperties: description: Shanghai Neardi Technology Co., Ltd. "^nec,.*": description: NEC LCD Technologies, Ltd. + "^neofidelity,.*": + description: Neofidelity Inc. "^neonode,.*": description: Neonode Inc. "^netgear,.*": diff --git a/Documentation/sound/designs/compress-accel.rst b/Documentation/sound/designs/compress-accel.rst new file mode 100644 index 000000000000..c9c1744b94c2 --- /dev/null +++ b/Documentation/sound/designs/compress-accel.rst @@ -0,0 +1,134 @@ +================================== +ALSA Co-processor Acceleration API +================================== + +Jaroslav Kysela <perex@perex.cz> + + +Overview +======== + +There is a requirement to expose the audio hardware that accelerates various +tasks for user space such as sample rate converters, compressed +stream decoders, etc. + +This is description for the API extension for the compress ALSA API which +is able to handle "tasks" that are not bound to real-time operations +and allows for the serialization of operations. + +Requirements +============ + +The main requirements are: + +- serialization of multiple tasks for user space to allow multiple + operations without user space intervention + +- separate buffers (input + output) for each operation + +- expose buffers using mmap to user space + +- signal user space when the task is finished (standard poll mechanism) + +Design +====== + +A new direction SND_COMPRESS_ACCEL is introduced to identify +the passthrough API. + +The API extension shares device enumeration and parameters handling from +the main compressed API. All other realtime streaming ioctls are deactivated +and a new set of task related ioctls are introduced. The standard +read/write/mmap I/O operations are not supported in the passthrough device. + +Device ("stream") state handling is reduced to OPEN/SETUP. All other +states are not available for the passthrough mode. + +Data I/O mechanism is using standard dma-buf interface with all advantages +like mmap, standard I/O, buffer sharing etc. One buffer is used for the +input data and second (separate) buffer is used for the output data. Each task +have separate I/O buffers. + +For the buffering parameters, the fragments means a limit of allocated tasks +for given device. The fragment_size limits the input buffer size for the given +device. The output buffer size is determined by the driver (may be different +from the input buffer size). + +State Machine +============= + +The passthrough audio stream state machine is described below:: + + +----------+ + | | + | OPEN | + | | + +----------+ + | + | + | compr_set_params() + | + v + all passthrough task ops +----------+ + +------------------------------------| | + | | SETUP | + | | + | +----------+ + | | + +------------------------------------------+ + + +Passthrough operations (ioctls) +=============================== + +All operations are protected using stream->device->lock (mutex). + +CREATE +------ +Creates a set of input/output buffers. The input buffer size is +fragment_size. Allocates unique seqno. + +The hardware drivers allocate internal 'struct dma_buf' for both input and +output buffers (using 'dma_buf_export()' function). The anonymous +file descriptors for those buffers are passed to user space. + +FREE +---- +Free a set of input/output buffers. If a task is active, the stop +operation is executed before. If seqno is zero, operation is executed for all +tasks. + +START +----- +Starts (queues) a task. There are two cases of the task start - right after +the task is created. In this case, origin_seqno must be zero. +The second case is for reusing of already finished task. The origin_seqno +must identify the task to be reused. In both cases, a new seqno value +is allocated and returned to user space. + +The prerequisite is that application filled input dma buffer with +new source data and set input_size to pass the real data size to the driver. + +The order of data processing is preserved (first started job must be +finished at first). + +If the multiple tasks require a state handling (e.g. resampling operation), +the user space may set SND_COMPRESS_TFLG_NEW_STREAM flag to mark the +start of the new stream data. It is useful to keep the allocated buffers +for the new operation rather using open/close mechanism. + +STOP +---- +Stop (dequeues) a task. If seqno is zero, operation is executed for all +tasks. + +STATUS +------ +Obtain the task status (active, finished). Also, the driver will set +the real output data size (valid area in the output buffer). + +Credits +======= +- Shengjiu Wang <shengjiu.wang@gmail.com> +- Takashi Iwai <tiwai@suse.de> +- Vinod Koul <vkoul@kernel.org> diff --git a/Documentation/sound/designs/index.rst b/Documentation/sound/designs/index.rst index b79db9ad8732..6b825c5617fc 100644 --- a/Documentation/sound/designs/index.rst +++ b/Documentation/sound/designs/index.rst @@ -6,6 +6,7 @@ Designs and Implementations control-names channel-mapping-api + compress-accel compress-offload timestamping jack-controls diff --git a/Documentation/sound/soc/clocking.rst b/Documentation/sound/soc/clocking.rst index 32122d6877a3..25d016ea8b65 100644 --- a/Documentation/sound/soc/clocking.rst +++ b/Documentation/sound/soc/clocking.rst @@ -42,5 +42,17 @@ rate, number of channels and word size) to save on power. It is also desirable to use the codec (if possible) to drive (or master) the audio clocks as it usually gives more accurate sample rates than the CPU. +ASoC provided clock APIs +------------------------ +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_sysclk +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_clkdiv + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_pll + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_bclk_ratio diff --git a/Documentation/sound/soc/dpcm.rst b/Documentation/sound/soc/dpcm.rst index 2d7ad1d91504..02419a6f8213 100644 --- a/Documentation/sound/soc/dpcm.rst +++ b/Documentation/sound/soc/dpcm.rst @@ -157,15 +157,13 @@ FE DAI links are defined as follows :- .codec_dai_name = "snd-soc-dummy-dai", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, }, .....< other FE and BE DAI links here > }; This FE DAI link is pretty similar to a regular DAI link except that we also -set the DAI link to a DPCM FE with the ``dynamic = 1``. The supported FE stream -directions should also be set with the ``dpcm_playback`` and ``dpcm_capture`` -flags. There is also an option to specify the ordering of the trigger call for +set the DAI link to a DPCM FE with the ``dynamic = 1``. +There is also an option to specify the ordering of the trigger call for each FE. This allows the ASoC core to trigger the DSP before or after the other components (as some DSPs have strong requirements for the ordering DAI/DSP start and stop sequences). @@ -189,15 +187,12 @@ The BE DAIs are configured as follows :- .ignore_pmdown_time = 1, .be_hw_params_fixup = hswult_ssp0_fixup, .ops = &haswell_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, }, .....< other BE DAI links here > }; This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets -the ``no_pcm`` flag to mark it has a BE and sets flags for supported stream -directions using ``dpcm_playback`` and ``dpcm_capture`` above. +the ``no_pcm`` flag to mark it has a BE. The BE has also flags set for ignoring suspend and PM down time. This allows the BE to work in a hostless mode where the host CPU is not transferring data diff --git a/Documentation/sound/soc/machine.rst b/Documentation/sound/soc/machine.rst index 515c9444deaf..9db132bc0070 100644 --- a/Documentation/sound/soc/machine.rst +++ b/Documentation/sound/soc/machine.rst @@ -71,6 +71,18 @@ struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. .ops = &corgi_ops, }; +In the above struct, dai’s are registered using names but you can pass +either dai name or device tree node but not both. Also, names used here +for cpu/codec/platform dais should be globally unique. + +Additionaly below example macro can be used to register cpu, codec and +platform dai:: + + SND_SOC_DAILINK_DEFS(wm2200_cpu_dsp, + DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); + struct snd_soc_card then sets up the machine with its DAIs. e.g. :: @@ -81,6 +93,10 @@ struct snd_soc_card then sets up the machine with its DAIs. e.g. .num_links = 1, }; +Following this, ``devm_snd_soc_register_card`` can be used to register +the sound card. During the registration, the individual components +such as the codec, CPU, and platform are probed. If all these components +are successfully probed, the sound card gets registered. Machine Power Map ----------------- @@ -95,3 +111,13 @@ Machine Controls ---------------- Machine specific audio mixer controls can be added in the DAI init function. + + +Clocking Controls +----------------- + +As previously noted, clock configuration is handled within the machine driver. +For details on the clock APIs that the machine driver can utilize for +setup, please refer to Documentation/sound/soc/clocking.rst. However, the +callback needs to be registered by the CPU/Codec/Platform drivers to configure +the clocks that is needed for the corresponding device operation. diff --git a/MAINTAINERS b/MAINTAINERS index 4148844ca52e..48688a2f3b7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1530,6 +1530,7 @@ L: linux-sound@vger.kernel.org S: Supported W: http://wiki.analog.com/ W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/sound/adi,* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ad7* F: sound/soc/codecs/adau* @@ -2141,9 +2142,11 @@ L: asahi@lists.linux.dev L: linux-sound@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml +F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml F: Documentation/devicetree/bindings/sound/apple,* F: sound/soc/apple/* F: sound/soc/codecs/cs42l83-i2c.c +F: sound/soc/codecs/cs42l84.* F: sound/soc/codecs/ssm3515.c ARM/APPLE MACHINE SUPPORT @@ -19694,6 +19697,17 @@ S: Maintained F: Documentation/devicetree/bindings/sound/renesas,idt821034.yaml F: sound/soc/codecs/idt821034.c +RENESAS R-CAR & FSI AUDIO (ASoC) DRIVERS +M: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +L: linux-sound@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/sound/renesas,rsnd.* +F: Documentation/devicetree/bindings/sound/renesas,fsi.yaml +F: sound/soc/renesas/rcar/ +F: sound/soc/renesas/fsi.c +F: include/sound/sh_fsi.h + RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER M: Miquel Raynal <miquel.raynal@bootlin.com> L: linux-mtd@lists.infradead.org @@ -19742,6 +19756,15 @@ S: Supported F: Documentation/devicetree/bindings/i2c/renesas,riic.yaml F: drivers/i2c/busses/i2c-riic.c +RENESAS RZ AUDIO (ASoC) DRIVER +M: Biju Das <biju.das.jz@bp.renesas.com> +M: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> +L: linux-sound@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +F: sound/soc/renesas/rz-ssi.c + RENESAS RZ/G2L A/D DRIVER M: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> L: linux-iio@vger.kernel.org diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig index 4d8f3b7024ae..f66f869dff2e 100644 --- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig @@ -6,6 +6,7 @@ menuconfig SOUNDWIRE tristate "SoundWire support" depends on ACPI || OF + depends on SND_SOC_SDCA_OPTIONAL help SoundWire is a 2-Pin interface with data and clock line ratified by the MIPI Alliance. SoundWire is used for transporting data diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c index db040f435059..53d1d707ca1a 100644 --- a/drivers/soundwire/amd_init.c +++ b/drivers/soundwire/amd_init.c @@ -177,7 +177,7 @@ EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT); void sdw_amd_exit(struct sdw_amd_ctx *ctx) { sdw_amd_cleanup(ctx); - kfree(ctx->ids); + kfree(ctx->peripherals); kfree(ctx); } EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); @@ -204,10 +204,11 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) num_slaves++; } - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); - if (!ctx->ids) + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), + GFP_KERNEL); + if (!ctx->peripherals) return -ENOMEM; - ctx->num_slaves = num_slaves; + ctx->peripherals->num_peripherals = num_slaves; for (index = 0; index < ctx->count; index++) { if (!(ctx->link_mask & BIT(index))) continue; @@ -215,8 +216,7 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) if (amd_manager) { bus = &amd_manager->bus; list_for_each_entry(slave, &bus->slaves, node) { - ctx->ids[i].id = slave->id; - ctx->ids[i].link_id = bus->link_id; + ctx->peripherals->array[i] = slave; i++; } } diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 4f3dd70d6a1a..a005b63582e9 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -175,6 +175,9 @@ static int intel_link_power_up(struct sdw_intel *sdw) __func__, ret); goto out; } + + hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true, + AZX_REG_ML_LEPTR_ID_SDW, true); } *shim_mask |= BIT(link_id); @@ -201,6 +204,10 @@ static int intel_link_power_down(struct sdw_intel *sdw) *shim_mask &= ~BIT(link_id); + if (!*shim_mask) + hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true, + AZX_REG_ML_LEPTR_ID_SDW, false); + ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id); if (ret < 0) { dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n", diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index a09134b97cd6..12e7a98f319f 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -252,17 +252,16 @@ static struct sdw_intel_ctx num_slaves++; } - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); - if (!ctx->ids) + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), + GFP_KERNEL); + if (!ctx->peripherals) goto err; - - ctx->num_slaves = num_slaves; + ctx->peripherals->num_peripherals = num_slaves; i = 0; list_for_each_entry(link, &ctx->link_list, list) { bus = &link->cdns->bus; list_for_each_entry(slave, &bus->slaves, node) { - ctx->ids[i].id = slave->id; - ctx->ids[i].link_id = bus->link_id; + ctx->peripherals->array[i] = slave; i++; } } @@ -371,7 +370,7 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) } sdw_intel_cleanup(ctx); - kfree(ctx->ids); + kfree(ctx->peripherals); kfree(ctx->ldev); kfree(ctx); } diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index f1a4df6cfebd..97cf8bcca047 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -5,6 +5,7 @@ #include <linux/of.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <sound/sdca.h> #include "bus.h" #include "sysfs_local.h" @@ -70,6 +71,17 @@ int sdw_slave_add(struct sdw_bus *bus, list_add_tail(&slave->node, &bus->slaves); mutex_unlock(&bus->bus_lock); + /* + * The Soundwire driver probe may optionally register SDCA + * sub-devices, one per Function. This means the information + * on the SDCA revision and the number/type of Functions need + * to be extracted from platform firmware before the SoundWire + * driver probe, and as a consequence before the SoundWire + * device_register() below. + */ + sdca_lookup_interface_revision(slave); + sdca_lookup_functions(slave); + ret = device_register(&slave->dev); if (ret) { dev_err(bus->dev, "Failed to add slave: ret %d\n", ret); @@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus) return 0; } + +MODULE_IMPORT_NS(SND_SOC_SDCA); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 5e0dd47a0412..49d690f3d29a 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -10,6 +10,7 @@ #include <linux/irqdomain.h> #include <linux/mod_devicetable.h> #include <linux/bitfield.h> +#include <sound/sdca.h> struct sdw_bus; struct sdw_slave; @@ -488,9 +489,9 @@ struct sdw_slave_id { __u8 sdw_version:4; }; -struct sdw_extended_slave_id { - int link_id; - struct sdw_slave_id id; +struct sdw_peripherals { + int num_peripherals; + struct sdw_slave *array[]; }; /* @@ -663,6 +664,7 @@ struct sdw_slave_ops { * @is_mockup_device: status flag used to squelch errors in the command/control * protocol for SoundWire mockup devices * @sdw_dev_lock: mutex used to protect callbacks/remove races + * @sdca_data: structure containing all device data for SDCA helpers */ struct sdw_slave { struct sdw_slave_id id; @@ -686,6 +688,7 @@ struct sdw_slave { bool first_interrupt_done; bool is_mockup_device; struct mutex sdw_dev_lock; /* protect callbacks/remove races */ + struct sdca_device_data sdca_data; }; #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h index 28a4eb77717f..585b4c58a8a6 100644 --- a/include/linux/soundwire/sdw_amd.h +++ b/include/linux/soundwire/sdw_amd.h @@ -115,19 +115,16 @@ struct sdw_amd_acpi_info { * struct sdw_amd_ctx - context allocated by the controller driver probe * * @count: link count - * @num_slaves: total number of devices exposed across all enabled links * @link_mask: bit-wise mask listing SoundWire links reported by the * Controller - * @ids: array of slave_id, representing Slaves exposed across all enabled - * links * @pdev: platform device structure + * @peripherals: array representing Peripherals exposed across all enabled links */ struct sdw_amd_ctx { int count; - int num_slaves; u32 link_mask; - struct sdw_extended_slave_id *ids; struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT]; + struct sdw_peripherals *peripherals; }; /** diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 734dc1fa3b5b..580086417e4b 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -4,6 +4,7 @@ #ifndef __SDW_INTEL_H #define __SDW_INTEL_H +#include <linux/acpi.h> #include <linux/irqreturn.h> #include <linux/soundwire/sdw.h> @@ -286,31 +287,28 @@ struct hdac_bus; * hardware capabilities after all power dependencies are settled. * @link_mask: bit-wise mask listing SoundWire links reported by the * Controller - * @num_slaves: total number of devices exposed across all enabled links * @handle: ACPI parent handle * @ldev: information for each link (controller-specific and kept * opaque here) - * @ids: array of slave_id, representing Slaves exposed across all enabled - * links * @link_list: list to handle interrupts across all links * @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers. * @shim_mask: flags to track initialization of SHIM shared registers * @shim_base: sdw shim base. * @alh_base: sdw alh base. + * @peripherals: array representing Peripherals exposed across all enabled links */ struct sdw_intel_ctx { int count; void __iomem *mmio_base; u32 link_mask; - int num_slaves; acpi_handle handle; struct sdw_intel_link_dev **ldev; - struct sdw_extended_slave_id *ids; struct list_head link_list; struct mutex shim_lock; /* lock for access to shared SHIM registers */ u32 shim_mask; u32 shim_base; u32 alh_base; + struct sdw_peripherals *peripherals; }; /** diff --git a/include/sound/adau1373.h b/include/sound/adau1373.h deleted file mode 100644 index 4c32ba1328ed..000000000000 --- a/include/sound/adau1373.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Analog Devices ADAU1373 Audio Codec drive - * - * Copyright 2011 Analog Devices Inc. - * Author: Lars-Peter Clausen <lars@metafoo.de> - */ - -#ifndef __SOUND_ADAU1373_H__ -#define __SOUND_ADAU1373_H__ - -enum adau1373_micbias_voltage { - ADAU1373_MICBIAS_2_9V = 0, - ADAU1373_MICBIAS_2_2V = 1, - ADAU1373_MICBIAS_2_6V = 2, - ADAU1373_MICBIAS_1_8V = 3, -}; - -#define ADAU1373_DRC_SIZE 13 - -struct adau1373_platform_data { - bool input_differential[4]; - bool lineout_differential; - bool lineout_ground_sense; - - unsigned int num_drc; - uint8_t drc_setting[3][ADAU1373_DRC_SIZE]; - - enum adau1373_micbias_voltage micbias1; - enum adau1373_micbias_voltage micbias2; -}; - -#endif diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index bcf872c17dd3..b55c9eeb2b54 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -20,6 +20,30 @@ struct snd_compr_ops; /** + * struct snd_compr_task_runtime: task runtime description + * @list: list of all managed tasks + * @input: input DMA buffer + * @output: output DMA buffer + * @seqno: sequence number + * @input_size: really used data in the input buffer + * @output_size: really used data in the output buffer + * @flags: see SND_COMPRESS_TFLG_* + * @state: actual task state + * @private_value: used by the lowlevel driver (opaque) + */ +struct snd_compr_task_runtime { + struct list_head list; + struct dma_buf *input; + struct dma_buf *output; + u64 seqno; + u64 input_size; + u64 output_size; + u32 flags; + u8 state; + void *private_value; +}; + +/** * struct snd_compr_runtime: runtime stream description * @state: stream state * @ops: pointer to DSP callbacks @@ -37,6 +61,10 @@ struct snd_compr_ops; * @dma_addr: physical buffer address (not accessible from main CPU) * @dma_bytes: size of DMA area * @dma_buffer_p: runtime dma buffer pointer + * @active_tasks: count of active tasks + * @total_tasks: count of all tasks + * @task_seqno: last task sequence number (!= 0) + * @tasks: list of all tasks */ struct snd_compr_runtime { snd_pcm_state_t state; @@ -54,6 +82,13 @@ struct snd_compr_runtime { dma_addr_t dma_addr; size_t dma_bytes; struct snd_dma_buffer *dma_buffer_p; + +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + u32 active_tasks; + u32 total_tasks; + u64 task_seqno; + struct list_head tasks; +#endif }; /** @@ -108,6 +143,10 @@ struct snd_compr_stream { * Not valid if copy is implemented * @get_caps: Retrieve DSP capabilities, mandatory * @get_codec_caps: Retrieve capabilities for a specific codec, mandatory + * @task_create: Create a set of input/output buffers for accel operations + * @task_start: Start (queue) a task for accel operations + * @task_stop: Stop (dequeue) a task for accel operations + * @task_free: Free a set of input/output buffers for accel operations */ struct snd_compr_ops { int (*open)(struct snd_compr_stream *stream); @@ -132,6 +171,12 @@ struct snd_compr_ops { struct snd_compr_caps *caps); int (*get_codec_caps) (struct snd_compr_stream *stream, struct snd_compr_codec_caps *codec); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + int (*task_create) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task); + int (*task_start) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task); + int (*task_stop) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task); + int (*task_free) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task); +#endif }; /** @@ -242,4 +287,9 @@ int snd_compr_free_pages(struct snd_compr_stream *stream); int snd_compr_stop_error(struct snd_compr_stream *stream, snd_pcm_state_t state); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) +void snd_compr_task_finished(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task); +#endif + #endif diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index 9ced94686ce3..6774f4b9e5fc 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -15,6 +15,7 @@ int hda_bus_ml_init(struct hdac_bus *bus); void hda_bus_ml_free(struct hdac_bus *bus); int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid); +void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable); void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable); bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid); @@ -72,6 +73,9 @@ static inline int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid) { return 0; } static inline void +hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable) { } + +static inline void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable) { } static inline bool diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 5ff31e6d41c1..db1cc0b897fd 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -180,7 +180,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define AZX_INT_ALL_STREAM 0x3fffffff /* all stream interrupts */ #define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ #define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0bf7d25434d7..67c99ffbf51b 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -97,11 +97,11 @@ struct snd_pcm_ops { #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 -#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 3 -#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4 -#define SNDRV_PCM_TRIGGER_SUSPEND 5 -#define SNDRV_PCM_TRIGGER_RESUME 6 -#define SNDRV_PCM_TRIGGER_DRAIN 7 +#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 2 +#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 3 +#define SNDRV_PCM_TRIGGER_SUSPEND 4 +#define SNDRV_PCM_TRIGGER_RESUME 5 +#define SNDRV_PCM_TRIGGER_DRAIN 6 #define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1) @@ -1393,30 +1393,6 @@ snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size); } -/** - * snd_pcm_mmap_data_open - increase the mmap counter - * @area: VMA - * - * PCM mmap callback should handle this counter properly - */ -static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) -{ - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; - atomic_inc(&substream->mmap_count); -} - -/** - * snd_pcm_mmap_data_close - decrease the mmap counter - * @area: VMA - * - * PCM mmap callback should handle this counter properly - */ -static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) -{ - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; - atomic_dec(&substream->mmap_count); -} - int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area); /* mmap for io-memory area */ diff --git a/include/sound/sdca.h b/include/sound/sdca.h new file mode 100644 index 000000000000..7e138229e8f3 --- /dev/null +++ b/include/sound/sdca.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + * + * Copyright(c) 2024 Intel Corporation + */ + +#ifndef __SDCA_H__ +#define __SDCA_H__ + +struct sdw_slave; + +#define SDCA_MAX_FUNCTION_COUNT 8 + +/** + * sdca_device_desc - short descriptor for an SDCA Function + * @adr: ACPI address (used for SDCA register access) + * @type: Function topology type + * @name: human-readable string + */ +struct sdca_function_desc { + u64 adr; + u32 type; + const char *name; +}; + +/** + * sdca_device_data - structure containing all SDCA related information + * @sdca_interface_revision: value read from _DSD property, mainly to check + * for changes between silicon versions + * @num_functions: total number of supported SDCA functions. Invalid/unsupported + * functions will be skipped. + * @sdca_func: array of function descriptors + */ +struct sdca_device_data { + u32 interface_revision; + int num_functions; + struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT]; +}; + +enum sdca_quirk { + SDCA_QUIRKS_RT712_VB, +}; + +#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA) + +void sdca_lookup_functions(struct sdw_slave *slave); +void sdca_lookup_interface_revision(struct sdw_slave *slave); +bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk); + +#else + +static inline void sdca_lookup_functions(struct sdw_slave *slave) {} +static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {} +static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) +{ + return false; +} +#endif + +#endif diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h new file mode 100644 index 000000000000..a01eec86b9a6 --- /dev/null +++ b/include/sound/sdca_function.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + * + * Copyright(c) 2024 Intel Corporation + */ + +#ifndef __SDCA_FUNCTION_H__ +#define __SDCA_FUNCTION_H__ + +/* + * SDCA Function Types from SDCA specification v1.0a Section 5.1.2 + * all Function types not described are reserved + * Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types + * are NOT defined in SDCA 1.0a, but they were defined in earlier + * drafts and are planned for 1.1. + */ + +enum sdca_function_type { + SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */ + SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */ + SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */ + SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */ + SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */ + SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */ + SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */ + SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */ + SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */ + SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */ +}; + +/* Human-readable names used for kernel logs and Function device registration/bind */ +#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp" +#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp" +#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic" +#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic" +#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic" +#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ" +#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ" +#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack" +#define SDCA_FUNCTION_TYPE_HID_NAME "HID" + +enum sdca_entity0_controls { + SDCA_CONTROL_ENTITY_0_COMMIT_GROUP_MASK = 0x01, + SDCA_CONTROL_ENTITY_0_INTSTAT_CLEAR = 0x02, + SDCA_CONTROL_ENTITY_0_INT_ENABLE = 0x03, + SDCA_CONTROL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04, + SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY = 0x05, + SDCA_CONTROL_ENTITY_0_FUNCTION_MANUFACTURER_ID = 0x06, + SDCA_CONTROL_ENTITY_0_FUNCTION_ID = 0x07, + SDCA_CONTROL_ENTITY_0_FUNCTION_VERSION = 0x08 +}; + +#endif diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 60d3b86a4660..72e371a21767 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -185,6 +185,10 @@ struct snd_soc_acpi_link_adr { * ACPI ID alone is not sufficient, wrong or misleading * @quirk_data: data used to uniquely identify a machine, usually a list of * audio codecs whose presence if checked with ACPI + * @machine_check: pointer to quirk function. The functionality is similar to + * the use of @machine_quirk, except that the return value is a boolean: the intent + * is to skip a machine if the additional hardware/firmware verification invalidates + * the initial selection in the snd_soc_acpi_mach table. * @pdata: intended for platform data or machine specific-ops. This structure * is not constant since this field may be updated at run-time * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled @@ -203,6 +207,7 @@ struct snd_soc_acpi_mach { const char *board; struct snd_soc_acpi_mach * (*machine_quirk)(void *arg); const void *quirk_data; + bool (*machine_check)(void *arg); void *pdata; struct snd_soc_acpi_mach_params mach_params; const char *sof_tplg_filename; @@ -233,7 +238,6 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev) bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, const struct snd_soc_acpi_link_adr *link, - struct sdw_extended_slave_id *ids, - int num_slaves); + struct sdw_peripherals *peripherals); #endif diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 0d1b215f24f4..aab57c19f62b 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -216,8 +216,7 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int rollback); void snd_soc_dai_suspend(struct snd_soc_dai *dai); 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); +int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd); bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream); void snd_soc_dai_action(struct snd_soc_dai *dai, int stream, int action); @@ -275,7 +274,7 @@ struct snd_soc_dai_ops { int (*probe)(struct snd_soc_dai *dai); int (*remove)(struct snd_soc_dai *dai); /* compress dai */ - int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num); + int (*compress_new)(struct snd_soc_pcm_runtime *rtd); /* Optional Callback used at pcm creation*/ int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); @@ -450,9 +449,9 @@ struct snd_soc_dai { struct snd_soc_dai_stream stream[SNDRV_PCM_STREAM_LAST + 1]; /* Symmetry data - only valid if symmetry is being enforced */ - unsigned int rate; - unsigned int channels; - unsigned int sample_bits; + unsigned int symmetric_rate; + unsigned int symmetric_channels; + unsigned int symmetric_sample_bits; /* parent platform/codec */ struct snd_soc_component *component; diff --git a/include/sound/soc.h b/include/sound/soc.h index e6e359c1a2ac..4f5d411e3823 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -486,11 +486,11 @@ struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev, struct snd_soc_component *snd_soc_lookup_component(struct device *dev, const char *driver_name); -int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); +int soc_new_pcm(struct snd_soc_pcm_runtime *rtd); #ifdef CONFIG_SND_SOC_COMPRESS -int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); +int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd); #else -static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) +static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd) { return 0; } @@ -541,8 +541,13 @@ int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params, int tdm_width, int tdm_slots, int slot_multiple); /* set runtime hw params */ -int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, - const struct snd_pcm_hardware *hw); +static inline int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, + const struct snd_pcm_hardware *hw) +{ + substream->runtime->hw = *hw; + + return 0; +} struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component); struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, @@ -815,11 +820,6 @@ 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; - /* DPCM used FE & BE merged format */ unsigned int dpcm_merged_format:1; /* DPCM used FE & BE merged channel */ @@ -1195,7 +1195,7 @@ struct snd_soc_pcm_runtime { struct dentry *debugfs_dpcm_root; #endif - unsigned int num; /* 0-based and monotonic increasing */ + unsigned int id; /* 0-based and monotonic increasing */ struct list_head list; /* rtd list of the soc card */ /* function mark */ @@ -1438,10 +1438,6 @@ struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_a struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, bool legacy_dai_naming); -struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev, - struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming); void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index f68c1f193b3b..0e82598e10af 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -28,6 +28,7 @@ * - SOC_SDW_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported */ #define SOC_SDW_SIDECAR_AMPS BIT(16) +#define SOC_SDW_CODEC_MIC BIT(17) #define SOC_SDW_UNUSED_DAI_ID -1 #define SOC_SDW_JACK_OUT_DAI_ID 0 @@ -59,6 +60,7 @@ struct asoc_sdw_dai_info { 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; + bool quirk_exclude; }; struct asoc_sdw_codec_info { @@ -150,14 +152,15 @@ void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_lin 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), + int codecs_num, int no_pcm, + 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, + const char *codec_dai_name, int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops); @@ -234,8 +237,7 @@ int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s 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_rt_mf_sdca_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); diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index fc0231d04a94..7dfe3ccf1fe4 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -60,6 +60,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_FW_VERSION = 0, SOF_EXT_MAN_ELEM_WINDOW = 1, SOF_EXT_MAN_ELEM_CC_VERSION = 2, + SOF_EXT_MAN_ELEM_PROBE_INFO = 3, SOF_EXT_MAN_ELEM_DBG_ABI = 4, SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA = 6, diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index d185957f3fe0..d62eb93af0ed 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -14,7 +14,7 @@ #include <sound/compress_params.h> -#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 2, 0) +#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 0) /** * struct snd_compressed_buffer - compressed buffer * @fragment_size: size of buffer fragment in bytes @@ -68,7 +68,8 @@ struct snd_compr_avail { enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, - SND_COMPRESS_CAPTURE + SND_COMPRESS_CAPTURE, + SND_COMPRESS_ACCEL }; /** @@ -127,6 +128,59 @@ struct snd_compr_metadata { __u32 value[8]; } __attribute__((packed, aligned(4))); +/* flags for struct snd_compr_task */ +#define SND_COMPRESS_TFLG_NEW_STREAM (1<<0) /* mark for the new stream data */ + +/** + * struct snd_compr_task - task primitive for non-realtime operation + * @seqno: sequence number (task identifier) + * @origin_seqno: previous sequence number (task identifier) - for reuse + * @input_fd: data input file descriptor (dma-buf) + * @output_fd: data output file descriptor (dma-buf) + * @input_size: filled data in bytes (from caller, must not exceed fragment size) + * @flags: see SND_COMPRESS_TFLG_* defines + * @reserved: reserved for future extension + */ +struct snd_compr_task { + __u64 seqno; + __u64 origin_seqno; + int input_fd; + int output_fd; + __u64 input_size; + __u32 flags; + __u8 reserved[16]; +} __attribute__((packed, aligned(4))); + +/** + * enum snd_compr_state - task state + * @SND_COMPRESS_TASK_STATE_IDLE: task is not queued + * @SND_COMPRESS_TASK_STATE_ACTIVE: task is in the queue + * @SND_COMPRESS_TASK_STATE_FINISHED: task was processed, output is available + */ +enum snd_compr_state { + SND_COMPRESS_TASK_STATE_IDLE = 0, + SND_COMPRESS_TASK_STATE_ACTIVE, + SND_COMPRESS_TASK_STATE_FINISHED +}; + +/** + * struct snd_compr_task_status - task status + * @seqno: sequence number (task identifier) + * @input_size: filled data in bytes (from user space) + * @output_size: filled data in bytes (from driver) + * @output_flags: reserved for future (all zeros - from driver) + * @state: actual task state (SND_COMPRESS_TASK_STATE_*) + * @reserved: reserved for future extension + */ +struct snd_compr_task_status { + __u64 seqno; + __u64 input_size; + __u64 output_size; + __u32 output_flags; + __u8 state; + __u8 reserved[15]; +} __attribute__((packed, aligned(4))); + /* * compress path ioctl definitions * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP @@ -164,6 +218,14 @@ struct snd_compr_metadata { #define SNDRV_COMPRESS_DRAIN _IO('C', 0x34) #define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35) #define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36) + + +#define SNDRV_COMPRESS_TASK_CREATE _IOWR('C', 0x60, struct snd_compr_task) +#define SNDRV_COMPRESS_TASK_FREE _IOW('C', 0x61, __u64) +#define SNDRV_COMPRESS_TASK_START _IOWR('C', 0x62, struct snd_compr_task) +#define SNDRV_COMPRESS_TASK_STOP _IOW('C', 0x63, __u64) +#define SNDRV_COMPRESS_TASK_STATUS _IOWR('C', 0x68, struct snd_compr_task_status) + /* * TODO * 1. add mmap support diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 4c367e73b2c9..77b11616a7ee 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -271,7 +271,7 @@ static void pxa2xx_ac97_remove(struct platform_device *dev) static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_probe, - .remove_new = pxa2xx_ac97_remove, + .remove = pxa2xx_ac97_remove, .driver = { .name = "pxa2xx-ac97", .pm = &pxa2xx_ac97_pm_ops, diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 402b5f66dcc3..d8f8e08f1bb7 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -861,7 +861,7 @@ static void atmel_ac97c_remove(struct platform_device *pdev) static struct platform_driver atmel_ac97c_driver = { .probe = atmel_ac97c_probe, - .remove_new = atmel_ac97c_remove, + .remove = atmel_ac97c_remove, .driver = { .name = "atmel_ac97c", .pm = ATMEL_AC97C_PM_OPS, diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 2c5b9f964703..48db44fa56fe 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -59,6 +59,9 @@ config SND_CORE_TEST config SND_COMPRESS_OFFLOAD tristate +config SND_COMPRESS_ACCEL + bool + config SND_JACK bool diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index bdf1d78de833..86ed2fbee0c8 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -24,6 +24,7 @@ #include <linux/types.h> #include <linux/uio.h> #include <linux/uaccess.h> +#include <linux/dma-buf.h> #include <linux/module.h> #include <linux/compat.h> #include <sound/core.h> @@ -54,6 +55,12 @@ struct snd_compr_file { static void error_delayed_work(struct work_struct *work); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) +static void snd_compr_task_free_all(struct snd_compr_stream *stream); +#else +static inline void snd_compr_task_free_all(struct snd_compr_stream *stream) { } +#endif + /* * a note on stream states used: * we use following states in the compressed core @@ -85,6 +92,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) dirn = SND_COMPRESS_PLAYBACK; else if ((f->f_flags & O_ACCMODE) == O_RDONLY) dirn = SND_COMPRESS_CAPTURE; + else if ((f->f_flags & O_ACCMODE) == O_RDWR) + dirn = SND_COMPRESS_ACCEL; else return -EINVAL; @@ -125,6 +134,9 @@ static int snd_compr_open(struct inode *inode, struct file *f) } runtime->state = SNDRV_PCM_STATE_OPEN; init_waitqueue_head(&runtime->sleep); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + INIT_LIST_HEAD(&runtime->tasks); +#endif data->stream.runtime = runtime; f->private_data = (void *)data; scoped_guard(mutex, &compr->lock) @@ -154,6 +166,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) break; } + snd_compr_task_free_all(&data->stream); + data->stream.ops->free(&data->stream); if (!data->stream.runtime->dma_buffer_p) kfree(data->stream.runtime->buffer); @@ -226,6 +240,9 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) struct snd_compr_avail ioctl_avail; size_t avail; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; + avail = snd_compr_calc_avail(stream, &ioctl_avail); ioctl_avail.avail = avail; @@ -287,6 +304,8 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, return -EFAULT; stream = &data->stream; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; guard(mutex)(&stream->device->lock); /* write is allowed when stream is running or has been setup */ switch (stream->runtime->state) { @@ -336,6 +355,8 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, return -EFAULT; stream = &data->stream; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; guard(mutex)(&stream->device->lock); /* read is allowed when stream is running, paused, draining and setup @@ -385,6 +406,7 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) { struct snd_compr_file *data = f->private_data; struct snd_compr_stream *stream; + struct snd_compr_runtime *runtime; size_t avail; __poll_t retval = 0; @@ -392,10 +414,11 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) return EPOLLERR; stream = &data->stream; + runtime = stream->runtime; guard(mutex)(&stream->device->lock); - switch (stream->runtime->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_XRUN: return snd_compr_get_poll(stream) | EPOLLERR; @@ -403,23 +426,37 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) break; } - poll_wait(f, &stream->runtime->sleep, wait); + poll_wait(f, &runtime->sleep, wait); + +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + if (stream->direction == SND_COMPRESS_ACCEL) { + struct snd_compr_task_runtime *task; + if (runtime->fragments > runtime->active_tasks) + retval |= EPOLLOUT | EPOLLWRNORM; + task = list_first_entry_or_null(&runtime->tasks, + struct snd_compr_task_runtime, + list); + if (task && task->state == SND_COMPRESS_TASK_STATE_FINISHED) + retval |= EPOLLIN | EPOLLRDNORM; + return retval; + } +#endif avail = snd_compr_get_avail(stream); pr_debug("avail is %ld\n", (unsigned long)avail); /* check if we have at least one fragment to fill */ - switch (stream->runtime->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_DRAINING: /* stream has been woken up after drain is complete * draining done so set stream state to stopped */ retval = snd_compr_get_poll(stream); - stream->runtime->state = SNDRV_PCM_STATE_SETUP; + runtime->state = SNDRV_PCM_STATE_SETUP; break; case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: - if (avail >= stream->runtime->fragment_size) + if (avail >= runtime->fragment_size) retval = snd_compr_get_poll(stream); break; default: @@ -521,6 +558,9 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, unsigned int buffer_size; void *buffer = NULL; + if (stream->direction == SND_COMPRESS_ACCEL) + goto params; + buffer_size = params->buffer.fragment_size * params->buffer.fragments; if (stream->ops->copy) { buffer = NULL; @@ -543,18 +583,30 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, if (!buffer) return -ENOMEM; } - stream->runtime->fragment_size = params->buffer.fragment_size; - stream->runtime->fragments = params->buffer.fragments; + stream->runtime->buffer = buffer; stream->runtime->buffer_size = buffer_size; +params: + stream->runtime->fragment_size = params->buffer.fragment_size; + stream->runtime->fragments = params->buffer.fragments; return 0; } -static int snd_compress_check_input(struct snd_compr_params *params) +static int +snd_compress_check_input(struct snd_compr_stream *stream, struct snd_compr_params *params) { + u32 max_fragments; + /* first let's check the buffer parameter's */ - if (params->buffer.fragment_size == 0 || - params->buffer.fragments > U32_MAX / params->buffer.fragment_size || + if (params->buffer.fragment_size == 0) + return -EINVAL; + + if (stream->direction == SND_COMPRESS_ACCEL) + max_fragments = 64; /* safe value */ + else + max_fragments = U32_MAX / params->buffer.fragment_size; + + if (params->buffer.fragments > max_fragments || params->buffer.fragments == 0) return -EINVAL; @@ -583,7 +635,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) if (IS_ERR(params)) return PTR_ERR(params); - retval = snd_compress_check_input(params); + retval = snd_compress_check_input(stream, params); if (retval) return retval; @@ -939,6 +991,264 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream) return snd_compress_wait_for_drain(stream); } +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + +static struct snd_compr_task_runtime * +snd_compr_find_task(struct snd_compr_stream *stream, __u64 seqno) +{ + struct snd_compr_task_runtime *task; + + list_for_each_entry(task, &stream->runtime->tasks, list) { + if (task->seqno == seqno) + return task; + } + return NULL; +} + +static void snd_compr_task_free(struct snd_compr_task_runtime *task) +{ + if (task->output) + dma_buf_put(task->output); + if (task->input) + dma_buf_put(task->input); + kfree(task); +} + +static u64 snd_compr_seqno_next(struct snd_compr_stream *stream) +{ + u64 seqno = ++stream->runtime->task_seqno; + if (seqno == 0) + seqno = ++stream->runtime->task_seqno; + return seqno; +} + +static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_task *utask) +{ + struct snd_compr_task_runtime *task; + int retval; + + if (stream->runtime->total_tasks >= stream->runtime->fragments) + return -EBUSY; + if (utask->origin_seqno != 0 || utask->input_size != 0) + return -EINVAL; + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (task == NULL) + return -ENOMEM; + task->seqno = utask->seqno = snd_compr_seqno_next(stream); + task->input_size = utask->input_size; + retval = stream->ops->task_create(stream, task); + if (retval < 0) + goto cleanup; + utask->input_fd = dma_buf_fd(task->input, O_WRONLY|O_CLOEXEC); + if (utask->input_fd < 0) { + retval = utask->input_fd; + goto cleanup; + } + utask->output_fd = dma_buf_fd(task->output, O_RDONLY|O_CLOEXEC); + if (utask->output_fd < 0) { + retval = utask->output_fd; + goto cleanup; + } + /* keep dmabuf reference until freed with task free ioctl */ + dma_buf_get(utask->input_fd); + dma_buf_get(utask->output_fd); + list_add_tail(&task->list, &stream->runtime->tasks); + stream->runtime->total_tasks++; + return 0; +cleanup: + snd_compr_task_free(task); + return retval; +} + +static int snd_compr_task_create(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + task = memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(no_free_ptr(task)); + retval = snd_compr_task_new(stream, task); + if (retval >= 0) + if (copy_to_user((void __user *)arg, task, sizeof(*task))) + retval = -EFAULT; + return retval; +} + +static int snd_compr_task_start_prepare(struct snd_compr_task_runtime *task, + struct snd_compr_task *utask) +{ + if (task == NULL) + return -EINVAL; + if (task->state >= SND_COMPRESS_TASK_STATE_FINISHED) + return -EBUSY; + if (utask->input_size > task->input->size) + return -EINVAL; + task->flags = utask->flags; + task->input_size = utask->input_size; + task->state = SND_COMPRESS_TASK_STATE_IDLE; + return 0; +} + +static int snd_compr_task_start(struct snd_compr_stream *stream, struct snd_compr_task *utask) +{ + struct snd_compr_task_runtime *task; + int retval; + + if (utask->origin_seqno > 0) { + task = snd_compr_find_task(stream, utask->origin_seqno); + retval = snd_compr_task_start_prepare(task, utask); + if (retval < 0) + return retval; + task->seqno = utask->seqno = snd_compr_seqno_next(stream); + utask->origin_seqno = 0; + list_move_tail(&task->list, &stream->runtime->tasks); + } else { + task = snd_compr_find_task(stream, utask->seqno); + if (task && task->state != SND_COMPRESS_TASK_STATE_IDLE) + return -EBUSY; + retval = snd_compr_task_start_prepare(task, utask); + if (retval < 0) + return retval; + } + retval = stream->ops->task_start(stream, task); + if (retval >= 0) { + task->state = SND_COMPRESS_TASK_STATE_ACTIVE; + stream->runtime->active_tasks++; + } + return retval; +} + +static int snd_compr_task_start_ioctl(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + task = memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(no_free_ptr(task)); + retval = snd_compr_task_start(stream, task); + if (retval >= 0) + if (copy_to_user((void __user *)arg, task, sizeof(*task))) + retval = -EFAULT; + return retval; +} + +static void snd_compr_task_stop_one(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + if (task->state != SND_COMPRESS_TASK_STATE_ACTIVE) + return; + stream->ops->task_stop(stream, task); + if (!snd_BUG_ON(stream->runtime->active_tasks == 0)) + stream->runtime->active_tasks--; + list_move_tail(&task->list, &stream->runtime->tasks); + task->state = SND_COMPRESS_TASK_STATE_IDLE; +} + +static void snd_compr_task_free_one(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + snd_compr_task_stop_one(stream, task); + stream->ops->task_free(stream, task); + list_del(&task->list); + snd_compr_task_free(task); + stream->runtime->total_tasks--; +} + +static void snd_compr_task_free_all(struct snd_compr_stream *stream) +{ + struct snd_compr_task_runtime *task, *temp; + + list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list) + snd_compr_task_free_one(stream, task); +} + +typedef void (*snd_compr_seq_func_t)(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task); + +static int snd_compr_task_seq(struct snd_compr_stream *stream, unsigned long arg, + snd_compr_seq_func_t fcn) +{ + struct snd_compr_task_runtime *task; + __u64 seqno; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + retval = get_user(seqno, (__u64 __user *)arg); + if (retval < 0) + return retval; + retval = 0; + if (seqno == 0) { + list_for_each_entry_reverse(task, &stream->runtime->tasks, list) + fcn(stream, task); + } else { + task = snd_compr_find_task(stream, seqno); + if (task == NULL) { + retval = -EINVAL; + } else { + fcn(stream, task); + } + } + return retval; +} + +static int snd_compr_task_status(struct snd_compr_stream *stream, + struct snd_compr_task_status *status) +{ + struct snd_compr_task_runtime *task; + + task = snd_compr_find_task(stream, status->seqno); + if (task == NULL) + return -EINVAL; + status->input_size = task->input_size; + status->output_size = task->output_size; + status->state = task->state; + return 0; +} + +static int snd_compr_task_status_ioctl(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task_status *status __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + status = memdup_user((void __user *)arg, sizeof(*status)); + if (IS_ERR(status)) + return PTR_ERR(no_free_ptr(status)); + retval = snd_compr_task_status(stream, status); + if (retval >= 0) + if (copy_to_user((void __user *)arg, status, sizeof(*status))) + retval = -EFAULT; + return retval; +} + +/** + * snd_compr_task_finished: Notify that the task was finished + * @stream: pointer to stream + * @task: runtime task structure + * + * Set the finished task state and notify waiters. + */ +void snd_compr_task_finished(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + guard(mutex)(&stream->device->lock); + if (!snd_BUG_ON(stream->runtime->active_tasks == 0)) + stream->runtime->active_tasks--; + task->state = SND_COMPRESS_TASK_STATE_FINISHED; + wake_up(&stream->runtime->sleep); +} +EXPORT_SYMBOL_GPL(snd_compr_task_finished); + +#endif /* CONFIG_SND_COMPRESS_ACCEL */ + static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { struct snd_compr_file *data = f->private_data; @@ -968,6 +1278,27 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return snd_compr_set_metadata(stream, arg); case _IOC_NR(SNDRV_COMPRESS_GET_METADATA): return snd_compr_get_metadata(stream, arg); + } + + if (stream->direction == SND_COMPRESS_ACCEL) { +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + switch (_IOC_NR(cmd)) { + case _IOC_NR(SNDRV_COMPRESS_TASK_CREATE): + return snd_compr_task_create(stream, arg); + case _IOC_NR(SNDRV_COMPRESS_TASK_FREE): + return snd_compr_task_seq(stream, arg, snd_compr_task_free_one); + case _IOC_NR(SNDRV_COMPRESS_TASK_START): + return snd_compr_task_start_ioctl(stream, arg); + case _IOC_NR(SNDRV_COMPRESS_TASK_STOP): + return snd_compr_task_seq(stream, arg, snd_compr_task_stop_one); + case _IOC_NR(SNDRV_COMPRESS_TASK_STATUS): + return snd_compr_task_status_ioctl(stream, arg); + } +#endif + return -ENOTTY; + } + + switch (_IOC_NR(cmd)) { case _IOC_NR(SNDRV_COMPRESS_TSTAMP): return snd_compr_tstamp(stream, arg); case _IOC_NR(SNDRV_COMPRESS_AVAIL): @@ -1140,6 +1471,11 @@ int snd_compress_new(struct snd_card *card, int device, }; int ret; +#if !IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + if (snd_BUG_ON(dirn == SND_COMPRESS_ACCEL)) + return -EINVAL; +#endif + compr->card = card; compr->device = device; compr->direction = dirn; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 3320cce35a03..b44d205cc838 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3774,6 +3774,26 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file #endif /* coherent mmap */ /* + * snd_pcm_mmap_data_open - increase the mmap counter + */ +static void snd_pcm_mmap_data_open(struct vm_area_struct *area) +{ + struct snd_pcm_substream *substream = area->vm_private_data; + + atomic_inc(&substream->mmap_count); +} + +/* + * snd_pcm_mmap_data_close - decrease the mmap counter + */ +static void snd_pcm_mmap_data_close(struct vm_area_struct *area) +{ + struct snd_pcm_substream *substream = area->vm_private_data; + + atomic_dec(&substream->mmap_count); +} + +/* * fault callback for mmapping a RAM page */ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) diff --git a/sound/core/ump.c b/sound/core/ump.c index 7d59a0a9b037..5d4dd207e5ab 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -366,7 +366,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, { struct snd_ump_block *fb, *p; - if (blk < 0 || blk >= SNDRV_UMP_MAX_BLOCKS) + if (blk >= SNDRV_UMP_MAX_BLOCKS) return -EINVAL; if (snd_ump_get_block(ump, blk)) @@ -387,7 +387,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, fb->info.first_group = first_group; fb->info.num_groups = num_groups; /* fill the default name, may be overwritten to a better name */ - snprintf(fb->info.name, sizeof(fb->info.name), "Group %d-%d", + snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u", first_group + 1, first_group + num_groups); /* put the entry in the ordered list */ diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 6fc255a6754d..17f215bad0ec 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -1008,7 +1008,7 @@ static void snd_mts64_remove(struct platform_device *pdev) static struct platform_driver snd_mts64_driver = { .probe = snd_mts64_probe, - .remove_new = snd_mts64_remove, + .remove = snd_mts64_remove, .driver = { .name = PLATFORM_DRIVER, } diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 21cefaf5419a..72378f354fd0 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -640,7 +640,7 @@ static struct platform_device pcmtst_pdev = { static struct platform_driver pcmtst_pdrv = { .probe = pcmtst_probe, - .remove_new = pdev_remove, + .remove = pdev_remove, .driver = { .name = "pcmtest", }, diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 54d818d2f53d..5e4ef25a83a4 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -794,7 +794,7 @@ static void snd_portman_remove(struct platform_device *pdev) static struct platform_driver snd_portman_driver = { .probe = snd_portman_probe, - .remove_new = snd_portman_remove, + .remove = snd_portman_remove, .driver = { .name = PLATFORM_DRIVER, } diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index b596bec19774..f5028a061a91 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -333,53 +333,6 @@ retry_after_bus_reset: } EXPORT_SYMBOL(cmp_connection_establish); -/** - * cmp_connection_update - update the connection after a bus reset - * @c: the connection manager - * - * This function must be called from the driver's .update handler to - * reestablish any connection that might have been active. - * - * Returns zero on success, or a negative error code. On an error, the - * connection is broken and the caller must stop transmitting iso packets. - */ -int cmp_connection_update(struct cmp_connection *c) -{ - int err; - - mutex_lock(&c->mutex); - - if (!c->connected) { - mutex_unlock(&c->mutex); - return 0; - } - - err = fw_iso_resources_update(&c->resources); - if (err < 0) - goto err_unconnect; - - if (c->direction == CMP_OUTPUT) - err = pcr_modify(c, opcr_set_modify, pcr_set_check, - SUCCEED_ON_BUS_RESET); - else - err = pcr_modify(c, ipcr_set_modify, pcr_set_check, - SUCCEED_ON_BUS_RESET); - - if (err < 0) - goto err_unconnect; - - mutex_unlock(&c->mutex); - - return 0; - -err_unconnect: - c->connected = false; - mutex_unlock(&c->mutex); - - return err; -} -EXPORT_SYMBOL(cmp_connection_update); - static __be32 pcr_break_modify(struct cmp_connection *c, __be32 pcr) { return pcr & ~cpu_to_be32(PCR_BCAST_CONN | PCR_P2P_CONN_MASK); diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h index 26ab88000e34..66fc08b742d2 100644 --- a/sound/firewire/cmp.h +++ b/sound/firewire/cmp.h @@ -47,7 +47,6 @@ int cmp_connection_reserve(struct cmp_connection *connection, void cmp_connection_release(struct cmp_connection *connection); int cmp_connection_establish(struct cmp_connection *connection); -int cmp_connection_update(struct cmp_connection *connection); void cmp_connection_break(struct cmp_connection *connection); #endif diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 3c26334227bb..991793e6bda9 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -886,7 +886,7 @@ static void hal2_remove(struct platform_device *pdev) static struct platform_driver hal2_driver = { .probe = hal2_probe, - .remove_new = hal2_remove, + .remove = hal2_remove, .driver = { .name = "sgihal2", } diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index a8551ccdd1bf..4e2ff954ff59 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -917,8 +917,8 @@ static void snd_sgio2audio_remove(struct platform_device *pdev) static struct platform_driver sgio2audio_driver = { .probe = snd_sgio2audio_probe, - .remove_new = snd_sgio2audio_remove, - .driver = { + .remove = snd_sgio2audio_remove, + .driver = { .name = "sgio2audio", } }; diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index b8fad12f9e5f..8d443a3663d3 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -732,7 +732,7 @@ static void __exit amiga_audio_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_audio_driver __refdata = { - .remove_new = __exit_p(amiga_audio_remove), + .remove = __exit_p(amiga_audio_remove), .driver = { .name = "amiga-audio", }, diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7c6b1fe8dfcc..8e74be038b0f 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -956,6 +956,28 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); +/* check whether the given quirk entry matches with vendor/device pair */ +static bool hda_quirk_match(u16 vendor, u16 device, const struct hda_quirk *q) +{ + if (q->subvendor != vendor) + return false; + return !q->subdevice || + (device & q->subdevice_mask) == q->subdevice; +} + +/* look through the quirk list and return the matching entry */ +static const struct hda_quirk * +hda_quirk_lookup_id(u16 vendor, u16 device, const struct hda_quirk *list) +{ + const struct hda_quirk *q; + + for (q = list; q->subvendor || q->subdevice; q++) { + if (hda_quirk_match(vendor, device, q)) + return q; + } + return NULL; +} + /** * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string * @codec: the HDA codec @@ -975,14 +997,16 @@ EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); */ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, + const struct hda_quirk *quirk, const struct hda_fixup *fixlist) { - const struct snd_pci_quirk *q; + const struct hda_quirk *q; int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; const char *type = NULL; unsigned int vendor, device; + u16 pci_vendor, pci_device; + u16 codec_vendor, codec_device; if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; @@ -1013,27 +1037,42 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (!quirk) return; + if (codec->bus->pci) { + pci_vendor = codec->bus->pci->subsystem_vendor; + pci_device = codec->bus->pci->subsystem_device; + } + + codec_vendor = codec->core.subsystem_id >> 16; + codec_device = codec->core.subsystem_id & 0xffff; + /* match with the SSID alias given by the model string "XXXX:YYYY" */ if (codec->modelname && sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) { - q = snd_pci_quirk_lookup_id(vendor, device, quirk); + q = hda_quirk_lookup_id(vendor, device, quirk); if (q) { type = "alias SSID"; goto found_device; } } - /* match with the PCI SSID */ - q = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (q) { - type = "PCI SSID"; - goto found_device; + /* match primarily with the PCI SSID */ + for (q = quirk; q->subvendor || q->subdevice; q++) { + /* if the entry is specific to codec SSID, check with it */ + if (!codec->bus->pci || q->match_codec_ssid) { + if (hda_quirk_match(codec_vendor, codec_device, q)) { + type = "codec SSID"; + goto found_device; + } + } else { + if (hda_quirk_match(pci_vendor, pci_device, q)) { + type = "PCI SSID"; + goto found_device; + } + } } /* match with the codec SSID */ - q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16, - codec->core.subsystem_id & 0xffff, - quirk); + q = hda_quirk_lookup_id(codec_vendor, codec_device, quirk); if (q) { type = "codec SSID"; goto found_device; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b4540c5cd2a6..4a62440adfaf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -773,6 +773,14 @@ static void azx_clear_irq_pending(struct azx *chip) static int azx_acquire_irq(struct azx *chip, int do_disconnect) { struct hdac_bus *bus = azx_bus(chip); + int ret; + + if (!chip->msi || pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_MSI) < 0) { + ret = pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_INTX); + if (ret < 0) + return ret; + chip->msi = 0; + } if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, @@ -786,7 +794,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) } bus->irq = chip->pci->irq; chip->card->sync_irq = bus->irq; - pci_intx(chip->pci, !chip->msi); return 0; } @@ -1032,22 +1039,12 @@ static int azx_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hdac_bus *bus; if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - bus = azx_bus(chip); azx_shutdown_chip(chip); - if (bus->irq >= 0) { - free_irq(bus->irq, chip); - bus->irq = -1; - chip->card->sync_irq = -1; - } - - if (chip->msi) - pci_disable_msi(chip->pci); trace_azx_suspend(chip); return 0; @@ -1062,11 +1059,6 @@ static int __maybe_unused azx_resume(struct device *dev) return 0; chip = card->private_data; - if (chip->msi) - if (pci_enable_msi(chip->pci) < 0) - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) - return -EIO; __azx_runtime_resume(chip); @@ -1867,6 +1859,8 @@ static int azx_first_init(struct azx *chip) bus->polling_mode = 1; bus->not_use_interrupts = 1; bus->access_sdnctl_in_dword = 1; + if (!chip->jackpoll_interval) + chip->jackpoll_interval = msecs_to_jiffies(1500); } err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio"); @@ -1892,13 +1886,9 @@ static int azx_first_init(struct azx *chip) chip->gts_present = true; #endif - if (chip->msi) { - if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { - dev_dbg(card->dev, "Disabling 64bit MSI\n"); - pci->no_64bit_msi = true; - } - if (pci_enable_msi(pci) < 0) - chip->msi = 0; + if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { + dev_dbg(card->dev, "Disabling 64bit MSI\n"); + pci->no_64bit_msi = true; } pci_set_master(pci); @@ -2050,7 +2040,7 @@ static int disable_msi_reset_irq(struct azx *chip) free_irq(bus->irq, chip); bus->irq = -1; chip->card->sync_irq = -1; - pci_disable_msi(chip->pci); + pci_free_irq_vectors(chip->pci); chip->msi = 0; err = azx_acquire_irq(chip, 1); if (err < 0) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 53a5a62b78fa..763f79f6f32e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -292,6 +292,32 @@ struct hda_fixup { } v; }; +/* + * extended form of snd_pci_quirk: + * for PCI SSID matching, use SND_PCI_QUIRK() like before; + * for codec SSID matching, use the new HDA_CODEC_QUIRK() instead + */ +struct hda_quirk { + unsigned short subvendor; /* PCI subvendor ID */ + unsigned short subdevice; /* PCI subdevice ID */ + unsigned short subdevice_mask; /* bitmask to match */ + bool match_codec_ssid; /* match only with codec SSID */ + int value; /* value */ +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *name; /* name of the device (optional) */ +#endif +}; + +#ifdef CONFIG_SND_DEBUG_VERBOSE +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname),\ + .match_codec_ssid = true } +#else +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), \ + .match_codec_ssid = true } +#endif + struct snd_hda_pin_quirk { unsigned int codec; /* Codec vendor/device ID */ unsigned short subvendor; /* PCI subvendor ID */ @@ -351,7 +377,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action); void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth); void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, + const struct hda_quirk *quirk, const struct hda_fixup *fixlist); void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index d967e70a7058..b1e30a83dfb0 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -606,7 +606,7 @@ static struct platform_driver tegra_platform_hda = { .of_match_table = hda_tegra_match, }, .probe = hda_tegra_probe, - .remove_new = hda_tegra_remove, + .remove = hda_tegra_remove, .shutdown = hda_tegra_shutdown, }; module_platform_driver(tegra_platform_hda); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1e9dadcdc51b..56354fe060a1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -345,7 +345,7 @@ static const struct hda_fixup ad1986a_fixups[] = { }, }; -static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { +static const struct hda_quirk ad1986a_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD), @@ -588,7 +588,7 @@ static const struct hda_fixup ad1981_fixups[] = { }, }; -static const struct snd_pci_quirk ad1981_fixup_tbl[] = { +static const struct hda_quirk ad1981_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), @@ -1061,7 +1061,7 @@ static const struct hda_fixup ad1884_fixups[] = { }, }; -static const struct snd_pci_quirk ad1884_fixup_tbl[] = { +static const struct hda_quirk ad1884_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD), diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 654724559355..06e046214a41 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -385,7 +385,7 @@ static const struct hda_model_fixup cs420x_models[] = { {} }; -static const struct snd_pci_quirk cs420x_fixup_tbl[] = { +static const struct hda_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), @@ -634,13 +634,13 @@ static const struct hda_model_fixup cs4208_models[] = { {} }; -static const struct snd_pci_quirk cs4208_fixup_tbl[] = { +static const struct hda_quirk cs4208_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), {} /* terminator */ }; /* codec SSID matching */ -static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { +static const struct hda_quirk cs4208_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), @@ -818,7 +818,7 @@ static const struct hda_model_fixup cs421x_models[] = { {} }; -static const struct snd_pci_quirk cs421x_fixup_tbl[] = { +static const struct hda_quirk cs421x_fixup_tbl[] = { /* Test Intel board + CDB2410 */ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), {} /* terminator */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b2bcdf76da30..2e9f817b948e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -828,23 +828,6 @@ static const struct hda_pintbl cxt_pincfg_sws_js201d[] = { {} }; -/* pincfg quirk for Tuxedo Sirius; - * unfortunately the (PCI) SSID conflicts with System76 Pangolin pang14, - * which has incompatible pin setup, so we check the codec SSID (luckily - * different one!) and conditionally apply the quirk here - */ -static void cxt_fixup_sirius_top_speaker(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - /* ignore for incorrectly picked-up pang14 */ - if (codec->core.subsystem_id == 0x278212b3) - return; - /* set up the top speaker pin */ - if (action == HDA_FIXUP_ACT_PRE_PROBE) - snd_hda_codec_set_pincfg(codec, 0x1d, 0x82170111); -} - static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -1009,12 +992,15 @@ static const struct hda_fixup cxt_fixups[] = { .v.pins = cxt_pincfg_sws_js201d, }, [CXT_PINCFG_TOP_SPEAKER] = { - .type = HDA_FIXUP_FUNC, - .v.func = cxt_fixup_sirius_top_speaker, + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1d, 0x82170111 }, + { } + }, }, }; -static const struct snd_pci_quirk cxt5045_fixups[] = { +static const struct hda_quirk cxt5045_fixups[] = { SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105), /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have @@ -1034,7 +1020,7 @@ static const struct hda_model_fixup cxt5045_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5047_fixups[] = { +static const struct hda_quirk cxt5047_fixups[] = { /* HP laptops have really bad sound over 0 dB on NID 0x10. */ SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047), @@ -1046,7 +1032,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5051_fixups[] = { +static const struct hda_quirk cxt5051_fixups[] = { SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), {} @@ -1057,7 +1043,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5066_fixups[] = { +static const struct hda_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), @@ -1109,8 +1095,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), - SND_PCI_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER), - SND_PCI_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER), + HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER), + HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER), {} }; diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c index 36b411d1a960..759f48038273 100644 --- a/sound/pci/hda/patch_cs8409-tables.c +++ b/sound/pci/hda/patch_cs8409-tables.c @@ -473,7 +473,7 @@ struct sub_codec dolphin_cs42l42_1 = { * Arrays Used for all projects using CS8409 ******************************************************************************/ -const struct snd_pci_quirk cs8409_fixup_tbl[] = { +const struct hda_quirk cs8409_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE), diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index 937e9387abdc..5e48115caf09 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/pci/hda/patch_cs8409.h @@ -355,7 +355,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback; extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture; -extern const struct snd_pci_quirk cs8409_fixup_tbl[]; +extern const struct hda_quirk cs8409_fixup_tbl[]; extern const struct hda_model_fixup cs8409_models[]; extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_verb cs8409_cs42l42_init_verbs[]; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 24b4fe99304a..56a3622ca2c1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1565,7 +1565,7 @@ static const struct hda_fixup alc880_fixups[] = { }, }; -static const struct snd_pci_quirk alc880_fixup_tbl[] = { +static const struct hda_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), @@ -1874,7 +1874,7 @@ static const struct hda_fixup alc260_fixups[] = { }, }; -static const struct snd_pci_quirk alc260_fixup_tbl[] = { +static const struct hda_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), @@ -2566,7 +2566,7 @@ static const struct hda_fixup alc882_fixups[] = { }, }; -static const struct snd_pci_quirk alc882_fixup_tbl[] = { +static const struct hda_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), @@ -2910,7 +2910,7 @@ static const struct hda_fixup alc262_fixups[] = { }, }; -static const struct snd_pci_quirk alc262_fixup_tbl[] = { +static const struct hda_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), @@ -3071,7 +3071,7 @@ static const struct hda_model_fixup alc268_fixup_models[] = { {} }; -static const struct snd_pci_quirk alc268_fixup_tbl[] = { +static const struct hda_quirk alc268_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), /* below is codec SSID since multiple Toshiba laptops have the @@ -7736,8 +7736,6 @@ enum { ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, ALC298_FIXUP_LENOVO_C940_DUET7, - ALC287_FIXUP_LENOVO_14IRP8_DUETITL, - ALC287_FIXUP_LENOVO_LEGION_7, ALC287_FIXUP_13S_GEN2_SPEAKERS, ALC256_FIXUP_SET_COEF_DEFAULTS, ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, @@ -7782,8 +7780,6 @@ enum { ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1, ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318, ALC256_FIXUP_CHROME_BOOK, - ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7, - ALC287_FIXUP_LENOVO_SSID_17AA3820, ALC245_FIXUP_CLEVO_NOISY_MIC, ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE, }; @@ -7805,72 +7801,6 @@ static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec, __snd_hda_apply_fixup(codec, id, action, 0); } -/* A special fixup for Lenovo Slim/Yoga Pro 9 14IRP8 and Yoga DuetITL 2021; - * 14IRP8 PCI SSID will mistakenly be matched with the DuetITL codec SSID, - * so we need to apply a different fixup in this case. The only DuetITL codec - * SSID reported so far is the 17aa:3802 while the 14IRP8 has the 17aa:38be - * and 17aa:38bf. If it weren't for the PCI SSID, the 14IRP8 models would - * have matched correctly by their codecs. - */ -static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa3802) - id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* DuetITL */ - else - id = ALC287_FIXUP_TAS2781_I2C; /* 14IRP8 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Similar to above the Lenovo Yoga Pro 7 14ARP8 PCI SSID matches the codec SSID of the - Legion Y9000X 2022 IAH7.*/ -static void alc287_fixup_lenovo_14arp8_legion_iah7(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa386e) - id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion Y9000X 2022 IAH7 */ - else - id = ALC285_FIXUP_SPEAKER2_TO_DAC1; /* Yoga Pro 7 14ARP8 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Another hilarious PCI SSID conflict with Lenovo Legion Pro 7 16ARX8H (with - * TAS2781 codec) and Legion 7i 16IAX7 (with CS35L41 codec); - * we apply a corresponding fixup depending on the codec SSID instead - */ -static void alc287_fixup_lenovo_legion_7(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa38a8) - id = ALC287_FIXUP_TAS2781_I2C; /* Legion Pro 7 16ARX8H */ - else - id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion 7i 16IAX7 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Yet more conflicting PCI SSID (17aa:3820) on two Lenovo models */ -static void alc287_fixup_lenovo_ssid_17aa3820(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa3820) - id = ALC269_FIXUP_ASPIRE_HEADSET_MIC; /* IdeaPad 330-17IKB 81DM */ - else /* 0x17aa3802 */ - id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* "Yoga Duet 7 13ITL6 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_GPIO2] = { .type = HDA_FIXUP_FUNC, @@ -9810,14 +9740,6 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc298_fixup_lenovo_c940_duet7, }, - [ALC287_FIXUP_LENOVO_14IRP8_DUETITL] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_14irp8_duetitl, - }, - [ALC287_FIXUP_LENOVO_LEGION_7] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_legion_7, - }, [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -10002,10 +9924,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK, }, - [ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_14arp8_legion_iah7, - }, [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = { .type = HDA_FIXUP_FUNC, .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin, @@ -10140,10 +10058,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC225_FIXUP_HEADSET_JACK }, - [ALC287_FIXUP_LENOVO_SSID_17AA3820] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_ssid_17aa3820, - }, [ALC245_FIXUP_CLEVO_NOISY_MIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_limit_int_mic_boost, @@ -10162,7 +10076,7 @@ static const struct hda_fixup alc269_fixups[] = { }, }; -static const struct snd_pci_quirk alc269_fixup_tbl[] = { +static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), @@ -10895,11 +10809,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8 / DuetITL 2021", ALC287_FIXUP_LENOVO_14IRP8_DUETITL), + HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3820, "IdeaPad 330 / Yoga Duet 7", ALC287_FIXUP_LENOVO_SSID_17AA3820), + HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC), + SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF), SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), @@ -10913,8 +10829,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7 / Yoga Pro 7 14ARP8", ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7), - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7/7i", ALC287_FIXUP_LENOVO_LEGION_7), + HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1), + HDA_CODEC_QUIRK(0x17aa, 0x386f, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), @@ -11085,7 +11003,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; -static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { +static const struct hda_quirk alc269_fixup_vendor_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), @@ -12021,7 +11939,7 @@ static const struct hda_fixup alc861_fixups[] = { } }; -static const struct snd_pci_quirk alc861_fixup_tbl[] = { +static const struct hda_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), @@ -12125,7 +12043,7 @@ static const struct hda_fixup alc861vd_fixups[] = { }, }; -static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { +static const struct hda_quirk alc861vd_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), @@ -12926,7 +12844,7 @@ static const struct hda_fixup alc662_fixups[] = { }, }; -static const struct snd_pci_quirk alc662_fixup_tbl[] = { +static const struct hda_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ae1a34c68c61..bde6b7373858 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1462,7 +1462,7 @@ static const struct hda_model_fixup stac9200_models[] = { {} }; -static const struct snd_pci_quirk stac9200_fixup_tbl[] = { +static const struct hda_quirk stac9200_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1683,7 +1683,7 @@ static const struct hda_model_fixup stac925x_models[] = { {} }; -static const struct snd_pci_quirk stac925x_fixup_tbl[] = { +static const struct hda_quirk stac925x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), @@ -1957,7 +1957,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { +static const struct hda_quirk stac92hd73xx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -2753,7 +2753,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -3236,7 +3236,7 @@ static const struct hda_model_fixup stac92hd71bxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), @@ -3496,7 +3496,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = { }; /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ -static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { +static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3), SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), @@ -3640,7 +3640,7 @@ static const struct hda_model_fixup stac922x_models[] = { {} }; -static const struct snd_pci_quirk stac922x_fixup_tbl[] = { +static const struct hda_quirk stac922x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -3968,7 +3968,7 @@ static const struct hda_model_fixup stac927x_models[] = { {} }; -static const struct snd_pci_quirk stac927x_fixup_tbl[] = { +static const struct hda_quirk stac927x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -4178,7 +4178,7 @@ static const struct hda_model_fixup stac9205_models[] = { {} }; -static const struct snd_pci_quirk stac9205_fixup_tbl[] = { +static const struct hda_quirk stac9205_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -4255,7 +4255,7 @@ static const struct hda_fixup stac92hd95_fixups[] = { }, }; -static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = { +static const struct hda_quirk stac92hd95_fixup_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS), {} /* terminator */ }; @@ -5002,7 +5002,7 @@ static const struct hda_fixup stac9872_fixups[] = { }, }; -static const struct snd_pci_quirk stac9872_fixup_tbl[] = { +static const struct hda_quirk stac9872_fixup_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index a8ef4bb70dd0..d0893059b1b9 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1035,7 +1035,7 @@ static const struct hda_fixup via_fixups[] = { }, }; -static const struct snd_pci_quirk vt2002p_fixups[] = { +static const struct hda_quirk vt2002p_fixups[] = { SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE), SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75), SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 096ec76f5304..a12dafbf53ab 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -170,14 +170,9 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el tmp = stac9460_get(ice, idx); ovol = 0x7f - (tmp & 0x7f); change = (ovol != nvol); - if (change) { - ovol = (0x7f - nvol) | (tmp & 0x80); - /* - dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", - idx, ovol); - */ + if (change) stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); - } + return change; } diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 8e29c92830ad..f1b0cf9ea555 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -160,7 +160,7 @@ static SIMPLE_DEV_PM_OPS(snd_pmac_pm, snd_pmac_driver_suspend, snd_pmac_driver_r static struct platform_driver snd_pmac_driver = { .probe = snd_pmac_probe, - .remove_new = snd_pmac_remove, + .remove = snd_pmac_remove, .driver = { .name = SND_PMAC_DRIVER, .pm = SND_PMAC_PM_OPS, diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 936cd6e91529..39bf51ff43a1 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -315,8 +315,6 @@ static void aica_period_elapsed(struct timer_list *t) static void spu_begin_dma(struct snd_pcm_substream *substream) { struct snd_card_aica *dreamcastcard; - struct snd_pcm_runtime *runtime; - runtime = substream->runtime; dreamcastcard = substream->pcm->private_data; /*get the queue to do the work */ schedule_work(&(dreamcastcard->spu_dma_work)); @@ -601,7 +599,7 @@ static int snd_aica_probe(struct platform_device *devptr) static struct platform_driver snd_aica_driver = { .probe = snd_aica_probe, - .remove_new = snd_aica_remove, + .remove = snd_aica_remove, .driver = { .name = SND_AICA_DRIVER, }, diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index e7b6ce7bd086..e7b80328f0ef 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -383,7 +383,7 @@ probe_error: */ static struct platform_driver sh_dac_driver = { .probe = snd_sh_dac_probe, - .remove_new = snd_sh_dac_remove, + .remove = snd_sh_dac_remove, .driver = { .name = "dac_audio", }, diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index e87bd15a8b43..5efba76abb31 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -106,9 +106,10 @@ source "sound/soc/meson/Kconfig" source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/qcom/Kconfig" +source "sound/soc/renesas/Kconfig" source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" -source "sound/soc/sh/Kconfig" +source "sound/soc/sdca/Kconfig" source "sound/soc/sof/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sprd/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 775bb38c2ed4..08baaa11d813 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -59,9 +59,10 @@ obj-$(CONFIG_SND_SOC) += mxs/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += qcom/ +obj-$(CONFIG_SND_SOC) += renesas/ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ -obj-$(CONFIG_SND_SOC) += sh/ +obj-$(CONFIG_SND_SOC) += sdca/ obj-$(CONFIG_SND_SOC) += sof/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sprd/ diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 77cf72082e73..02b04f355ca6 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -542,7 +542,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = cz_da7219_init, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_play_ops, SND_SOC_DAILINK_REG(designware1, dlgs, platform), @@ -552,7 +552,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_cap_ops, SND_SOC_DAILINK_REG(designware2, dlgs, platform), @@ -562,7 +562,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), @@ -573,7 +573,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), @@ -584,7 +584,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), @@ -598,7 +598,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = cz_rt5682_init, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_play_ops, SND_SOC_DAILINK_REG(designware1, rt5682, platform), @@ -608,7 +608,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_cap_ops, SND_SOC_DAILINK_REG(designware2, rt5682, platform), @@ -618,7 +618,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), @@ -629,7 +629,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), @@ -640,7 +640,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c index 3756b8bef17b..0193b3eae7a6 100644 --- a/sound/soc/amd/acp-es8336.c +++ b/sound/soc/amd/acp-es8336.c @@ -150,8 +150,6 @@ static struct snd_soc_dai_link st_dai_es8336[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, - .dpcm_capture = 1, - .dpcm_playback = 1, .init = st_es8336_init, .ops = &st_es8336_ops, SND_SOC_DAILINK_REG(designware1, codec, platform), diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 88391e4c17e3..03f3fcbba5af 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -119,10 +119,17 @@ config SND_SOC_AMD_SOF_MACH help This option enables SOF sound card support for ACP audio. +config SND_SOC_AMD_SDW_MACH_COMMON + tristate + help + This option enables common SoundWire Machine driver module for + AMD platforms. + 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_AMD_SDW_MACH_COMMON select SND_SOC_SDW_UTILS select SND_SOC_DMIC select SND_SOC_RT711_SDW @@ -137,6 +144,28 @@ config SND_SOC_AMD_SOF_SDW_MACH on AMD platform. If unsure select "N". +config SND_SOC_AMD_LEGACY_SDW_MACH + tristate "AMD Legacy(No DSP) Soundwire Machine Driver Support" + depends on X86 && PCI && ACPI + depends on SOUNDWIRE + select SND_SOC_AMD_SDW_MACH_COMMON + select SND_SOC_SDW_UTILS + select SND_SOC_DMIC + select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW + select SND_SOC_RT712_SDCA_SDW + select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT1316_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT722_SDCA_SDW + help + This option enables Legacy(No DSP) 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 82cf5d180b3a..bb2702036338 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -23,7 +23,9 @@ 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-mach-y := acp-sdw-mach-common.o snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o +snd-acp-sdw-legacy-mach-y += acp-sdw-legacy-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o @@ -41,4 +43,6 @@ 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_SDW_MACH_COMMON) += snd-acp-sdw-mach.o obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o +obj-$(CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH) += snd-acp-sdw-legacy-mach.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 56ce9e4b6acc..515bf862deb5 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -59,9 +59,9 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) val |= BIT(1); switch (chip->acp_rev) { - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div); val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div); break; @@ -121,8 +121,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas } switch (chip->acp_rev) { - case ACP3X_DEV: - case ACP6X_DEV: + case ACP_RN_PCI_ID: + case ACP_RMB_PCI_ID: switch (slots) { case 1 ... 7: no_of_slots = slots; @@ -135,9 +135,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas return -EINVAL; } break; - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: switch (slots) { case 1 ... 31: no_of_slots = slots; @@ -160,8 +160,8 @@ 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) { switch (chip->acp_rev) { - case ACP3X_DEV: - case ACP6X_DEV: + case ACP_RN_PCI_ID: + case ACP_RMB_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) adata->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); @@ -169,9 +169,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas 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: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) adata->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 13) | (slot_len << 18); @@ -534,7 +534,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; else phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; @@ -546,7 +546,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; else phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; @@ -561,7 +561,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; @@ -573,7 +573,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; @@ -588,7 +588,7 @@ 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; - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; else phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; @@ -600,7 +600,7 @@ 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; - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; else phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index be01b178172e..3f76d1f0a9e7 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -257,20 +257,20 @@ static int acp_power_on(struct acp_chip_info *chip) base = chip->base; switch (chip->acp_rev) { - case ACP3X_DEV: + case ACP_RN_PCI_ID: acp_pgfsm_stat_reg = ACP_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL; break; - case ACP6X_DEV: + case ACP_RMB_PCI_ID: acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL; break; - case ACP63_DEV: + case ACP63_PCI_ID: acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL; break; - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL; break; @@ -322,7 +322,7 @@ int acp_init(struct acp_chip_info *chip) pr_err("ACP reset failed\n"); return ret; } - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) writel(0, chip->base + ACP_ZSC_DSP_CTRL); return 0; } @@ -337,7 +337,7 @@ int acp_deinit(struct acp_chip_info *chip) if (ret) return ret; - if (chip->acp_rev < ACP70_DEV) + if (chip->acp_rev < ACP70_PCI_ID) writel(0, chip->base + ACP_CONTROL); else writel(0x01, chip->base + ACP_ZSC_DSP_CTRL); @@ -448,20 +448,20 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) u32 pdm_addr; switch (chip->acp_rev) { - case ACP3X_DEV: + case ACP_RN_PCI_ID: pdm_addr = ACP_RENOIR_PDM_ADDR; check_acp3x_config(chip); break; - case ACP6X_DEV: + case ACP_RMB_PCI_ID: pdm_addr = ACP_REMBRANDT_PDM_ADDR; check_acp6x_config(chip); break; - case ACP63_DEV: + case ACP63_PCI_ID: pdm_addr = ACP63_PDM_ADDR; check_acp6x_config(chip); break; - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: 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 d104f7e8fdcd..45613a865d2b 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -57,7 +57,6 @@ static struct acp_card_drvdata es83xx_rn_data = { .dmic_cpu_id = DMIC, .hs_codec_id = ES83XX, .dmic_codec_id = DMIC, - .platform = RENOIR, }; static struct acp_card_drvdata max_nau8825_data = { @@ -68,7 +67,6 @@ static struct acp_card_drvdata max_nau8825_data = { .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, .soc_mclk = true, - .platform = REMBRANDT, .tdm_mode = false, }; @@ -80,7 +78,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { .amp_codec_id = RT1019, .dmic_codec_id = DMIC, .soc_mclk = true, - .platform = REMBRANDT, .tdm_mode = false, }; @@ -126,6 +123,7 @@ static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); const struct dmi_system_id *dmi_id; struct acp_card_drvdata *acp_card_drvdata; int ret; @@ -171,7 +169,9 @@ static int acp_asoc_probe(struct platform_device *pdev) goto out; } if (!strcmp(pdev->name, "acp-pdm-mach")) - acp_card_drvdata->platform = *((int *)dev->platform_data); + acp_card_drvdata->acp_rev = *((int *)dev->platform_data); + else + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; dmi_id = dmi_first_match(acp_quirk_table); if (dmi_id && dmi_id->driver_data) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index e9ff4815c12c..d314253207d5 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -1407,8 +1407,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_sp); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { @@ -1444,8 +1442,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_hs); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { @@ -1471,7 +1467,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; - if (drv_data->platform == RENOIR) { + if (drv_data->acp_rev == ACP_RN_PCI_ID) { links[i].cpus = sof_sp; links[i].num_cpus = ARRAY_SIZE(sof_sp); } else { @@ -1480,7 +1476,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) } links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { @@ -1512,7 +1508,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { @@ -1527,7 +1523,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].init = acp_card_maxim_init; } if (drv_data->amp_codec_id == MAX98388) { - links[i].dpcm_capture = 1; + links[i].playback_only = 0; links[i].codecs = max98388; links[i].num_codecs = ARRAY_SIZE(max98388); links[i].ops = &acp_max98388_ops; @@ -1553,8 +1549,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_bt); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->bt_codec_id) { @@ -1574,7 +1568,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_dmic); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_capture = 1; + links[i].capture_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; } @@ -1613,8 +1607,6 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(i2s_sp); links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1647,18 +1639,21 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].id = HEADSET_BE_ID; links[i].cpus = i2s_hs; links[i].num_cpus = ARRAY_SIZE(i2s_hs); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; + if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1686,7 +1681,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(i2s_sp); links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1714,17 +1709,22 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].id = AMP_BE_ID; links[i].cpus = i2s_hs; links[i].num_cpus = ARRAY_SIZE(i2s_hs); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } - links[i].dpcm_playback = 1; + + links[i].playback_only = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1749,6 +1749,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; + links[i].stream_name = "DMIC capture"; links[i].id = DMIC_BE_ID; if (drv_data->dmic_codec_id == DMIC) { links[i].codecs = dmic_codec; @@ -1760,21 +1761,27 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) } links[i].cpus = pdm_dmic; links[i].num_cpus = ARRAY_SIZE(pdm_dmic); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else if ((drv_data->platform == ACP70) || (drv_data->platform == ACP71)) { + break; + case ACP70_PCI_ID: + case ACP71_PCI_ID: links[i].platforms = platform_acp70_component; links[i].num_platforms = ARRAY_SIZE(platform_acp70_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } links[i].ops = &acp_card_dmic_ops; - links[i].dpcm_capture = 1; + links[i].capture_only = 1; } card->dai_link = links; diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 93d9e3886b7e..f94c30c20f20 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -18,6 +18,8 @@ #include <linux/module.h> #include <sound/soc.h> +#include "acp_common.h" + #define TDM_CHANNELS 8 #define ACP_OPS(priv, cb) ((priv)->ops.cb) @@ -51,14 +53,6 @@ enum codec_endpoints { ES83XX, }; -enum platform_end_point { - RENOIR = 0, - REMBRANDT, - ACP63, - ACP70, - ACP71, -}; - struct acp_mach_ops { int (*probe)(struct snd_soc_card *card); int (*configure_link)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); @@ -77,7 +71,7 @@ struct acp_card_drvdata { unsigned int bt_codec_id; unsigned int dmic_codec_id; unsigned int dai_fmt; - unsigned int platform; + unsigned int acp_rev; struct clk *wclk; struct clk *bclk; struct acp_mach_ops ops; diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index f7450a5bd103..4b6ad7abc3ba 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -77,27 +77,22 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id res_acp = acp_res; num_res = ARRAY_SIZE(acp_res); - + chip->acp_rev = pci->revision; switch (pci->revision) { case 0x01: chip->name = "acp_asoc_renoir"; - chip->acp_rev = ACP3X_DEV; break; case 0x6f: chip->name = "acp_asoc_rembrandt"; - chip->acp_rev = ACP6X_DEV; break; case 0x63: chip->name = "acp_asoc_acp63"; - chip->acp_rev = ACP63_DEV; break; case 0x70: 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); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 22dd8988d005..48faafe724ed 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -47,7 +47,7 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, size_dmic = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) physical_addr = ACP7x_DMIC_MEM_WINDOW_START; else physical_addr = stream->reg_offset + MEM_WINDOW_START; diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 3a7a467b7063..1f352b2b3002 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -114,7 +114,7 @@ int acp_machine_select(struct acp_dev_data *adata) int size, platform; if (adata->flag == FLAG_AMD_LEGACY_ONLY_DMIC) { - platform = adata->platform; + platform = adata->acp_rev; adata->mach_dev = platform_device_register_data(adata->dev, "acp-pdm-mach", PLATFORM_DEVID_NONE, &platform, sizeof(platform)); @@ -125,6 +125,7 @@ int acp_machine_select(struct acp_dev_data *adata) dev_err(adata->dev, "warning: No matching ASoC machine driver found\n"); return -EINVAL; } + mach->mach_params.subsystem_rev = adata->acp_rev; adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name, PLATFORM_DEVID_NONE, mach, size); } @@ -142,9 +143,6 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) u16 i2s_flag = 0; u32 ext_intr_stat, ext_intr_stat1; - if (!adata) - return IRQ_NONE; - if (adata->rsrc->no_of_ctrls == 2) ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); @@ -204,9 +202,9 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s u32 low, high, val; u16 page_idx; - switch (adata->platform) { - case ACP70: - case ACP71: + switch (adata->acp_rev) { + case ACP70_PCI_ID: + case ACP71_PCI_ID: switch (stream->dai_id) { case I2S_SP_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) @@ -270,9 +268,9 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs stream->substream = substream; chip = dev_get_platdata(dev); switch (chip->acp_rev) { - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp6x_pcm_hardware_playback; else diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 396434a45eea..008d97598b62 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -197,7 +197,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP6X_DEV) { + if (chip->acp_rev != ACP_RMB_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -227,7 +227,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) adata->dai_driver = acp_rmb_dai; adata->num_dai = ARRAY_SIZE(acp_rmb_dai); adata->rsrc = &rsrc; - adata->platform = REMBRANDT; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_rmb_acp_machines; diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 5e3f730aa6bf..166f1efacf1d 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -157,7 +157,7 @@ static int renoir_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP3X_DEV) { + if (chip->acp_rev != ACP_RN_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -185,7 +185,7 @@ static int renoir_audio_probe(struct platform_device *pdev) adata->dai_driver = acp_renoir_dai; adata->num_dai = ARRAY_SIZE(acp_renoir_dai); adata->rsrc = &rsrc; - adata->platform = RENOIR; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->machines = snd_soc_acpi_amd_acp_machines; diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c new file mode 100644 index 000000000000..48952a238946 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-legacy-mach - ASoC legacy Machine driver for AMD SoundWire platforms + */ + +#include <linux/bitmap.h> +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/module.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "soc_amd_sdw_common.h" +#include "../../codecs/rt711.h" + +static unsigned long soc_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(soc_sdw_quirk)) + dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", + SOC_JACK_JDSRC(soc_sdw_quirk)); + if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) + dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n"); +} + +static int soc_sdw_quirk_cb(const struct dmi_system_id *id) +{ + soc_sdw_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id soc_sdw_quirk_table[] = { + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"), + }, + .driver_data = (void *)RT711_JD2, + }, + {} +}; + +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 const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; + +static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dai, + struct snd_soc_dai_link **dai_links, + int *be_id, struct snd_soc_codec_conf **codec_conf, + struct snd_soc_dai_link_component *sdw_platform_component) +{ + 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 *soc_end; + int cpu_pin_id; + int stream; + int ret; + + list_for_each_entry(soc_end, &soc_dai->endpoints, list) { + if (soc_end->name_prefix) { + (*codec_conf)->dlc.name = soc_end->codec_name; + (*codec_conf)->name_prefix = soc_end->name_prefix; + (*codec_conf)++; + } + + if (soc_end->include_sidecar) { + ret = soc_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(soc_dai->link_mask[stream]); + int num_codecs = soc_dai->num_devs[stream]; + int playback, capture; + int j = 0; + char *name; + + if (!soc_dai->num_devs[stream]) + continue; + + soc_end = list_first_entry(&soc_dai->endpoints, + struct asoc_sdw_endpoint, list); + + *be_id = soc_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(soc_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(soc_end->link_mask) - 1, + cpu_pin_id, + type_strings[soc_end->dai_info->dai_type]); + } else { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], + ffs(soc_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(soc_end, &soc_dai->endpoints, list) { + if (!soc_end->dai_info->direction[stream]) + continue; + + int link_num = ffs(soc_end->link_mask) - 1; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name); + if (!cpus->dai_name) + return -ENOMEM; + + codec_maps[j].cpu = 0; + codec_maps[j].codec = j; + + codecs[j].name = soc_end->codec_name; + codecs[j].dai_name = soc_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, sdw_platform_component, + 1, codecs, num_codecs, + 0, 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(soc_end, &soc_dai->endpoints, list) { + if (soc_end->dai_info->init) + soc_end->dai_info->init(card, *dai_links, + soc_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 *soc_dais, + 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 snd_soc_dai_link_component *sdw_platform_component; + int ret; + + sdw_platform_component = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!sdw_platform_component) + return -ENOMEM; + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + sdw_platform_component->name = "amd_ps_sdw_dma.0"; + break; + default: + return -EINVAL; + } + + /* generate DAI links by each sdw link */ + while (soc_dais->initialised) { + int current_be_id; + + ret = create_sdw_dailink(card, soc_dais, dai_links, + ¤t_be_id, codec_conf, sdw_platform_component); + 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; + + soc_dais++; + } + + return 0; +} + +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm) +{ + 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 snd_soc_dai_link_component *pdm_cpu; + struct snd_soc_dai_link_component *pdm_platform; + int ret; + + pdm_cpu = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); + if (!pdm_cpu) + return -ENOMEM; + + pdm_platform = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); + if (!pdm_platform) + return -ENOMEM; + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + pdm_cpu->name = "acp_ps_pdm_dma.0"; + pdm_platform->name = "acp_ps_pdm_dma.0"; + break; + default: + return -EINVAL; + } + + *be_id = ACP_DMIC_BE_ID; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec", + 0, 1, // DMIC only supports capture + pdm_cpu->name, pdm_platform->name, 1, + "dmic-codec.0", "dmic-hifi", no_pcm, + asoc_sdw_dmic_init, NULL); + if (ret) + return ret; + + (*dai_links)++; + + return 0; +} + +static int soc_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 asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; + struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL; + struct snd_soc_codec_conf *codec_conf; + 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 */ + soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL); + if (!soc_dais) + return -ENOMEM; + + /* One per endpoint, ie. each DAI on each codec/amp */ + soc_ends = kcalloc(num_ends, sizeof(*soc_ends), GFP_KERNEL); + if (!soc_ends) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs); + if (ret < 0) + return ret; + + sdw_be_num = ret; + + /* enable dmic */ + if (soc_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) + return -ENOMEM; + + /* 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) + return -ENOMEM; + + 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, + soc_dais, &codec_conf); + if (ret) + return ret; + } + + /* 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, 0); + if (ret) + return ret; + } + } + + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); + + return ret; +} + +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(soc_sdw_quirk_table); + + if (quirk_override != -1) { + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + soc_sdw_quirk, quirk_override); + soc_sdw_quirk = quirk_override; + } + + log_quirks(card->dev); + + ctx->mc_quirk = soc_sdw_quirk; + dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_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 = soc_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; + if (mach->mach_params.dmic_num) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; + } + + /* 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_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + +static struct platform_driver soc_sdw_driver = { + .driver = { + .name = "amd_sdw", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, + .remove = mc_remove, + .id_table = mc_id_table, +}; + +module_platform_driver(soc_sdw_driver); + +MODULE_DESCRIPTION("ASoC AMD SoundWire Legacy Generic Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_SDW_UTILS); +MODULE_IMPORT_NS(SND_SOC_AMD_SDW_MACH); diff --git a/sound/soc/amd/acp/acp-sdw-mach-common.c b/sound/soc/amd/acp/acp-sdw-mach-common.c new file mode 100644 index 000000000000..d9393cc4a302 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-mach-common.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-mach-common - Common machine driver helper functions for + * legacy(No DSP) stack and SOF stack. + */ + +#include <linux/device.h> +#include <linux/module.h> +#include "soc_amd_sdw_common.h" + +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; +} +EXPORT_SYMBOL_NS_GPL(get_acp63_cpu_pin_id, SND_SOC_AMD_SDW_MACH); + +MODULE_DESCRIPTION("AMD SoundWire Common Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 306854fb08e3..0d256c0749c9 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -64,54 +64,6 @@ static const struct snd_soc_ops sdw_ops = { .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, @@ -154,7 +106,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, 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; + int j = 0; char *name; if (!sof_dai->num_devs[stream]) @@ -213,14 +165,14 @@ static int create_sdw_dailink(struct snd_soc_card *card, 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) + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name); + if (!cpus->dai_name) return -ENOMEM; - codec_maps[j].cpu = i; + codec_maps[j].cpu = 0; codec_maps[j].codec = j; codecs[j].name = sof_end->codec_name; @@ -236,7 +188,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, 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); + 1, asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -285,7 +237,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, } static int create_dmic_dailinks(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, int *be_id) + struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm) { struct device *dev = card->dev; int ret; @@ -294,7 +246,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "acp-sof-dmic", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", no_pcm, asoc_sdw_dmic_init, NULL); if (ret) return ret; @@ -311,9 +263,9 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) 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 asoc_sdw_endpoint *sof_ends __free(kfree) = NULL; + struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL; 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; @@ -334,14 +286,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) /* 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; - } + if (!sof_ends) + return -ENOMEM; ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); if (ret < 0) - goto err_end; + return ret; sdw_be_num = ret; @@ -352,18 +302,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) 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; - } + if (!codec_conf) + return -ENOMEM; /* 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; - } + if (!dai_links) + return -ENOMEM; card->codec_conf = codec_conf; card->num_configs = num_devs; @@ -375,7 +321,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) ret = create_sdw_dailinks(card, &dai_links, &be_id, sof_dais, &codec_conf); if (ret) - goto err_end; + return ret; } /* dmic */ @@ -383,20 +329,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (ctx->ignore_internal_dmic) { dev_warn(dev, "Ignoring ACP DMIC\n"); } else { - ret = create_dmic_dailinks(card, &dai_links, &be_id); + ret = create_dmic_dailinks(card, &dai_links, &be_id, 1); if (ret) - goto err_end; + return ret; } } 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; } @@ -502,3 +443,4 @@ MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver"); MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(SND_SOC_SDW_UTILS); +MODULE_IMPORT_NS(SND_SOC_AMD_SDW_MACH); diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index f36750167fa2..63a9621ede6d 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -46,7 +46,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = { .hs_codec_id = RT5682S, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .platform = RENOIR, }; static struct acp_card_drvdata sof_rt5682s_max_data = { @@ -56,7 +55,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .hs_codec_id = RT5682S, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .platform = RENOIR, }; static struct acp_card_drvdata sof_nau8825_data = { @@ -66,7 +64,6 @@ static struct acp_card_drvdata sof_nau8825_data = { .hs_codec_id = NAU8825, .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, - .platform = REMBRANDT, .soc_mclk = true, }; @@ -77,7 +74,6 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { .hs_codec_id = RT5682S, .amp_codec_id = RT1019, .dmic_codec_id = DMIC, - .platform = REMBRANDT, .soc_mclk = true, }; @@ -94,6 +90,7 @@ static int acp_sof_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); const struct dmi_system_id *dmi_id; struct acp_card_drvdata *acp_card_drvdata; int ret; @@ -116,6 +113,7 @@ static int acp_sof_probe(struct platform_device *pdev) if (dmi_id && dmi_id->driver_data) acp_card_drvdata->tdm_mode = dmi_id->driver_data; + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; ret = acp_sofdsp_dai_links_create(card); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n"); diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index f325c374f228..e0b86132eb95 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -207,7 +207,7 @@ static int acp63_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP63_DEV) { + if (chip->acp_rev != ACP63_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -237,7 +237,7 @@ static int acp63_audio_probe(struct platform_device *pdev) adata->dai_driver = acp63_dai; adata->num_dai = ARRAY_SIZE(acp63_dai); adata->rsrc = &rsrc; - adata->platform = ACP63; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_acp63_acp_machines; diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 68d2590e1a4e..3e4fd113a8a4 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -142,9 +142,9 @@ static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata) struct pci_dev *smn_dev; u32 device_id; - if (adata->platform == ACP70) + if (adata->acp_rev == ACP70_PCI_ID) device_id = 0x1507; - else if (adata->platform == ACP71) + else if (adata->acp_rev == ACP71_PCI_ID) device_id = 0x1122; else return -ENODEV; @@ -175,8 +175,8 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) } switch (chip->acp_rev) { - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: break; default: dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); @@ -209,11 +209,7 @@ 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; - if (chip->acp_rev == ACP70_DEV) - adata->platform = ACP70; - else - adata->platform = ACP71; - + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; acp_machine_select(adata); diff --git a/sound/soc/amd/acp/acp_common.h b/sound/soc/amd/acp/acp_common.h new file mode 100644 index 000000000000..f1ae88013f62 --- /dev/null +++ b/sound/soc/amd/acp/acp_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved + */ + +/* + * acp_common.h - acp common header file + */ + +#ifndef __ACP_COMMON_H +#define __ACP_COMMON_H + +#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 ACP71_PCI_ID 0x71 + +#endif diff --git a/sound/soc/amd/acp/amd-acp63-acpi-match.c b/sound/soc/amd/acp/amd-acp63-acpi-match.c index be9367913073..9b6a49c051cd 100644 --- a/sound/soc/amd/acp/amd-acp63-acpi-match.c +++ b/sound/soc/amd/acp/amd-acp63-acpi-match.c @@ -73,6 +73,45 @@ static const struct snd_soc_acpi_link_adr acp63_4_in_1_sdca[] = { {} }; +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 rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_link_adr acp63_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { { .link_mask = BIT(0) | BIT(1), @@ -85,6 +124,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_sdw_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[] = { + { + .link_mask = BIT(0), + .links = acp63_rt722_only, + .drv_name = "amd_sdw", + }, + { + .link_mask = BIT(0) | BIT(1), + .links = acp63_4_in_1_sdca, + .drv_name = "amd_sdw", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_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 854269fea875..ee69dfb10cb8 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -16,14 +16,9 @@ #include <sound/soc-acpi.h> #include <sound/soc-dai.h> +#include "acp_common.h" #include "chip_offset_byte.h" -#define ACP3X_DEV 3 -#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 #define I2S_BT_INSTANCE 0x02 @@ -182,6 +177,7 @@ struct acp_dev_data { struct device *dev; void __iomem *acp_base; unsigned int i2s_irq; + unsigned int acp_rev; /* ACP Revision id */ bool tdm_mode; bool is_i2s_config; @@ -205,7 +201,6 @@ struct acp_dev_data { u32 xfer_tx_resolution[3]; u32 xfer_rx_resolution[3]; unsigned int flag; - unsigned int platform; }; enum acp_config { diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h index f1bd5a7afc8e..b7bae107c13e 100644 --- a/sound/soc/amd/acp/soc_amd_sdw_common.h +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -36,9 +36,13 @@ #define ACP63_SW1_AUDIO0_TX 0 #define ACP63_SW1_AUDIO0_RX 1 +#define ACP_DMIC_BE_ID 4 + struct amd_mc_ctx { unsigned int acp_rev; unsigned int max_sdw_links; }; +int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev); + #endif diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 357dfd016baf..4ca1978020a9 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -317,8 +317,6 @@ static struct snd_soc_dai_link acp3x_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = acp3x_5682_init, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp3x_5682_ops, SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform), }, @@ -327,7 +325,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, .ops = &acp3x_max_play_ops, .cpus = acp3x_bt, .num_cpus = ARRAY_SIZE(acp3x_bt), @@ -339,7 +337,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .stream_name = "Capture DMIC0", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_capture = 1, + .capture_only = 1, .ops = &acp3x_ec_cap0_ops, SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), }, diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 1a967da35a0f..a86c76f781f9 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -23,6 +23,7 @@ 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_sdw_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[]; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index c72d666d51bd..a7583844f5b4 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -302,8 +302,7 @@ static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev) link = mach->links; for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { if (!snd_soc_acpi_sdw_link_slaves_found(dev, link, - acp_data->sdw->ids, - acp_data->sdw->num_slaves)) + acp_data->sdw->peripherals)) break; } if (i == acp_data->info.count || !link->num_adr) @@ -599,6 +598,7 @@ static int snd_acp63_probe(struct pci_dev *pci, dev_err(&pci->dev, "ACP platform devices creation failed\n"); goto de_init; } + adata->machines = snd_soc_acpi_amd_acp63_sdw_machines; ret = acp63_machine_register(&pci->dev); if (ret) { dev_err(&pci->dev, "ACP machine register failed\n"); diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 3b4b9c6b3171..b602cca92b8b 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -445,6 +445,8 @@ static const struct snd_soc_component_driver acp63_sdw_component = { .trigger = acp63_sdw_dma_trigger, .pointer = acp63_sdw_dma_pointer, .pcm_construct = acp63_sdw_dma_new, + .use_dai_pcm_id = true, + }; static int acp63_sdw_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 7878e061ecb9..2ca904db82ab 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -276,8 +276,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp5x_8821_ops, .init = acp5x_8821_init, SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), @@ -288,7 +286,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, .playback_only = 1, .ops = &acp5x_cs35l41_play_ops, SND_SOC_DAILINK_REG(acp5x_bt, cs35l41, platform), @@ -375,8 +372,6 @@ static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp5x_8821_ops, .init = acp5x_8821_init, SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), @@ -387,7 +382,6 @@ static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, .playback_only = 1, .ops = &acp5x_max98388_play_ops, SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform), diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 3763454436c1..89098f41679c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -821,8 +821,9 @@ static int atmel_ssc_resume(struct snd_soc_component *component) return 0; } +/* S24_LE is not supported if more than 2 channels (of TDM slots) are used. */ #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .startup = atmel_ssc_startup, @@ -836,6 +837,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { + .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, @@ -843,6 +845,7 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { + .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index b2507a1491b7..fb820609c043 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -1014,7 +1014,7 @@ static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", .capture = { - .stream_name = "S/PDIF Capture", + .stream_name = "Capture", .channels_min = SPDIFRX_CHANNELS, .channels_max = SPDIFRX_CHANNELS, .rates = MCHP_SPDIF_RATES, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 4c60ea652896..245c0352c141 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -707,7 +707,7 @@ static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", .playback = { - .stream_name = "S/PDIF Playback", + .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = MCHP_SPDIFTX_RATES, diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index ea01d6490cec..3392693faeb9 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -311,7 +311,7 @@ static int au1xpsc_pcm_new(struct snd_soc_component *component, } /* au1xpsc audio platform */ -static struct snd_soc_component_driver au1xpsc_soc_component = { +static const struct snd_soc_component_driver au1xpsc_soc_component = { .name = DRV_NAME, .open = au1xpsc_pcm_open, .close = au1xpsc_pcm_close, diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index d2fdebd8881b..c9c2b1e71d55 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -289,7 +289,7 @@ static int alchemy_pcm_new(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver alchemy_pcm_soc_component = { +static const struct snd_soc_component_driver alchemy_pcm_soc_component = { .name = DRV_NAME, .open = alchemy_pcm_open, .close = alchemy_pcm_close, diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 9bda6499e66e..87d2f06c2f53 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -817,7 +817,7 @@ static const struct regmap_config bcm2835_regmap_config = { .max_register = BCM2835_I2S_GRAY_REG, .precious_reg = bcm2835_i2s_precious_reg, .volatile_reg = bcm2835_i2s_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct snd_soc_component_driver bcm2835_i2s_component = { diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c index 018f2372e892..e3a4fcc63a56 100644 --- a/sound/soc/bcm/bcm63xx-pcm-whistler.c +++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c @@ -256,12 +256,16 @@ static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv) offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >> I2S_RX_DESC_OFF_LEVEL_SHIFT; + bool val_read = false; while (offlevel) { regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1); regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2); + val_read = true; offlevel--; } - prtd->dma_addr_next = val_1 + val_2; + if (val_read) + prtd->dma_addr_next = val_1 + val_2; + ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >> I2S_RX_DESC_IFF_LEVEL_SHIFT; diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 2d1e241d8367..4cb2fe10bcdc 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -707,7 +707,7 @@ static int cygnus_dma_new(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver cygnus_soc_platform = { +static const struct snd_soc_component_driver cygnus_soc_platform = { .open = cygnus_pcm_open, .close = cygnus_pcm_close, .prepare = cygnus_pcm_prepare, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7092842480ef..0f2df7c91e18 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AW8738 imply SND_SOC_AW87390 imply SND_SOC_AW88395 + imply SND_SOC_AW88081 imply SND_SOC_AW88261 imply SND_SOC_AW88399 imply SND_SOC_BT_SCO @@ -85,6 +86,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS42L52 imply SND_SOC_CS42L56 imply SND_SOC_CS42L73 + imply SND_SOC_CS42L84 imply SND_SOC_CS4234 imply SND_SOC_CS4265 imply SND_SOC_CS4270 @@ -112,6 +114,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_DA9055 imply SND_SOC_DMIC imply SND_SOC_ES8316 + imply SND_SOC_ES8323 imply SND_SOC_ES8326 imply SND_SOC_ES8328_SPI imply SND_SOC_ES8328_I2C @@ -222,6 +225,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT712_SDCA_DMIC_SDW imply SND_SOC_RT715_SDW imply SND_SOC_RT715_SDCA_SDW + imply SND_SOC_RT721_SDCA_SDW imply SND_SOC_RT722_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW @@ -236,6 +240,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SMA1303 + imply SND_SOC_SMA1307 imply SND_SOC_SPDIF imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 @@ -281,6 +286,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TWL4030 imply SND_SOC_TWL6040 imply SND_SOC_UDA1334 + imply SND_SOC_UDA1342 imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X @@ -461,7 +467,7 @@ config SND_SOC_ADAU1372_SPI select REGMAP_SPI config SND_SOC_ADAU1373 - tristate + tristate "Analog Devices ADAU1373 CODEC" depends on I2C select SND_SOC_ADAU_UTILS @@ -685,6 +691,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude. +config SND_SOC_AW88081 + tristate "Soc Audio for awinic aw88081" + depends on I2C + select REGMAP_I2C + select SND_SOC_AW88395_LIB + help + This option enables support for aw88081 Smart PA. + The awinic AW88081 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier. Due to its 9uV noise + floor and ultra-low distortion, clean listening is guaranteed. + config SND_SOC_AW87390 tristate "Soc Audio for awinic aw87390" depends on I2C @@ -926,6 +943,12 @@ config SND_SOC_CS42L83 select REGMAP_I2C select SND_SOC_CS42L42_CORE +config SND_SOC_CS42L84 + tristate "Cirrus Logic CS42L84 CODEC" + depends on I2C + select REGMAP + select REGMAP_I2C + config SND_SOC_CS4234 tristate "Cirrus Logic CS4234 CODEC" depends on I2C @@ -1143,6 +1166,10 @@ config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C +config SND_SOC_ES8323 + tristate "Everest Semi ES8323 CODEC" + depends on I2C + config SND_SOC_ES8326 tristate "Everest Semi ES8326 CODEC" depends on I2C @@ -1545,6 +1572,11 @@ config SND_SOC_RL6231 default m if SND_SOC_RT1305=m default m if SND_SOC_RT1308=m +config SND_SOC_RT_SDW_COMMON + tristate + default y if SND_SOC_RT721_SDCA_SDW=y + default m if SND_SOC_RT721_SDCA_SDW=m + config SND_SOC_RL6347A tristate default y if SND_SOC_RT274=y @@ -1743,6 +1775,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ +config SND_SOC_RT721_SDCA_SDW + tristate "Realtek RT721 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT722_SDCA_SDW tristate "Realtek RT722 SDCA Codec - SDW" depends on SOUNDWIRE @@ -1836,6 +1874,15 @@ config SND_SOC_SMA1303 help Enable support for Iron Device SMA1303 Boosted Class-D amplifier +config SND_SOC_SMA1307 + tristate "Iron Device SMA1307 Audio Amplifier" + depends on I2C + help + Enable support for Iron Device SMA1307 boosted digital speaker + amplifier with feedback-loop. + If you are using a system with an SMA1307 amplifier connected + via I2C, enable this option. + config SND_SOC_SPDIF tristate "S/PDIF CODEC" @@ -2114,6 +2161,13 @@ config SND_SOC_UDA1334 and has basic features such as de-emphasis (at 44.1 kHz sampling rate) and mute. +config SND_SOC_UDA1342 + tristate "NXP UDA1342 CODEC" + depends on I2C + help + The UDA1342 is an NXP audio codec, support 2x Stereo audio ADC (4x PGA + mic inputs), stereo audio DAC, with basic audio processing. + config SND_SOC_UDA1380 tristate depends on I2C @@ -2565,6 +2619,19 @@ config SND_SOC_NAU8825 tristate depends on I2C +config SND_SOC_NTPFW + tristate + +config SND_SOC_NTP8918 + select SND_SOC_NTPFW + tristate "NeoFidelity NTP8918 amplifier" + depends on I2C + +config SND_SOC_NTP8835 + select SND_SOC_NTPFW + tristate "NeoFidelity NTP8835 and NTP8835C amplifiers" + depends on I2C + config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 54cbc3feae32..f37e82ddb7a1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -49,6 +49,7 @@ snd-soc-arizona-y := arizona.o arizona-jack.o snd-soc-audio-iio-aux-y := audio-iio-aux.o snd-soc-aw8738-y := aw8738.o snd-soc-aw87390-y := aw87390.o +snd-soc-aw88081-y := aw88081.o snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o snd-soc-aw88395-y := aw88395/aw88395.o \ aw88395/aw88395_device.o @@ -91,6 +92,7 @@ snd-soc-cs42l52-y := cs42l52.o snd-soc-cs42l56-y := cs42l56.o snd-soc-cs42l73-y := cs42l73.o snd-soc-cs42l83-i2c-y := cs42l83-i2c.o +snd-soc-cs42l84-objs := cs42l84.o snd-soc-cs4234-y := cs4234.o snd-soc-cs4265-y := cs4265.o snd-soc-cs4270-y := cs4270.o @@ -125,6 +127,7 @@ snd-soc-es7241-y := es7241.o snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o snd-soc-es8311-y := es8311.o snd-soc-es8316-y := es8316.o +snd-soc-es8323-y := es8323.o snd-soc-es8326-y := es8326.o snd-soc-es8328-y := es8328.o snd-soc-es8328-i2c-y := es8328-i2c.o @@ -189,6 +192,9 @@ snd-soc-nau8821-y := nau8821.o snd-soc-nau8822-y := nau8822.o snd-soc-nau8824-y := nau8824.o snd-soc-nau8825-y := nau8825.o +snd-soc-ntp8835-y := ntp8835.o +snd-soc-ntp8918-y := ntp8918.o +snd-soc-ntpfw-y := ntpfw.o snd-soc-hdmi-codec-y := hdmi-codec.o snd-soc-pcm1681-y := pcm1681.o snd-soc-pcm1789-codec-y := pcm1789.o @@ -216,6 +222,7 @@ snd-soc-rk3308-y := rk3308_codec.o snd-soc-rk3328-y := rk3328_codec.o snd-soc-rk817-y := rk817_codec.o snd-soc-rl6231-y := rl6231.o +snd-soc-rt-sdw-common-y := rt-sdw-common.o snd-soc-rl6347a-y := rl6347a.o snd-soc-rt1011-y := rt1011.o snd-soc-rt1015-y := rt1015.o @@ -259,6 +266,7 @@ snd-soc-rt712-sdca-y := rt712-sdca.o rt712-sdca-sdw.o snd-soc-rt712-sdca-dmic-y := rt712-sdca-dmic.o snd-soc-rt715-y := rt715.o rt715-sdw.o snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o +snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o snd-soc-rt9120-y := rt9120.o snd-soc-rtq9128-y := rtq9128.o @@ -271,6 +279,7 @@ snd-soc-sigmadsp-i2c-y := sigmadsp-i2c.o snd-soc-sigmadsp-regmap-y := sigmadsp-regmap.o snd-soc-si476x-y := si476x.o snd-soc-sma1303-y := sma1303.o +snd-soc-sma1307-y := sma1307.o snd-soc-spdif-tx-y := spdif_transmitter.o snd-soc-spdif-rx-y := spdif_receiver.o snd-soc-src4xxx-y := src4xxx.o @@ -319,6 +328,7 @@ snd-soc-ts3a227e-y := ts3a227e.o snd-soc-twl4030-y := twl4030.o snd-soc-twl6040-y := twl6040.o snd-soc-uda1334-y := uda1334.o +snd-soc-uda1342-y := uda1342.o snd-soc-uda1380-y := uda1380.o snd-soc-wcd-classh-y := wcd-clsh-v2.o snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o @@ -457,6 +467,7 @@ obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o +obj-$(CONFIG_SND_SOC_AW88081) += snd-soc-aw88081.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o @@ -498,6 +509,7 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o +obj-$(CONFIG_SND_SOC_CS42L84) += snd-soc-cs42l84.o obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o @@ -532,6 +544,7 @@ obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o +obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o @@ -591,6 +604,9 @@ obj-$(CONFIG_SND_SOC_NAU8821) += snd-soc-nau8821.o obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o +obj-$(CONFIG_SND_SOC_NTP8835) += snd-soc-ntp8835.o +obj-$(CONFIG_SND_SOC_NTP8918) += snd-soc-ntp8918.o +obj-$(CONFIG_SND_SOC_NTPFW) += snd-soc-ntpfw.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o @@ -618,6 +634,7 @@ obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o +obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o @@ -662,6 +679,7 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o +obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o @@ -672,6 +690,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o +obj-$(CONFIG_SND_SOC_SMA1307) += snd-soc-sma1307.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o @@ -723,6 +742,7 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o +obj-$(CONFIG_SND_SOC_UDA1342) += snd-soc-uda1342.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index 2869325f9ace..73f83be38f74 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids); static struct i2c_driver adau1372_i2c_driver = { .driver = { .name = "adau1372", + .of_match_table = adau1372_of_match, }, .probe = adau1372_i2c_probe, .id_table = adau1372_i2c_ids, diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c index 51298e00fbd6..656bd1fabeb3 100644 --- a/sound/soc/codecs/adau1372-spi.c +++ b/sound/soc/codecs/adau1372-spi.c @@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(spi, adau1372_spi_id); static struct spi_driver adau1372_spi_driver = { .driver = { .name = "adau1372", + .of_match_table = adau1372_of_match, }, .probe = adau1372_spi_probe, .id_table = adau1372_spi_id, diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 98380a7ce64d..fdee689cae53 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -11,6 +11,7 @@ #include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/pm.h> #include <linux/slab.h> @@ -1060,6 +1061,13 @@ const struct regmap_config adau1372_regmap_config = { }; EXPORT_SYMBOL_GPL(adau1372_regmap_config); +const struct of_device_id adau1372_of_match[] = { + { .compatible = "adi,adau1372" }, + { } +}; +EXPORT_SYMBOL_GPL(adau1372_of_match); +MODULE_DEVICE_TABLE(of, adau1372_of_match); + MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h index a9d2c59b73a9..c55b1c24fe39 100644 --- a/sound/soc/codecs/adau1372.h +++ b/sound/soc/codecs/adau1372.h @@ -13,6 +13,7 @@ struct device; +extern const struct of_device_id adau1372_of_match[]; int adau1372_probe(struct device *dev, struct regmap *regmap, void (*switch_mode)(struct device *dev)); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index a910e252aa12..16b9b2658341 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -8,8 +8,10 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/pm.h> +#include <linux/property.h> #include <linux/i2c.h> #include <linux/slab.h> @@ -18,7 +20,6 @@ #include <sound/pcm_params.h> #include <sound/tlv.h> #include <sound/soc.h> -#include <sound/adau1373.h> #include "adau1373.h" #include "adau-utils.h" @@ -30,9 +31,28 @@ struct adau1373_dai { bool clock_provider; }; +enum adau1373_micbias_voltage { + ADAU1373_MICBIAS_2_9V, + ADAU1373_MICBIAS_2_2V, + ADAU1373_MICBIAS_2_6V, + ADAU1373_MICBIAS_1_8V, +}; + +#define ADAU1373_DRC_SIZE 13 + struct adau1373 { struct regmap *regmap; struct adau1373_dai dais[3]; + + bool input_differential[4]; + bool lineout_differential; + bool lineout_ground_sense; + + unsigned int num_drc; + u8 drc_setting[3][ADAU1373_DRC_SIZE]; + + enum adau1373_micbias_voltage micbias1; + enum adau1373_micbias_voltage micbias2; }; #define ADAU1373_INPUT_MODE 0x00 @@ -1332,66 +1352,61 @@ static void adau1373_load_drc_settings(struct adau1373 *adau1373, regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]); } -static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) +static int adau1373_get_micbias(unsigned int val, + enum adau1373_micbias_voltage *micbias) { - switch (micbias) { - case ADAU1373_MICBIAS_2_9V: - case ADAU1373_MICBIAS_2_2V: - case ADAU1373_MICBIAS_2_6V: - case ADAU1373_MICBIAS_1_8V: - return true; + switch (val) { + case 2900000: + *micbias = ADAU1373_MICBIAS_2_9V; + return 0; + case 2200000: + *micbias = ADAU1373_MICBIAS_2_2V; + return 0; + case 2600000: + *micbias = ADAU1373_MICBIAS_2_6V; + return 0; + case 1800000: + *micbias = ADAU1373_MICBIAS_1_8V; + return 0; default: - break; + return -EINVAL; } - return false; } static int adau1373_probe(struct snd_soc_component *component) { struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component); - struct adau1373_platform_data *pdata = component->dev->platform_data; - bool lineout_differential = false; unsigned int val; int i; - if (pdata) { - if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting)) - return -EINVAL; - - if (!adau1373_valid_micbias(pdata->micbias1) || - !adau1373_valid_micbias(pdata->micbias2)) - return -EINVAL; - - for (i = 0; i < pdata->num_drc; ++i) { - adau1373_load_drc_settings(adau1373, i, - pdata->drc_setting[i]); - } + for (i = 0; i < adau1373->num_drc; ++i) { + adau1373_load_drc_settings(adau1373, i, + adau1373->drc_setting[i]); + } - snd_soc_add_component_controls(component, adau1373_drc_controls, - pdata->num_drc); + snd_soc_add_component_controls(component, adau1373_drc_controls, + adau1373->num_drc); - val = 0; - for (i = 0; i < 4; ++i) { - if (pdata->input_differential[i]) - val |= BIT(i); - } - regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); + val = 0; + for (i = 0; i < ARRAY_SIZE(adau1373->input_differential); ++i) { + if (adau1373->input_differential[i]) + val |= BIT(i); + } + regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); - val = 0; - if (pdata->lineout_differential) - val |= ADAU1373_OUTPUT_CTRL_LDIFF; - if (pdata->lineout_ground_sense) - val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); + val = 0; + if (adau1373->lineout_differential) + val |= ADAU1373_OUTPUT_CTRL_LDIFF; + if (adau1373->lineout_ground_sense) + val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - lineout_differential = pdata->lineout_differential; + regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); - regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, - (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | - (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); - } + regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, + (adau1373->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | + (adau1373->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); - if (!lineout_differential) { + if (!adau1373->lineout_differential) { snd_soc_add_component_controls(component, adau1373_lineout2_controls, ARRAY_SIZE(adau1373_lineout2_controls)); } @@ -1471,9 +1486,74 @@ static const struct snd_soc_component_driver adau1373_component_driver = { .endianness = 1, }; +static void adau1373_reset(void *reset_gpio) +{ + gpiod_set_value_cansleep(reset_gpio, 1); +} + +static int adau1373_parse_fw(struct device *dev, struct adau1373 *adau1373) +{ + int ret, drc_count; + unsigned int val; + + if (device_property_present(dev, "adi,input1-differential")) + adau1373->input_differential[0] = true; + if (device_property_present(dev, "adi,input2-differential")) + adau1373->input_differential[1] = true; + if (device_property_present(dev, "adi,input3-differential")) + adau1373->input_differential[2] = true; + if (device_property_present(dev, "adi,input4-differential")) + adau1373->input_differential[3] = true; + + if (device_property_present(dev, "adi,lineout-differential")) + adau1373->lineout_differential = true; + if (device_property_present(dev, "adi,lineout-gnd-sense")) + adau1373->lineout_ground_sense = true; + + ret = device_property_read_u32(dev, "adi,micbias1-microvolt", &val); + if (!ret) { + ret = adau1373_get_micbias(val, &adau1373->micbias1); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get micbias1(%u)\n", val); + } + + ret = device_property_read_u32(dev, "adi,micbias2-microvolt", &val); + if (!ret) { + ret = adau1373_get_micbias(val, &adau1373->micbias2); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get micbias2(%u)\n", val); + } + + drc_count = device_property_count_u8(dev, "adi,drc-settings"); + if (drc_count < 0) + return 0; + if (drc_count % ADAU1373_DRC_SIZE != 0) + return dev_err_probe(dev, -EINVAL, + "DRC count(%u) not multiple of %u\n", + drc_count, ADAU1373_DRC_SIZE); + + adau1373->num_drc = drc_count / ADAU1373_DRC_SIZE; + if (adau1373->num_drc > ARRAY_SIZE(adau1373->drc_setting)) + return dev_err_probe(dev, -EINVAL, + "Too many DRC settings(%u)\n", + adau1373->num_drc); + + ret = device_property_read_u8_array(dev, "adi,drc-settings", + (u8 *)&adau1373->drc_setting[0], + drc_count); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read DRC settings\n"); + + return 0; +} + static int adau1373_i2c_probe(struct i2c_client *client) { struct adau1373 *adau1373; + struct gpio_desc *gpiod; int ret; adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL); @@ -1485,10 +1565,33 @@ static int adau1373_i2c_probe(struct i2c_client *client) if (IS_ERR(adau1373->regmap)) return PTR_ERR(adau1373->regmap); - regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + /* + * If the powerdown GPIO is specified, we use it for reset. Otherwise + * a software reset is done. + */ + gpiod = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + if (gpiod) { + gpiod_set_value_cansleep(gpiod, 0); + fsleep(10); + + ret = devm_add_action_or_reset(&client->dev, adau1373_reset, + gpiod); + if (ret) + return ret; + } else { + regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + } dev_set_drvdata(&client->dev, adau1373); + ret = adau1373_parse_fw(&client->dev, adau1373); + if (ret) + return ret; + ret = devm_snd_soc_register_component(&client->dev, &adau1373_component_driver, adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver)); @@ -1501,9 +1604,16 @@ static const struct i2c_device_id adau1373_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id); +static const struct of_device_id adau1373_of_match[] = { + { .compatible = "adi,adau1373", }, + { } +}; +MODULE_DEVICE_TABLE(of, adau1373_of_match); + static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", + .of_match_table = adau1373_of_match, }, .probe = adau1373_i2c_probe, .id_table = adau1373_i2c_id, diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c new file mode 100644 index 000000000000..58b8e002d76f --- /dev/null +++ b/sound/soc/codecs/aw88081.c @@ -0,0 +1,1087 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88081.c -- AW88081 ALSA SoC Audio driver +// +// Copyright (c) 2024 awinic Technology CO., LTD +// +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw88081.h" +#include "aw88395/aw88395_device.h" + +struct aw88081 { + struct aw_device *aw_pa; + struct mutex lock; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + bool phase_sync; +}; + +static const struct regmap_config aw88081_regmap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88081_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int aw88081_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88081_BIT_PLL_CHECK) != AW88081_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw88081_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static int aw88081_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88081_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88081_CCO_MUX_MASK); + if (reg_val == AW88081_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG, + ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG, + ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88081_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw88081_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88081_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return 0; +} + +static int aw88081_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + unsigned int value; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88081_PWMCTRL4_REG, ®_val); + if (ret) + return ret; + + if (reg_val & (~AW88081_NOISE_GATE_EN_MASK)) + check_val = AW88081_NO_SWS_SYSST_CHECK; + else + check_val = AW88081_SWS_SYSST_CHECK; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, ®_val); + if (ret) + return ret; + + value = reg_val & (~AW88081_BIT_SYSST_CHECK_MASK) & check_val; + if (value != check_val) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, check_val); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw88081_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + if (flag) + regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG, + ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG, + ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_DISABLE_VALUE); +} + +static void aw88081_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + if (pwd) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_PWDN_MASK, AW88081_PWDN_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_PWDN_MASK, AW88081_PWDN_WORKING_VALUE); +} + +static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + if (amppd) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_EN_PA_MASK, AW88081_EN_PA_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE); +} + +static void aw88081_dev_clear_int_status(struct aw_device *aw_dev) +{ + unsigned int int_status; + + /* read int status and clear */ + regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status); + /* make sure int status is clear */ + regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status); + + dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status); +} + +static void aw88081_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int volume; + + volume = min((value + vol_desc->init_volume), (unsigned int)AW88081_MUTE_VOL); + + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL2_REG, ~AW88081_VOL_MASK, volume); +} + +static void aw88081_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw88081_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88081_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88081_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88081_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88081_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88081_MUTE_VOL; i += fade_step) { + aw88081_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88081_MUTE_VOL) + aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL); +} + +static void aw88081_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw88081_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_HMUTE_MASK, AW88081_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_HMUTE_MASK, AW88081_HMUTE_DISABLE_VALUE); + aw88081_dev_fade_in(aw_dev); + } +} + +static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + if (uls_hmute) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_ULS_HMUTE_MASK, + AW88081_ULS_HMUTE_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_ULS_HMUTE_MASK, + AW88081_ULS_HMUTE_DISABLE_VALUE); +} + +static int aw88081_dev_reg_update(struct aw88081 *aw88081, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int read_vol; + int data_len, i, ret; + int16_t *reg_data; + u16 reg_val; + u8 reg_addr; + + if (!len || !data) { + dev_err(aw_dev->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88081_SYSCTRL_REG) { + reg_val &= ~(~AW88081_EN_PA_MASK | + ~AW88081_PWDN_MASK | + ~AW88081_HMUTE_MASK | + ~AW88081_ULS_HMUTE_MASK); + + reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE | + AW88081_PWDN_POWER_DOWN_VALUE | + AW88081_HMUTE_ENABLE_VALUE | + AW88081_ULS_HMUTE_ENABLE_VALUE; + } + + if (reg_addr == AW88081_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88081_VOL_MASK)) >> + AW88081_VOL_START_BIT; + aw_dev->volume_desc.init_volume = read_vol; + } + + /* i2stxen */ + if (reg_addr == AW88081_I2SCTRL3_REG) { + /* close tx */ + reg_val &= AW88081_I2STXEN_MASK; + reg_val |= AW88081_I2STXEN_DISABLE_VALUE; + } + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + return ret; + } + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + + /* keep min volume */ + aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume); + + return 0; +} + +static int aw88081_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} + +static int aw88081_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88081_dev_fw_update(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + ret = aw88081_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) { + dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88081_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw88081_dev_reg_update(aw88081, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; +} + +static int aw88081_dev_start(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + if (aw_dev->status == AW88081_DEV_PW_ON) { + dev_dbg(aw_dev->dev, "already power on"); + return 0; + } + + /* power on */ + aw88081_dev_pwd(aw_dev, false); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + + ret = aw88081_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw88081_dev_amppd(aw_dev, false); + usleep_range(AW88081_1000_US, AW88081_1000_US + 50); + + /* check i2s status */ + ret = aw88081_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + /* enable tx feedback */ + aw88081_dev_i2s_tx_enable(aw_dev, true); + + /* close uls mute */ + aw88081_dev_uls_hmute(aw_dev, false); + + /* close mute */ + aw88081_dev_mute(aw_dev, false); + + /* clear inturrupt */ + aw88081_dev_clear_int_status(aw_dev); + aw_dev->status = AW88081_DEV_PW_ON; + + return 0; + +sysst_check_fail: + aw88081_dev_i2s_tx_enable(aw_dev, false); + aw88081_dev_clear_int_status(aw_dev); + aw88081_dev_amppd(aw_dev, true); +pll_check_fail: + aw88081_dev_pwd(aw_dev, true); + aw_dev->status = AW88081_DEV_PW_OFF; + + return ret; +} + +static int aw88081_dev_stop(struct aw_device *aw_dev) +{ + if (aw_dev->status == AW88081_DEV_PW_OFF) { + dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88081_DEV_PW_OFF; + + /* clear inturrupt */ + aw88081_dev_clear_int_status(aw_dev); + + aw88081_dev_uls_hmute(aw_dev, true); + /* set mute */ + aw88081_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw88081_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88081_1000_US, AW88081_1000_US + 100); + + /* enable amppd */ + aw88081_dev_amppd(aw_dev, true); + + /* set power down */ + aw88081_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88081_reg_update(struct aw88081 *aw88081, bool force) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + if (force) { + ret = regmap_write(aw_dev->regmap, + AW88081_ID_REG, AW88081_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = aw88081_dev_fw_update(aw88081); + if (ret) + return ret; + } else { + if (aw_dev->prof_cur != aw_dev->prof_index) { + ret = aw88081_dev_fw_update(aw88081); + if (ret) + return ret; + } + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; +} + +static void aw88081_start_pa(struct aw88081 *aw88081) +{ + int ret, i; + + for (i = 0; i < AW88081_START_RETRIES; i++) { + ret = aw88081_reg_update(aw88081, aw88081->phase_sync); + if (ret) { + dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i); + continue; + } + ret = aw88081_dev_start(aw88081); + if (ret) { + dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i); + continue; + } else { + dev_dbg(aw88081->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88081_startup_work(struct work_struct *work) +{ + struct aw88081 *aw88081 = + container_of(work, struct aw88081, start_work.work); + + mutex_lock(&aw88081->lock); + aw88081_start_pa(aw88081); + mutex_unlock(&aw88081->lock); +} + +static void aw88081_start(struct aw88081 *aw88081, bool sync_start) +{ + if (aw88081->aw_pa->fw_status != AW88081_DEV_FW_OK) + return; + + if (aw88081->aw_pa->status == AW88081_DEV_PW_ON) + return; + + if (sync_start == AW88081_SYNC_START) + aw88081_start_pa(aw88081); + else + queue_delayed_work(system_wq, + &aw88081->start_work, + AW88081_START_WORK_DELAY_MS); +} + +static struct snd_soc_dai_driver aw88081_dai[] = { + { + .name = "aw88081-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88081_RATES, + .formats = AW88081_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88081_RATES, + .formats = AW88081_FORMATS, + }, + }, +}; + +static int aw88081_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88081->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88081_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88081->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88081_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88081->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88081_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88081->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + +static int aw88081_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + /* check the index whether is valid */ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + /* check the index whether change */ + if (aw_dev->prof_index == index) + return -EPERM; + + aw_dev->prof_index = index; + + return 0; +} + +static int aw88081_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + char *prof_name; + int count, ret; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88081->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + count = uinfo->value.enumerated.item; + + ret = aw88081_dev_get_prof_name(aw88081->aw_pa, count, &prof_name); + if (ret) { + strscpy(uinfo->value.enumerated.name, "null", + sizeof(uinfo->value.enumerated.name)); + return 0; + } + + strscpy(uinfo->value.enumerated.name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88081_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88081->aw_pa->prof_index; + + return 0; +} + +static int aw88081_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + int ret; + + /* pa stop or stopping just set profile */ + mutex_lock(&aw88081->lock); + ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88081->lock); + return 0; + } + + if (aw88081->aw_pa->status) { + aw88081_dev_stop(aw88081->aw_pa); + aw88081_start(aw88081, AW88081_SYNC_START); + } + + mutex_unlock(&aw88081->lock); + + return 1; +} + +static int aw88081_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88081_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (vol_desc->ctl_volume != value) { + vol_desc->ctl_volume = value; + aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume); + return 1; + } + + return 0; +} + +static int aw88081_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88081->aw_pa->fade_step; + + return 0; +} + +static int aw88081_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88081->aw_pa->fade_step != value) { + aw88081->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new aw88081_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88081_SYSCTRL2_REG, + 0, AW88081_MUTE_VOL, 0, aw88081_volume_get, + aw88081_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88081_MUTE_VOL, 0, + aw88081_get_fade_step, aw88081_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, 0, + aw88081_get_fade_in_time, aw88081_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, 0, + aw88081_get_fade_out_time, aw88081_set_fade_out_time), + AW88081_PROFILE_EXT("Profile Set", aw88081_profile_info, + aw88081_profile_get, aw88081_profile_set), +}; + +static void aw88081_parse_channel_dt(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW88081_DEV_DEFAULT_CH; + + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + aw88081->phase_sync = of_property_read_bool(np, "awinic,sync-flag"); + + aw_dev->channel = channel_value; +} + +static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + /* read chip id */ + ret = regmap_read(regmap, AW88081_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88081_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + + dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + aw88081->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW88081_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->fade_step = AW88081_VOLUME_STEP_DB; + aw_dev->volume_desc.mute_volume = AW88081_MUTE_VOL; + aw88081_parse_channel_dt(aw88081); + + return 0; +} + +static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + + ret = regmap_write(aw_dev->regmap, AW88081_ID_REG, AW88081_SOFT_RESET_VALUE); + if (ret) + return ret; + + aw_dev->fade_in_time = AW88081_500_US; + aw_dev->fade_out_time = AW88081_500_US; + aw_dev->prof_cur = AW88081_INIT_PROFILE; + aw_dev->prof_index = AW88081_INIT_PROFILE; + + ret = aw88081_dev_fw_update(aw88081); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + aw88081_dev_clear_int_status(aw_dev); + + aw88081_dev_uls_hmute(aw_dev, true); + + aw88081_dev_mute(aw_dev, true); + + usleep_range(AW88081_5000_US, AW88081_5000_US + 10); + + aw88081_dev_i2s_tx_enable(aw_dev, false); + + usleep_range(AW88081_1000_US, AW88081_1000_US + 100); + + aw88081_dev_amppd(aw_dev, true); + + aw88081_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88081_request_firmware_file(struct aw88081 *aw88081) +{ + const struct firmware *cont = NULL; + int ret; + + aw88081->aw_pa->fw_status = AW88081_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88081_ACF_FILE, aw88081->aw_pa->dev); + if (ret) + return ret; + + dev_dbg(aw88081->aw_pa->dev, "loaded %s - size: %zu\n", + AW88081_ACF_FILE, cont ? cont->size : 0); + + aw88081->aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88081->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88081->aw_cfg->len = (int)cont->size; + memcpy(aw88081->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg); + if (ret) + return ret; + + mutex_lock(&aw88081->lock); + ret = aw88081_dev_init(aw88081, aw88081->aw_cfg); + mutex_unlock(&aw88081->lock); + + return ret; +} + +static int aw88081_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88081->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88081_start(aw88081, AW88081_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88081_dev_stop(aw88081->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88081->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88081_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0, + aw88081_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("DAC Output"), + + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("ADC Input"), +}; + +static const struct snd_soc_dapm_route aw88081_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88081_codec_probe(struct snd_soc_component *component) +{ + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88081->start_work, aw88081_startup_work); + + ret = aw88081_request_firmware_file(aw88081); + if (ret) + dev_err(aw88081->aw_pa->dev, "%s: request firmware failed\n", __func__); + + return ret; +} + +static void aw88081_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88081->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88081 = { + .probe = aw88081_codec_probe, + .remove = aw88081_codec_remove, + .dapm_widgets = aw88081_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aw88081_dapm_widgets), + .dapm_routes = aw88081_audio_map, + .num_dapm_routes = ARRAY_SIZE(aw88081_audio_map), + .controls = aw88081_controls, + .num_controls = ARRAY_SIZE(aw88081_controls), +}; + +static int aw88081_i2c_probe(struct i2c_client *i2c) +{ + struct aw88081 *aw88081; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed"); + + aw88081 = devm_kzalloc(&i2c->dev, sizeof(*aw88081), GFP_KERNEL); + if (!aw88081) + return -ENOMEM; + + mutex_init(&aw88081->lock); + + i2c_set_clientdata(i2c, aw88081); + + aw88081->regmap = devm_regmap_init_i2c(i2c, &aw88081_regmap_config); + if (IS_ERR(aw88081->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap), + "failed to init regmap\n"); + + /* aw pa init */ + ret = aw88081_init(aw88081, i2c, aw88081->regmap); + if (ret) + return ret; + + return devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88081, + aw88081_dai, ARRAY_SIZE(aw88081_dai)); +} + +static const struct i2c_device_id aw88081_i2c_id[] = { + { AW88081_I2C_NAME }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id); + +static struct i2c_driver aw88081_i2c_driver = { + .driver = { + .name = AW88081_I2C_NAME, + }, + .probe = aw88081_i2c_probe, + .id_table = aw88081_i2c_id, +}; +module_i2c_driver(aw88081_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88081 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h new file mode 100644 index 000000000000..b4bf7288021a --- /dev/null +++ b/sound/soc/codecs/aw88081.h @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88081.h -- AW88081 ALSA SoC Audio driver +// +// Copyright (c) 2024 awinic Technology CO., LTD +// +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#ifndef __AW88081_H__ +#define __AW88081_H__ + +#define AW88081_ID_REG (0x00) +#define AW88081_SYSST_REG (0x01) +#define AW88081_SYSINT_REG (0x02) +#define AW88081_SYSINTM_REG (0x03) +#define AW88081_SYSCTRL_REG (0x04) +#define AW88081_SYSCTRL2_REG (0x05) +#define AW88081_I2SCTRL1_REG (0x06) +#define AW88081_I2SCTRL2_REG (0x07) +#define AW88081_I2SCTRL3_REG (0x08) +#define AW88081_DACCFG1_REG (0x09) +#define AW88081_DACCFG2_REG (0x0A) +#define AW88081_DACCFG3_REG (0x0B) +#define AW88081_DACCFG4_REG (0x0C) +#define AW88081_DACCFG5_REG (0x0D) +#define AW88081_DACCFG6_REG (0x0E) +#define AW88081_DACCFG7_REG (0x11) +#define AW88081_PWMCTRL1_REG (0x13) +#define AW88081_PWMCTRL2_REG (0x14) +#define AW88081_PWMCTRL3_REG (0x15) +#define AW88081_PWMCTRL4_REG (0x16) +#define AW88081_I2SCFG1_REG (0x17) +#define AW88081_DBGCTRL_REG (0x18) +#define AW88081_PDMCTRL_REG (0x19) +#define AW88081_DACST_REG (0x20) +#define AW88081_PATTERNST_REG (0x21) +#define AW88081_I2SINT_REG (0x26) +#define AW88081_I2SCAPCNT_REG (0x27) +#define AW88081_ANASTA1_REG (0x28) +#define AW88081_ANASTA2_REG (0x29) +#define AW88081_ANASTA3_REG (0x2A) +#define AW88081_VBAT_REG (0x21) +#define AW88081_TEMP_REG (0x22) +#define AW88081_PVDD_REG (0x23) +#define AW88081_ISNDAT_REG (0x24) +#define AW88081_VSNDAT_REG (0x25) +#define AW88081_DSMCFG1_REG (0x30) +#define AW88081_DSMCFG2_REG (0x31) +#define AW88081_DSMCFG3_REG (0x32) +#define AW88081_DSMCFG4_REG (0x33) +#define AW88081_DSMCFG5_REG (0x34) +#define AW88081_DSMCFG6_REG (0x35) +#define AW88081_DSMCFG7_REG (0x36) +#define AW88081_DSMCFG8_REG (0x37) +#define AW88081_TESTIN_REG (0x38) +#define AW88081_TESTOUT_REG (0x39) +#define AW88081_BOPCTRL1_REG (0x40) +#define AW88081_BOPCTRL2_REG (0x41) +#define AW88081_BOPCTRL3_REG (0x42) +#define AW88081_BOPSTA_REG (0x43) +#define AW88081_PLLCTRL1_REG (0x54) +#define AW88081_PLLCTRL2_REG (0x55) +#define AW88081_PLLCTRL3_REG (0x56) +#define AW88081_CDACTRL1_REG (0x57) +#define AW88081_CDACTRL2_REG (0x58) +#define AW88081_CDACTRL3_REG (0x59) +#define AW88081_DITHERCFG1_REG (0x5A) +#define AW88081_DITHERCFG2_REG (0x5B) +#define AW88081_DITHERCFG3_REG (0x5C) +#define AW88081_TM_REG (0x6E) +#define AW88081_TM2_REG (0x6F) +#define AW88081_TESTCTRL1_REG (0x70) +#define AW88081_TESTCTRL2_REG (0x71) + +#define AW88081_REG_MAX (0x72) + +#define AW88081_UVLS_START_BIT (14) +#define AW88081_UVLS_UVLO (1) +#define AW88081_UVLS_UVLO_VALUE \ + (AW88081_UVLS_UVLO << AW88081_UVLS_START_BIT) + +#define AW88081_SWS_START_BIT (8) +#define AW88081_SWS_SWITCHING (1) +#define AW88081_SWS_SWITCHING_VALUE \ + (AW88081_SWS_SWITCHING << AW88081_SWS_START_BIT) + +#define AW88081_NOCLKS_START_BIT (5) +#define AW88081_NOCLKS_NO_CLOCK (1) +#define AW88081_NOCLKS_NO_CLOCK_VALUE \ + (AW88081_NOCLKS_NO_CLOCK << AW88081_NOCLKS_START_BIT) + +#define AW88081_CLKS_START_BIT (4) +#define AW88081_CLKS_STABLE (1) +#define AW88081_CLKS_STABLE_VALUE \ + (AW88081_CLKS_STABLE << AW88081_CLKS_START_BIT) + +#define AW88081_OCDS_START_BIT (3) +#define AW88081_OCDS_OC (1) +#define AW88081_OCDS_OC_VALUE \ + (AW88081_OCDS_OC << AW88081_OCDS_START_BIT) + +#define AW88081_OTHS_START_BIT (1) +#define AW88081_OTHS_OT (1) +#define AW88081_OTHS_OT_VALUE \ + (AW88081_OTHS_OT << AW88081_OTHS_START_BIT) + +#define AW88081_PLLS_START_BIT (0) +#define AW88081_PLLS_LOCKED (1) +#define AW88081_PLLS_LOCKED_VALUE \ + (AW88081_PLLS_LOCKED << AW88081_PLLS_START_BIT) + +#define AW88081_BIT_PLL_CHECK \ + (AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_BIT_SYSST_CHECK_MASK \ + (~(AW88081_UVLS_UVLO_VALUE | \ + AW88081_SWS_SWITCHING_VALUE | \ + AW88081_NOCLKS_NO_CLOCK_VALUE | \ + AW88081_CLKS_STABLE_VALUE | \ + AW88081_OCDS_OC_VALUE | \ + AW88081_OTHS_OT_VALUE | \ + AW88081_PLLS_LOCKED_VALUE)) + +#define AW88081_NO_SWS_SYSST_CHECK \ + (AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_SWS_SYSST_CHECK \ + (AW88081_SWS_SWITCHING_VALUE | \ + AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_ULS_HMUTE_START_BIT (14) +#define AW88081_ULS_HMUTE_BITS_LEN (1) +#define AW88081_ULS_HMUTE_MASK \ + (~(((1<<AW88081_ULS_HMUTE_BITS_LEN)-1) << AW88081_ULS_HMUTE_START_BIT)) + +#define AW88081_ULS_HMUTE_DISABLE (0) +#define AW88081_ULS_HMUTE_DISABLE_VALUE \ + (AW88081_ULS_HMUTE_DISABLE << AW88081_ULS_HMUTE_START_BIT) + +#define AW88081_ULS_HMUTE_ENABLE (1) +#define AW88081_ULS_HMUTE_ENABLE_VALUE \ + (AW88081_ULS_HMUTE_ENABLE << AW88081_ULS_HMUTE_START_BIT) + +#define AW88081_HMUTE_START_BIT (8) +#define AW88081_HMUTE_BITS_LEN (1) +#define AW88081_HMUTE_MASK \ + (~(((1<<AW88081_HMUTE_BITS_LEN)-1) << AW88081_HMUTE_START_BIT)) + +#define AW88081_HMUTE_DISABLE (0) +#define AW88081_HMUTE_DISABLE_VALUE \ + (AW88081_HMUTE_DISABLE << AW88081_HMUTE_START_BIT) + +#define AW88081_HMUTE_ENABLE (1) +#define AW88081_HMUTE_ENABLE_VALUE \ + (AW88081_HMUTE_ENABLE << AW88081_HMUTE_START_BIT) + +#define AW88081_EN_PA_START_BIT (1) +#define AW88081_EN_PA_BITS_LEN (1) +#define AW88081_EN_PA_MASK \ + (~(((1<<AW88081_EN_PA_BITS_LEN)-1) << AW88081_EN_PA_START_BIT)) + +#define AW88081_EN_PA_WORKING (1) +#define AW88081_EN_PA_WORKING_VALUE \ + (AW88081_EN_PA_WORKING << AW88081_EN_PA_START_BIT) + +#define AW88081_EN_PA_POWER_DOWN (0) +#define AW88081_EN_PA_POWER_DOWN_VALUE \ + (AW88081_EN_PA_POWER_DOWN << AW88081_EN_PA_START_BIT) + +#define AW88081_PWDN_START_BIT (0) +#define AW88081_PWDN_BITS_LEN (1) +#define AW88081_PWDN_MASK \ + (~(((1<<AW88081_PWDN_BITS_LEN)-1) << AW88081_PWDN_START_BIT)) + +#define AW88081_PWDN_WORKING (0) +#define AW88081_PWDN_WORKING_VALUE \ + (AW88081_PWDN_WORKING << AW88081_PWDN_START_BIT) + +#define AW88081_PWDN_POWER_DOWN (1) +#define AW88081_PWDN_POWER_DOWN_VALUE \ + (AW88081_PWDN_POWER_DOWN << AW88081_PWDN_START_BIT) + +#define AW88081_VOL_START_BIT (0) +#define AW88081_VOL_BITS_LEN (10) +#define AW88081_VOL_MASK \ + (~(((1<<AW88081_VOL_BITS_LEN)-1) << AW88081_VOL_START_BIT)) + +#define AW88081_VOLUME_STEP_DB (64) +#define AW88081_MUTE_VOL (1023) + +#define AW88081_I2STXEN_START_BIT (6) +#define AW88081_I2STXEN_BITS_LEN (1) +#define AW88081_I2STXEN_MASK \ + (~(((1<<AW88081_I2STXEN_BITS_LEN)-1) << AW88081_I2STXEN_START_BIT)) + +#define AW88081_I2STXEN_DISABLE (0) +#define AW88081_I2STXEN_DISABLE_VALUE \ + (AW88081_I2STXEN_DISABLE << AW88081_I2STXEN_START_BIT) + +#define AW88081_I2STXEN_ENABLE (1) +#define AW88081_I2STXEN_ENABLE_VALUE \ + (AW88081_I2STXEN_ENABLE << AW88081_I2STXEN_START_BIT) + +#define AW88081_NOISE_GATE_EN_START_BIT (13) +#define AW88081_NOISE_GATE_EN_BITS_LEN (1) +#define AW88081_NOISE_GATE_EN_MASK \ + (~(((1<<AW88081_NOISE_GATE_EN_BITS_LEN)-1) << AW88081_NOISE_GATE_EN_START_BIT)) + +#define AW88081_NOISE_GATE_EN_DISABLE (0) +#define AW88081_NOISE_GATE_EN_DISABLE_VALUE \ + (AW88081_NOISE_GATE_EN_DISABLE << AW88081_NOISE_GATE_EN_START_BIT) + +#define AW88081_NOISE_GATE_EN_ENABLE (1) +#define AW88081_NOISE_GATE_EN_ENABLE_VALUE \ + (AW88081_NOISE_GATE_EN_ENABLE << AW88081_NOISE_GATE_EN_START_BIT) + +#define AW88081_CCO_MUX_START_BIT (13) +#define AW88081_CCO_MUX_BITS_LEN (1) +#define AW88081_CCO_MUX_MASK \ + (~(((1<<AW88081_CCO_MUX_BITS_LEN)-1) << AW88081_CCO_MUX_START_BIT)) + +#define AW88081_CCO_MUX_DIVIDED (0) +#define AW88081_CCO_MUX_DIVIDED_VALUE \ + (AW88081_CCO_MUX_DIVIDED << AW88081_CCO_MUX_START_BIT) + +#define AW88081_CCO_MUX_BYPASS (1) +#define AW88081_CCO_MUX_BYPASS_VALUE \ + (AW88081_CCO_MUX_BYPASS << AW88081_CCO_MUX_START_BIT) + +#define AW88081_START_RETRIES (5) +#define AW88081_START_WORK_DELAY_MS (0) + +#define AW88081_I2C_NAME "aw88081" +#define AW88081_CHIP_ID 0x2116 + +#define AW88081_RATES (SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_96000) +#define AW88081_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define FADE_TIME_MAX 100000 + +#define AW88081_DEV_DEFAULT_CH (0) +#define AW88081_ACF_FILE "aw88081_acf.bin" +#define AW88081_DEV_SYSST_CHECK_MAX (10) +#define AW88081_SOFT_RESET_VALUE (0x55aa) + +#define AW88081_INIT_PROFILE (0) + +#define AW88081_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = profile_info, \ + .get = profile_get, \ + .put = profile_set, \ +} + +enum { + AW88081_SYNC_START = 0, + AW88081_ASYNC_START, +}; + +enum { + AW88081_500_US = 500, + AW88081_1000_US = 1000, + AW88081_2000_US = 2000, + AW88081_5000_US = 5000, +}; + +enum { + AW88081_DEV_PW_OFF = 0, + AW88081_DEV_PW_ON, +}; + +enum { + AW88081_DEV_FW_FAILED = 0, + AW88081_DEV_FW_OK, +}; + +#endif diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index fd1f67d5f22f..6b333d1c6e94 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -703,7 +703,7 @@ static int aw_dev_set_vcalb(struct aw_device *aw_dev) AW88395_VSCAL_FACTOR_DAC, icalk, vcalk); break; default: - dev_err(aw_dev->dev, "unsupport vsense status"); + dev_err(aw_dev->dev, "unsupported vsense status"); return -EINVAL; } diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 769ca32a5c8e..ceb7fc43d018 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -688,7 +688,7 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info); break; default: - dev_err(aw_dev->dev, "unsupport data type\n"); + dev_err(aw_dev->dev, "unsupported data type\n"); ret = -EINVAL; break; } diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index bba59885242d..ee3cc2a95f85 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -462,7 +462,7 @@ static int aw_dev_set_vcalb(struct aw88399 *aw88399) vcal_k * aw88399->vcalb_init_val; break; default: - dev_err(aw_dev->dev, "%s: unsupport vsense\n", __func__); + dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); ret = -EINVAL; break; } diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 4f9dabd9d78a..04304a7ad915 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -1649,7 +1649,7 @@ static int cpcap_soc_probe(struct snd_soc_component *component) return cpcap_audio_reset(component, false); } -static struct snd_soc_component_driver soc_codec_dev_cpcap = { +static const struct snd_soc_component_driver soc_codec_dev_cpcap = { .probe = cpcap_soc_probe, .controls = cpcap_snd_controls, .num_controls = ARRAY_SIZE(cpcap_snd_controls), diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c new file mode 100644 index 000000000000..17d5c96e334d --- /dev/null +++ b/sound/soc/codecs/cs42l84.c @@ -0,0 +1,1111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l84.c -- CS42L84 ALSA SoC audio driver + * + * Copyright (C) The Asahi Linux Contributors + * + * Based on sound/soc/codecs/cs42l42{.c,.h} + * Copyright 2016 Cirrus Logic, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/of_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "cs42l84.h" +#include "cirrus_legacy.h" + +struct cs42l84_private { + struct regmap *regmap; + struct device *dev; + struct gpio_desc *reset_gpio; + struct snd_soc_jack *jack; + struct mutex irq_lock; + u8 tip_state; + u8 ring_state; + int pll_config; + int bclk; + u8 pll_mclk_f; + u32 srate; + u8 stream_use; + int hs_type; +}; + +static bool cs42l84_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L84_DEVID ... CS42L84_DEVID+5: + case CS42L84_TSRS_PLUG_INT_STATUS: + case CS42L84_PLL_LOCK_STATUS: + case CS42L84_TSRS_PLUG_STATUS: + case CS42L84_HS_DET_STATUS2: + return true; + default: + return false; + } +} + +static const struct regmap_config cs42l84_regmap = { + .reg_bits = 16, + .val_bits = 8, + + .volatile_reg = cs42l84_volatile_register, + + .max_register = 0x73fe, + + .cache_type = REGCACHE_MAPLE, + + .use_single_read = true, + .use_single_write = true, +}; + +static int cs42l84_put_dac_vol(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *val) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; + int vola, volb; + int ret, ret2, updated = 0; + + vola = val->value.integer.value[0] + mc->min; + volb = val->value.integer.value[1] + mc->min; + + if (vola < mc->min || vola > mc->max || volb < mc->min || volb > mc->max) + return -EINVAL; + + ret = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, + CS42L84_FRZ_CTL_ENGAGE, + CS42L84_FRZ_CTL_ENGAGE); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_LSB, + 0xff, vola & 0xff); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_MSB, + 0xff, (vola >> 8) & 0x01); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_LSB, + 0xff, volb & 0xff); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_MSB, + 0xff, (volb >> 8) & 0x01); + if (ret < 0) + goto bail; + ret |= updated; + +bail: + ret2 = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, + CS42L84_FRZ_CTL_ENGAGE, 0); + if (ret2 < 0 && ret >= 0) + ret = ret2; + + return ret; +} + +static int cs42l84_get_dac_vol(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *val) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; + int vola, volb; + int ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_LSB); + if (ret < 0) + return ret; + vola = ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_MSB); + if (ret < 0) + return ret; + vola |= (ret & 1) << 8; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_LSB); + if (ret < 0) + return ret; + volb = ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_MSB); + if (ret < 0) + return ret; + volb |= (ret & 1) << 8; + + if (vola & BIT(8)) + vola |= ~((int)(BIT(8) - 1)); + if (volb & BIT(8)) + volb |= ~((int)(BIT(8) - 1)); + + val->value.integer.value[0] = vola - mc->min; + val->value.integer.value[1] = volb - mc->min; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(cs42l84_dac_tlv, -12800, 50, true); +static const DECLARE_TLV_DB_SCALE(cs42l84_adc_tlv, -1200, 50, false); +static const DECLARE_TLV_DB_SCALE(cs42l84_pre_tlv, 0, 1000, false); + +static const struct snd_kcontrol_new cs42l84_snd_controls[] = { + SOC_DOUBLE_R_S_EXT_TLV("DAC Playback Volume", CS42L84_DAC_CHA_VOL_LSB, + CS42L84_DAC_CHB_VOL_LSB, 0, -256, 24, 8, 0, + cs42l84_get_dac_vol, cs42l84_put_dac_vol, cs42l84_dac_tlv), + SOC_SINGLE_TLV("ADC Preamp Capture Volume", CS42L84_ADC_CTL1, + CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT, 2, 0, cs42l84_pre_tlv), + SOC_SINGLE_TLV("ADC PGA Capture Volume", CS42L84_ADC_CTL1, + CS42L84_ADC_CTL1_PGA_GAIN_SHIFT, 24, 0, cs42l84_adc_tlv), + SOC_SINGLE("ADC WNF Switch", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("WNF Corner Frequency", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_WNF_CF_SHIFT, 3, 0), + SOC_SINGLE("ADC HPF Switch", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("HPF Corner Frequency", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_HPF_CF_SHIFT, 3, 0), +}; + +static const char * const cs42l84_mux_text[] = { + "Blank", "ADC", "ASP RX CH1", "ASP RX CH2", +}; + +static const unsigned int cs42l84_mux_values[] = { + 0b0000, 0b0111, 0b1101, 0b1110, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_daca_mux_enum, + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACA_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_dacb_mux_enum, + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACB_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_sdout1_mux_enum, + CS42L84_BUS_ASP_TX_SRC, CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static const struct snd_kcontrol_new cs42l84_daca_mux_ctrl = + SOC_DAPM_ENUM("DACA Select", cs42l84_daca_mux_enum); + +static const struct snd_kcontrol_new cs42l84_dacb_mux_ctrl = + SOC_DAPM_ENUM("DACB Select", cs42l84_dacb_mux_enum); + +static const struct snd_kcontrol_new cs42l84_sdout1_mux_ctrl = + SOC_DAPM_ENUM("SDOUT1 Select", cs42l84_sdout1_mux_enum); + +static const struct snd_soc_dapm_widget cs42l84_dapm_widgets[] = { + /* Playback Path */ + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_DAC("DAC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_DAC_SHIFT, 0), + SND_SOC_DAPM_MUX("DACA Select", SND_SOC_NOPM, 0, 0, &cs42l84_daca_mux_ctrl), + SND_SOC_DAPM_MUX("DACB Select", SND_SOC_NOPM, 0, 0, &cs42l84_dacb_mux_ctrl), + SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH1_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH2_SHIFT, 0), + + /* Capture Path */ + SND_SOC_DAPM_INPUT("HS"), + SND_SOC_DAPM_ADC("ADC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ADC_SHIFT, 0), + SND_SOC_DAPM_MUX("SDOUT1 Select", SND_SOC_NOPM, 0, 0, &cs42l84_sdout1_mux_ctrl), + SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L84_ASP_TX_EN, CS42L84_ASP_TX_EN_CH1_SHIFT, 0), + + /* Playback/Capture Requirements */ + SND_SOC_DAPM_SUPPLY("BUS", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_BUS_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASP", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ASP_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BCLK", CS42L84_ASP_CTL, CS42L84_ASP_CTL_BCLK_EN_SHIFT, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route cs42l84_audio_map[] = { + /* Playback Path */ + {"HP", NULL, "DAC"}, + {"DAC", NULL, "DACA Select"}, + {"DAC", NULL, "DACB Select"}, + {"DACA Select", "ASP RX CH1", "SDIN1"}, + {"DACA Select", "ASP RX CH2", "SDIN2"}, + {"DACB Select", "ASP RX CH1", "SDIN1"}, + {"DACB Select", "ASP RX CH2", "SDIN2"}, + {"SDIN1", NULL, "Playback"}, + {"SDIN2", NULL, "Playback"}, + + {"ADC", NULL, "HS"}, + {"SDOUT1 Select", "ADC", "ADC"}, + {"SDOUT1", NULL, "SDOUT1 Select"}, + {"Capture", NULL, "SDOUT1"}, + + /* Playback Requirements */ + {"DAC", NULL, "BUS"}, + {"SDIN1", NULL, "ASP"}, + {"SDIN2", NULL, "ASP"}, + {"SDIN1", NULL, "BCLK"}, + {"SDIN2", NULL, "BCLK"}, + + /* Capture Requirements */ + {"SDOUT1", NULL, "BUS"}, + {"SDOUT1", NULL, "ASP"}, + {"SDOUT1", NULL, "BCLK"}, +}; + +static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d) +{ + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + + /* Prevent race with interrupt handler */ + mutex_lock(&cs42l84->irq_lock); + cs42l84->jack = jk; + snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); + mutex_unlock(&cs42l84->irq_lock); + + return 0; +} + +static int cs42l84_component_probe(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, CS42L84_ASP_CTL, + CS42L84_ASP_CTL_TDM_MODE, 0); + snd_soc_component_update_bits(component, CS42L84_HP_VOL_CTL, + CS42L84_HP_VOL_CTL_SOFT | CS42L84_HP_VOL_CTL_ZERO_CROSS, + CS42L84_HP_VOL_CTL_ZERO_CROSS); + + /* TDM settings */ + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, + CS42L84_ASP_RX_CHx_CTL1_EDGE); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, + CS42L84_ASP_RX_CHx_CTL1_EDGE); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + /* Routing defaults */ + snd_soc_component_write(component, CS42L84_BUS_DAC_SRC, + 0b1101 << CS42L84_BUS_DAC_SRC_DACA_SHIFT | + 0b1110 << CS42L84_BUS_DAC_SRC_DACB_SHIFT); + snd_soc_component_write(component, CS42L84_BUS_ASP_TX_SRC, + 0b0111 << CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_cs42l84 = { + .set_jack = cs42l84_set_jack, + .probe = cs42l84_component_probe, + .controls = cs42l84_snd_controls, + .num_controls = ARRAY_SIZE(cs42l84_snd_controls), + .dapm_widgets = cs42l84_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l84_dapm_widgets), + .dapm_routes = cs42l84_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l84_audio_map), + .endianness = 1, +}; + +struct cs42l84_pll_params { + u32 bclk; + u8 mclk_src_sel; + u8 bclk_prediv; + u8 pll_div_int; + u32 pll_div_frac; + u8 pll_mode; + u8 pll_divout; + u32 mclk_int; +}; + +/* + * Common PLL Settings for given BCLK + */ +static const struct cs42l84_pll_params pll_ratio_table[] = { + { 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000}, + { 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000}, + { 12288000, 0, 0, 0, 0, 0, 0, 12288000}, + { 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000}, +}; + +static int cs42l84_pll_config(struct snd_soc_component *component) +{ + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int i; + u32 clk; + u32 fsync; + + clk = cs42l84->bclk; + + /* Don't reconfigure if there is an audio stream running */ + if (cs42l84->stream_use) { + if (pll_ratio_table[cs42l84->pll_config].bclk == clk) + return 0; + else + return -EBUSY; + } + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].bclk == clk) { + cs42l84->pll_config = i; + break; + } + } + + if (i == ARRAY_SIZE(pll_ratio_table)) + return -EINVAL; + + /* Set up the LRCLK */ + fsync = clk / cs42l84->srate; + if (((fsync * cs42l84->srate) != clk) + || ((fsync % 2) != 0)) { + dev_err(component->dev, + "Unsupported bclk %d/sample rate %d\n", + clk, cs42l84->srate); + return -EINVAL; + } + + /* Set the LRCLK period */ + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL2, + CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, + FIELD_PREP(CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, fsync & 0x7f)); + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL3, + CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, + FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7)); + + /* Save what the MCLK will be */ + switch (pll_ratio_table[i].mclk_int) { + case 12000000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ; + break; + case 12288000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ; + break; + case 24000000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24MHZ; + break; + case 24576000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24_576KHZ; + break; + } + + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_EN, 0); + + if (pll_ratio_table[i].mclk_src_sel) { + /* Configure PLL */ + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL3, CS42L84_CCM_CTL3_REFCLK_DIV, + FIELD_PREP(CS42L84_CCM_CTL3_REFCLK_DIV, pll_ratio_table[i].bclk_prediv)); + snd_soc_component_write(component, + CS42L84_PLL_DIV_INT, + pll_ratio_table[i].pll_div_int); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC0, + pll_ratio_table[i].pll_div_frac); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC1, + pll_ratio_table[i].pll_div_frac >> 8); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC2, + pll_ratio_table[i].pll_div_frac >> 16); + snd_soc_component_update_bits(component, + CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_MODE, + FIELD_PREP(CS42L84_PLL_CTL1_MODE, pll_ratio_table[i].pll_mode)); + snd_soc_component_write(component, + CS42L84_PLL_DIVOUT, + pll_ratio_table[i].pll_divout); + } + + return 0; +} + +static int cs42l84_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + default: + return -EINVAL; + } + + /* Bitclock/frame inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs42l84_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int ret; + u32 ccm_samp_rate; + + cs42l84->srate = params_rate(params); + + ret = cs42l84_pll_config(component); + if (ret) + return ret; + + switch (params_rate(params)) { + case 44100: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_44K1HZ; + break; + case 48000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_48KHZ; + break; + case 88200: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_88K2HZ; + break; + case 96000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_96KHZ; + break; + case 176400: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_176K4HZ; + break; + case 192000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_192KHZ; + break; + default: + return -EINVAL; + } + + snd_soc_component_write(component, CS42L84_CCM_SAMP_RATE, ccm_samp_rate); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + snd_soc_component_write(component, CS42L84_ASP_RX_CH1_WIDTH, + params_width(params) - 1); + snd_soc_component_write(component, CS42L84_ASP_RX_CH2_WIDTH, + params_width(params) - 1); + break; + + case SNDRV_PCM_STREAM_CAPTURE: + snd_soc_component_write(component, CS42L84_ASP_TX_CH1_WIDTH, + params_width(params) - 1); + snd_soc_component_write(component, CS42L84_ASP_TX_CH2_WIDTH, + params_width(params) - 1); + break; + } + + return 0; +} + +static int cs42l84_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int i; + + if (freq == 0) { + cs42l84->bclk = 0; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].bclk == freq) { + cs42l84->bclk = freq; + return 0; + } + } + + dev_err(component->dev, "BCLK %u not supported\n", freq); + + return -EINVAL; +} + +static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + unsigned int regval; + int ret; + + if (mute) { + /* Mute the headphone */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, + CS42L84_DAC_CTL1_UNMUTE, 0); + cs42l84->stream_use &= ~(1 << stream); + if (!cs42l84->stream_use) { + /* Must disconnect PLL before stopping it */ + snd_soc_component_write(component, CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_RCO); + + usleep_range(150, 300); + + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, + CS42L84_PLL_CTL1_EN, 0); + + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, + CS42L84_CCM_CTL4_REFCLK_EN, 0); + } + } else { + if (!cs42l84->stream_use) { + /* SCLK must be running before codec unmute. + * + * Note carried over from CS42L42: + * + * PLL must not be started with ADC and HP both off + * otherwise the FILT+ supply will not charge properly. + * DAPM widgets power-up before stream unmute so at least + * one of the "DAC" or "ADC" widgets will already have + * powered-up. + */ + + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, + CS42L84_CCM_CTL4_REFCLK_EN, + CS42L84_CCM_CTL4_REFCLK_EN); + + if (pll_ratio_table[cs42l84->pll_config].mclk_src_sel) { + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, + CS42L84_PLL_CTL1_EN, + CS42L84_PLL_CTL1_EN); + /* TODO: should we be doing something with divout here? */ + + ret = regmap_read_poll_timeout(cs42l84->regmap, + CS42L84_PLL_LOCK_STATUS, + regval, + (regval & CS42L84_PLL_LOCK_STATUS_LOCKED), + CS42L84_PLL_LOCK_POLL_US, + CS42L84_PLL_LOCK_TIMEOUT_US); + if (ret < 0) + dev_warn(component->dev, "PLL failed to lock: %d\n", ret); + + if (regval & CS42L84_PLL_LOCK_STATUS_ERROR) + dev_warn(component->dev, "PLL lock error\n"); + + /* PLL must be running to drive glitchless switch logic */ + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_PLL) + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); + } else { + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_BCLK) + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); + } + } + cs42l84->stream_use |= 1 << stream; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + /* Un-mute the headphone */ + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, + CS42L84_DAC_CTL1_UNMUTE, + CS42L84_DAC_CTL1_UNMUTE); + } + + return 0; +} + +static const struct snd_soc_dai_ops cs42l84_ops = { + .hw_params = cs42l84_pcm_hw_params, + .set_fmt = cs42l84_set_dai_fmt, + .set_sysclk = cs42l84_set_sysclk, + .mute_stream = cs42l84_mute_stream, +}; + +#define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver cs42l84_dai = { + .name = "cs42l84", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = CS42L84_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = CS42L84_FORMATS, + }, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + .ops = &cs42l84_ops, +}; + +struct cs42l84_irq_params { + u16 status_addr; + u16 mask_addr; + u8 mask; +}; + +static const struct cs42l84_irq_params irq_params_table[] = { + {CS42L84_TSRS_PLUG_INT_STATUS, CS42L84_TSRS_PLUG_INT_MASK, + CS42L84_TSRS_PLUG_VAL_MASK} +}; + +static void cs42l84_detect_hs(struct cs42l84_private *cs42l84) +{ + unsigned int reg; + + /* Power up HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 3) | /* 2.7 V */ + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); + + /* Power up level detection circuitry */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 0); + + /* TODO: Optimize */ + msleep(50); + + /* Connect HSBIAS in CTIA wiring */ + /* TODO: Should likely be subject of detection */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 0)); + + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 3)); + + /* TODO: Optimize */ + msleep(50); + + regmap_read(cs42l84->regmap, CS42L84_HS_DET_STATUS2, ®); + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET); + + switch (reg & 0b11) { + case 0b11: /* shorted */ + case 0b00: /* open */ + /* Power down HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1)); /* 0.0 V */ + break; + } + + switch (reg & 0b11) { + case 0b10: /* load */ + dev_dbg(cs42l84->dev, "Detected mic\n"); + cs42l84->hs_type = SND_JACK_HEADSET; + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADSET, + SND_JACK_HEADSET); + break; + + case 0b00: /* open */ + dev_dbg(cs42l84->dev, "Detected open circuit on HS4\n"); + fallthrough; + case 0b11: /* shorted */ + default: + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + cs42l84->hs_type = SND_JACK_HEADPHONE; + dev_dbg(cs42l84->dev, "Detected bare headphone (no mic)\n"); + break; + } +} + +static void cs42l84_revert_hs(struct cs42l84_private *cs42l84) +{ + /* Power down HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1) | /* 0.0 V */ + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); + + /* Disconnect HSBIAS */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2)); +} + +static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84, + unsigned int val) +{ + regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK, + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG | + CS42L84_TS_PLUG | CS42L84_TS_UNPLUG, + val); +} + +static irqreturn_t cs42l84_irq_thread(int irq, void *data) +{ + struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data; + unsigned int stickies[1]; + unsigned int masks[1]; + unsigned int reg; + u8 current_tip_state; + u8 current_ring_state; + int i; + + mutex_lock(&cs42l84->irq_lock); + /* Read sticky registers to clear interrupt */ + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, + &(stickies[i])); + regmap_read(cs42l84->regmap, irq_params_table[i].mask_addr, + &(masks[i])); + stickies[i] = stickies[i] & (~masks[i]) & + irq_params_table[i].mask; + } + + /* When handling plug sene IRQs, we only care about EITHER tip OR ring. + * Ring is useless on remove, and is only useful on insert for + * detecting if the plug state has changed AFTER we have handled the + * tip sense IRQ, e.g. if the plug was not fully seated within the tip + * sense debounce time. + */ + + if ((~masks[0]) & irq_params_table[0].mask) { + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + + current_tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + + if (current_tip_state != cs42l84->tip_state) { + cs42l84->tip_state = current_tip_state; + switch (current_tip_state) { + case CS42L84_PLUG: + dev_dbg(cs42l84->dev, "Plug event\n"); + + cs42l84_detect_hs(cs42l84); + + /* + * Check the tip sense status again, and possibly invalidate + * the detection result + * + * Thanks to debounce, this should reliably indicate if the tip + * was disconnected at any point during the detection procedure. + */ + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + current_tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + if (current_tip_state != CS42L84_PLUG) { + dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n"); + cs42l84->tip_state = CS42L84_UNPLUG; + cs42l84_revert_hs(cs42l84); + } + + /* Unmask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, 0); + break; + case CS42L84_UNPLUG: + cs42l84->ring_state = CS42L84_UNPLUG; + dev_dbg(cs42l84->dev, "Unplug event\n"); + + cs42l84_revert_hs(cs42l84); + cs42l84->hs_type = 0; + snd_soc_jack_report(cs42l84->jack, 0, + SND_JACK_HEADSET); + + /* Mask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); + break; + default: + cs42l84->ring_state = CS42L84_TRANS; + break; + } + + mutex_unlock(&cs42l84->irq_lock); + + return IRQ_HANDLED; + } + + /* Tip state didn't change, we must've got a ring sense IRQ */ + current_ring_state = (((char) reg) & + (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >> + CS42L84_RS_PLUG_SHIFT; + + if (current_ring_state != cs42l84->ring_state) { + cs42l84->ring_state = current_ring_state; + if (current_ring_state == CS42L84_PLUG) + cs42l84_detect_hs(cs42l84); + } + } + + mutex_unlock(&cs42l84->irq_lock); + + return IRQ_HANDLED; +} + +static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84) +{ + unsigned int reg; + + /* Set up plug detection */ + regmap_update_bits(cs42l84->regmap, CS42L84_MIC_DET_CTL4, + CS42L84_MIC_DET_CTL4_LATCH_TO_VP, + CS42L84_MIC_DET_CTL4_LATCH_TO_VP); + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL2, + CS42L84_TIP_SENSE_CTL2_MODE, + FIELD_PREP(CS42L84_TIP_SENSE_CTL2_MODE, CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET)); + regmap_update_bits(cs42l84->regmap, CS42L84_RING_SENSE_CTL, + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | + CS42L84_RING_SENSE_CTL_RISETIME | CS42L84_RING_SENSE_CTL_FALLTIME, + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | + FIELD_PREP(CS42L84_RING_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_125MS) | + FIELD_PREP(CS42L84_RING_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL, + CS42L84_TIP_SENSE_CTL_INV | + CS42L84_TIP_SENSE_CTL_RISETIME | CS42L84_TIP_SENSE_CTL_FALLTIME, + CS42L84_TIP_SENSE_CTL_INV | + FIELD_PREP(CS42L84_TIP_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_500MS) | + FIELD_PREP(CS42L84_TIP_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); + regmap_update_bits(cs42l84->regmap, CS42L84_MSM_BLOCK_EN3, + CS42L84_MSM_BLOCK_EN3_TR_SENSE, + CS42L84_MSM_BLOCK_EN3_TR_SENSE); + + /* Save the initial status of the tip sense */ + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + cs42l84->tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + + /* Set mic-detection threshold */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MIC_DET_CTL1, CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, + FIELD_PREP(CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 0x2c)); /* ~1.9 V */ + + /* Disconnect HSBIAS (initially) */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET | CS42L84_HS_DET_CTL2_CTL, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2) | + FIELD_PREP(CS42L84_HS_DET_CTL2_CTL, 0)); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_CLAMP_DISABLE, 1, 1); + +} + +static int cs42l84_i2c_probe(struct i2c_client *i2c_client) +{ + struct cs42l84_private *cs42l84; + int ret, devid; + unsigned int reg; + + cs42l84 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l84_private), + GFP_KERNEL); + if (!cs42l84) + return -ENOMEM; + + cs42l84->dev = &i2c_client->dev; + i2c_set_clientdata(i2c_client, cs42l84); + mutex_init(&cs42l84->irq_lock); + + cs42l84->regmap = devm_regmap_init_i2c(i2c_client, &cs42l84_regmap); + if (IS_ERR(cs42l84->regmap)) { + ret = PTR_ERR(cs42l84->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs42l84->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs42l84->reset_gpio)) { + ret = PTR_ERR(cs42l84->reset_gpio); + goto err_disable_noreset; + } + + if (cs42l84->reset_gpio) { + dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + gpiod_set_value_cansleep(cs42l84->reset_gpio, 1); + } + usleep_range(CS42L84_BOOT_TIME_US, CS42L84_BOOT_TIME_US * 2); + + /* Request IRQ if one was specified */ + if (i2c_client->irq) { + ret = request_threaded_irq(i2c_client->irq, + NULL, cs42l84_irq_thread, + IRQF_ONESHOT, + "cs42l84", cs42l84); + if (ret == -EPROBE_DEFER) { + goto err_disable_noirq; + } else if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request IRQ: %d\n", ret); + goto err_disable_noirq; + } + } + + /* initialize codec */ + devid = cirrus_read_device_id(cs42l84->regmap, CS42L84_DEVID); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_disable; + } + + if (devid != CS42L84_CHIP_ID) { + dev_err(&i2c_client->dev, + "CS42L84 Device ID (%X). Expected %X\n", + devid, CS42L84_CHIP_ID); + ret = -EINVAL; + goto err_disable; + } + + ret = regmap_read(cs42l84->regmap, CS42L84_REVID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + goto err_shutdown; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS42L84, Revision: %02X\n", reg & 0xFF); + + /* Setup plug detection */ + cs42l84_setup_plug_detect(cs42l84); + + /* Mask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); + + /* Register codec for machine driver */ + ret = devm_snd_soc_register_component(&i2c_client->dev, + &soc_component_dev_cs42l84, &cs42l84_dai, 1); + if (ret < 0) + goto err_shutdown; + + return 0; + +err_shutdown: + /* Nothing to do */ + +err_disable: + if (i2c_client->irq) + free_irq(i2c_client->irq, cs42l84); + +err_disable_noirq: + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); +err_disable_noreset: + return ret; +} + +static void cs42l84_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l84_private *cs42l84 = i2c_get_clientdata(i2c_client); + + if (i2c_client->irq) + free_irq(i2c_client->irq, cs42l84); + + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); +} + +static const struct of_device_id cs42l84_of_match[] = { + { .compatible = "cirrus,cs42l84", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l84_of_match); + +static const struct i2c_device_id cs42l84_id[] = { + {"cs42l84", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs42l84_id); + +static struct i2c_driver cs42l84_i2c_driver = { + .driver = { + .name = "cs42l84", + .of_match_table = cs42l84_of_match, + }, + .id_table = cs42l84_id, + .probe = cs42l84_i2c_probe, + .remove = cs42l84_i2c_remove, +}; + +module_i2c_driver(cs42l84_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L84 driver"); +MODULE_AUTHOR("Martin PoviÅ¡er <povik+lin@cutebit.org>"); +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); +MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l84.h b/sound/soc/codecs/cs42l84.h new file mode 100644 index 000000000000..dbf778a902b9 --- /dev/null +++ b/sound/soc/codecs/cs42l84.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) The Asahi Linux Contributors + * + * Based on sound/soc/codecs/cs42l42.h + * + * Copyright 2016 Cirrus Logic, Inc. + */ + + +#ifndef __CS42L84_H__ +#define __CS42L84_H__ + +#include <linux/bits.h> + +#define CS42L84_CHIP_ID 0x42a84 + +#define CS42L84_DEVID 0x0000 +#define CS42L84_REVID 0x73fe +#define CS42L84_FRZ_CTL 0x0006 +#define CS42L84_FRZ_CTL_ENGAGE BIT(0) + +#define CS42L84_TSRS_PLUG_INT_STATUS 0x0400 +#define CS42L84_TSRS_PLUG_INT_MASK 0x0418 +#define CS42L84_RS_PLUG_SHIFT 0 +#define CS42L84_RS_PLUG BIT(0) +#define CS42L84_RS_UNPLUG BIT(1) +#define CS42L84_TS_PLUG_SHIFT 2 +#define CS42L84_TS_PLUG BIT(2) +#define CS42L84_TS_UNPLUG BIT(3) +#define CS42L84_TSRS_PLUG_VAL_MASK GENMASK(3, 0) +#define CS42L84_PLL_LOCK_STATUS 0x040e // probably bit 0x10 +#define CS42L84_PLL_LOCK_STATUS_LOCKED BIT(4) +#define CS42L84_PLL_LOCK_STATUS_ERROR BIT(5) + +#define CS42L84_PLUG 3 +#define CS42L84_UNPLUG 0 +#define CS42L84_TRANS 1 + +#define CS42L84_CCM_CTL1 0x0600 +#define CS42L84_CCM_CTL1_MCLK_SRC GENMASK(1, 0) +#define CS42L84_CCM_CTL1_MCLK_SRC_RCO 0 +#define CS42L84_CCM_CTL1_MCLK_SRC_MCLK 1 +#define CS42L84_CCM_CTL1_MCLK_SRC_BCLK 2 +#define CS42L84_CCM_CTL1_MCLK_SRC_PLL 3 +#define CS42L84_CCM_CTL1_MCLK_FREQ GENMASK(3, 2) +#define CS42L84_CCM_CTL1_MCLK_F_12MHZ 0b00 +#define CS42L84_CCM_CTL1_MCLK_F_24MHZ 0b01 +#define CS42L84_CCM_CTL1_MCLK_F_12_288KHZ 0b10 +#define CS42L84_CCM_CTL1_MCLK_F_24_576KHZ 0b11 +#define CS42L84_CCM_CTL1_RCO \ + (FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_RCO) \ + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, CS42L84_CCM_CTL1_MCLK_F_12MHZ)) + +#define CS42L84_CCM_SAMP_RATE 0x0601 +#define CS42L84_CCM_SAMP_RATE_RATE_48KHZ 4 +#define CS42L84_CCM_SAMP_RATE_RATE_96KHZ 5 +#define CS42L84_CCM_SAMP_RATE_RATE_192KHZ 6 +#define CS42L84_CCM_SAMP_RATE_RATE_44K1HZ 12 +#define CS42L84_CCM_SAMP_RATE_RATE_88K2HZ 13 +#define CS42L84_CCM_SAMP_RATE_RATE_176K4HZ 14 +#define CS42L84_CCM_CTL3 0x0602 +#define CS42L84_CCM_CTL3_REFCLK_DIV GENMASK(2, 1) +#define CS42L84_CCM_CTL4 0x0603 +#define CS42L84_CCM_CTL4_REFCLK_EN BIT(0) + +#define CS42L84_CCM_ASP_CLK_CTRL 0x0608 + +#define CS42L84_PLL_CTL1 0x0800 +#define CS42L84_PLL_CTL1_EN BIT(0) +#define CS42L84_PLL_CTL1_MODE GENMASK(2, 1) +#define CS42L84_PLL_DIV_FRAC0 0x0804 +#define CS42L84_PLL_DIV_FRAC1 0x0805 +#define CS42L84_PLL_DIV_FRAC2 0x0806 +#define CS42L84_PLL_DIV_INT 0x0807 +#define CS42L84_PLL_DIVOUT 0x0808 + +#define CS42L84_RING_SENSE_CTL 0x1282 +#define CS42L84_RING_SENSE_CTL_INV BIT(7) +#define CS42L84_RING_SENSE_CTL_UNK1 BIT(6) +#define CS42L84_RING_SENSE_CTL_FALLTIME GENMASK(5, 3) +#define CS42L84_RING_SENSE_CTL_RISETIME GENMASK(2, 0) +#define CS42L84_TIP_SENSE_CTL 0x1283 +#define CS42L84_TIP_SENSE_CTL_INV BIT(7) +#define CS42L84_TIP_SENSE_CTL_FALLTIME GENMASK(5, 3) +#define CS42L84_TIP_SENSE_CTL_RISETIME GENMASK(2, 0) + +#define CS42L84_TSRS_PLUG_STATUS 0x1288 + +#define CS42L84_TIP_SENSE_CTL2 0x1473 +#define CS42L84_TIP_SENSE_CTL2_MODE GENMASK(7, 6) +#define CS42L84_TIP_SENSE_CTL2_MODE_DISABLED 0b00 +#define CS42L84_TIP_SENSE_CTL2_MODE_DIG_INPUT 0b01 +#define CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET 0b11 +#define CS42L84_TIP_SENSE_CTL2_INV BIT(5) + +#define CS42L84_MISC_DET_CTL 0x1474 +#define CS42L84_MISC_DET_CTL_DETECT_MODE GENMASK(4, 3) +#define CS42L84_MISC_DET_CTL_HSBIAS_CTL GENMASK(2, 1) +#define CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET BIT(0) + +#define CS42L84_MIC_DET_CTL1 0x1475 +#define CS42L84_MIC_DET_CTL1_HS_DET_LEVEL GENMASK(5, 0) + +#define CS42L84_MIC_DET_CTL4 0x1477 +#define CS42L84_MIC_DET_CTL4_LATCH_TO_VP BIT(1) + +#define CS42L84_HS_DET_STATUS2 0x147d + +#define CS42L84_MSM_BLOCK_EN1 0x1800 +#define CS42L84_MSM_BLOCK_EN2 0x1801 +#define CS42L84_MSM_BLOCK_EN2_ASP_SHIFT 6 +#define CS42L84_MSM_BLOCK_EN2_BUS_SHIFT 5 +#define CS42L84_MSM_BLOCK_EN2_DAC_SHIFT 4 +#define CS42L84_MSM_BLOCK_EN2_ADC_SHIFT 3 +#define CS42L84_MSM_BLOCK_EN3 0x1802 +#define CS42L84_MSM_BLOCK_EN3_TR_SENSE BIT(3) + +#define CS42L84_HS_DET_CTL2 0x1811 +#define CS42L84_HS_DET_CTL2_CTL GENMASK(7, 6) +#define CS42L84_HS_DET_CTL2_SET GENMASK(5, 4) +#define CS42L84_HS_DET_CTL2_REF BIT(3) +#define CS42L84_HS_DET_CTL2_AUTO_TIME GENMASK(1, 0) + +#define CS42L84_HS_SWITCH_CTL 0x1812 +#define CS42L84_HS_SWITCH_CTL_REF_HS3 BIT(7) +#define CS42L84_HS_SWITCH_CTL_REF_HS4 BIT(6) +#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 BIT(5) +#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 BIT(4) +#define CS42L84_HS_SWITCH_CTL_HSB_HS3 BIT(3) +#define CS42L84_HS_SWITCH_CTL_HSB_HS4 BIT(2) +#define CS42L84_HS_SWITCH_CTL_GNDHS_HS3 BIT(1) +#define CS42L84_HS_SWITCH_CTL_GNDHS_HS4 BIT(0) + +#define CS42L84_HS_CLAMP_DISABLE 0x1813 + +#define CS42L84_ADC_CTL1 0x2000 +#define CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT 6 +#define CS42L84_ADC_CTL1_PGA_GAIN_SHIFT 0 +#define CS42L84_ADC_CTL4 0x2003 +#define CS42L84_ADC_CTL4_WNF_CF_SHIFT 4 +#define CS42L84_ADC_CTL4_WNF_EN_SHIFT 3 +#define CS42L84_ADC_CTL4_HPF_CF_SHIFT 1 +#define CS42L84_ADC_CTL4_HPF_EN_SHIFT 0 + +#define CS42L84_DAC_CTL1 0x3000 +#define CS42L84_DAC_CTL1_UNMUTE BIT(0) +//#define CS42L84_DAC_CTL1_DACB_INV_SHIFT 1 +//#define CS42L84_DAC_CTL1_DACA_INV_SHIFT 0 +#define CS42L84_DAC_CTL2 0x3001 + +#define CS42L84_DAC_CHA_VOL_LSB 0x3004 +#define CS42L84_DAC_CHA_VOL_MSB 0x3005 +#define CS42L84_DAC_CHB_VOL_LSB 0x3006 +#define CS42L84_DAC_CHB_VOL_MSB 0x3007 +#define CS42L84_HP_VOL_CTL 0x3020 +#define CS42L84_HP_VOL_CTL_ZERO_CROSS BIT(1) +#define CS42L84_HP_VOL_CTL_SOFT BIT(0) + +#define CS42L84_SRC_ASP_RX_CH1 0b1101 +#define CS42L84_SRC_ASP_RX_CH2 0b1110 + +#define CS42L84_BUS_ASP_TX_SRC 0x4000 +#define CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT 0 +#define CS42L84_BUS_DAC_SRC 0x4001 +#define CS42L84_BUS_DAC_SRC_DACA_SHIFT 0 +#define CS42L84_BUS_DAC_SRC_DACB_SHIFT 4 + +#define CS42L84_ASP_CTL 0x5000 +#define CS42L84_ASP_CTL_BCLK_EN_SHIFT 1 +#define CS42L84_ASP_CTL_TDM_MODE BIT(2) +#define CS42L84_ASP_FSYNC_CTL2 0x5010 +#define CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO GENMASK(7, 1) +#define CS42L84_ASP_FSYNC_CTL3 0x5011 +#define CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI GENMASK(4, 0) +#define CS42L84_ASP_DATA_CTL 0x5018 + +#define CS42L84_ASP_RX_EN 0x5020 +#define CS42L84_ASP_RX_EN_CH1_SHIFT 0 +#define CS42L84_ASP_RX_EN_CH2_SHIFT 1 +#define CS42L84_ASP_TX_EN 0x5024 +#define CS42L84_ASP_TX_EN_CH1_SHIFT 0 + +#define CS42L84_ASP_RX_CH1_CTL1 0x5028 +#define CS42L84_ASP_RX_CH1_CTL2 0x5029 +#define CS42L84_ASP_RX_CH1_WIDTH 0x502a +#define CS42L84_ASP_RX_CH2_CTL1 0x502c +#define CS42L84_ASP_RX_CH2_CTL2 0x502d +#define CS42L84_ASP_RX_CH2_WIDTH 0x502e + +#define CS42L84_ASP_RX_CHx_CTL1_EDGE BIT(0) +#define CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB GENMASK(7, 1) +#define CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB GENMASK(2, 0) + +#define CS42L84_ASP_TX_CH1_CTL1 0x5068 +#define CS42L84_ASP_TX_CH1_CTL2 0x5069 +#define CS42L84_ASP_TX_CH1_WIDTH 0x506a +#define CS42L84_ASP_TX_CH2_CTL1 0x506c +#define CS42L84_ASP_TX_CH2_CTL2 0x506d +#define CS42L84_ASP_TX_CH2_WIDTH 0x506e + +#define CS42L84_DEBOUNCE_TIME_125MS 0b001 +#define CS42L84_DEBOUNCE_TIME_500MS 0b011 + +#define CS42L84_BOOT_TIME_US 3000 +#define CS42L84_CLOCK_SWITCH_DELAY_US 150 +#define CS42L84_PLL_LOCK_POLL_US 250 +#define CS42L84_PLL_LOCK_TIMEOUT_US 1250 + +#endif /* __CS42L84_H__ */ diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index f3ef6fb55304..ca4cc954efa8 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -20,6 +20,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <linux/pm_runtime.h> +#include <linux/units.h> #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> @@ -1555,7 +1556,11 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq)) return 0; - if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) { + /* Maybe audio stream is closing. */ + if (freq == 0) + return 0; + + if (((freq < da7213->fin_min_rate) && (freq != 32768)) || (freq > 54000000)) { dev_err(component->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1854,11 +1859,14 @@ static int da7213_set_bias_level(struct snd_soc_component *component, return 0; } +#define DA7213_FIN_MIN_RATE (5 * MEGA) +#define DA7212_FIN_MIN_RATE (2 * MEGA) + #if defined(CONFIG_OF) /* DT */ static const struct of_device_id da7213_of_match[] = { - { .compatible = "dlg,da7212", }, - { .compatible = "dlg,da7213", }, + { .compatible = "dlg,da7212", .data = (void *)DA7212_FIN_MIN_RATE }, + { .compatible = "dlg,da7213", .data = (void *)DA7213_FIN_MIN_RATE }, { } }; MODULE_DEVICE_TABLE(of, da7213_of_match); @@ -1866,8 +1874,8 @@ MODULE_DEVICE_TABLE(of, da7213_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id da7213_acpi_match[] = { - { "DLGS7212", 0}, - { "DLGS7213", 0}, + { "DLGS7212", DA7212_FIN_MIN_RATE }, + { "DLGS7213", DA7213_FIN_MIN_RATE }, { }, }; MODULE_DEVICE_TABLE(acpi, da7213_acpi_match); @@ -2136,6 +2144,7 @@ static const struct regmap_config da7213_regmap_config = { .reg_bits = 8, .val_bits = 8, + .max_register = DA7213_TONE_GEN_OFF_PER, .reg_defaults = da7213_reg_defaults, .num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults), .volatile_reg = da7213_volatile_register, @@ -2162,6 +2171,10 @@ static int da7213_i2c_probe(struct i2c_client *i2c) if (!da7213) return -ENOMEM; + da7213->fin_min_rate = (uintptr_t)i2c_get_match_data(i2c); + if (!da7213->fin_min_rate) + return -EINVAL; + i2c_set_clientdata(i2c, da7213); /* Get required supplies */ @@ -2229,12 +2242,12 @@ static int __maybe_unused da7213_runtime_resume(struct device *dev) if (ret < 0) return ret; regcache_cache_only(da7213->regmap, false); - regcache_sync(da7213->regmap); - return 0; + return regcache_sync(da7213->regmap); } static const struct dev_pm_ops da7213_pm = { SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct i2c_device_id da7213_i2c_id[] = { diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 505b731c0adb..b9ab791d6b88 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -600,6 +600,7 @@ struct da7213_priv { struct clk *mclk; unsigned int mclk_rate; unsigned int out_rate; + unsigned int fin_min_rate; int clk_src; bool master; bool alc_calib_auto; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 311ea7918b31..e2da3e317b5a 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1167,17 +1167,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); int ret = 0; - if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) + mutex_lock(&da7219->pll_lock); + + if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) { + mutex_unlock(&da7219->pll_lock); return 0; + } if ((freq < 2000000) || (freq > 54000000)) { + mutex_unlock(&da7219->pll_lock); dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; } - mutex_lock(&da7219->pll_lock); - switch (clk_id) { case DA7219_CLKSRC_MCLK_SQR: snd_soc_component_update_bits(component, DA7219_PLL_CTRL, diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c new file mode 100644 index 000000000000..6f4fa36ea34d --- /dev/null +++ b/sound/soc/codecs/es8323.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// es8323.c -- es8323 ALSA SoC audio driver +// +// Copyright 2024 Rockchip Electronics Co. Ltd. +// Copyright 2024 Everest Semiconductor Co.,Ltd. +// Copyright 2024 Loongson Technology Co.,Ltd. +// +// Author: Mark Brown <broonie@kernel.org> +// Jianqun Xu <jay.xu@rock-chips.com> +// Nickey Yang <nickey.yang@rock-chips.com> +// Further cleanup and restructuring by: +// Binbin Zhou <zhoubinbin@loongson.cn> + +#include <linux/module.h> +#include <linux/acpi.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "es8323.h" + +struct es8323_priv { + unsigned int sysclk; + struct clk *mclk; + struct regmap *regmap; + struct snd_pcm_hw_constraint_list *sysclk_constraints; + struct snd_soc_component *component; +}; + +/* es8323 register cache */ +static const struct reg_default es8323_reg_defaults[] = { + { ES8323_CONTROL1, 0x06 }, + { ES8323_CONTROL2, 0x1c }, + { ES8323_CHIPPOWER, 0xc3 }, + { ES8323_ADCPOWER, 0xfc }, + { ES8323_DACPOWER, 0xc0 }, + { ES8323_CHIPLOPOW1, 0x00 }, + { ES8323_CHIPLOPOW2, 0x00 }, + { ES8323_ANAVOLMANAG, 0x7c }, + { ES8323_MASTERMODE, 0x80 }, + { ES8323_ADCCONTROL1, 0x00 }, + { ES8323_ADCCONTROL2, 0x00 }, + { ES8323_ADCCONTROL3, 0x06 }, + { ES8323_ADCCONTROL4, 0x00 }, + { ES8323_ADCCONTROL5, 0x06 }, + { ES8323_ADCCONTROL6, 0x30 }, + { ES8323_ADC_MUTE, 0x30 }, + { ES8323_LADC_VOL, 0xc0 }, + { ES8323_RADC_VOL, 0xc0 }, + { ES8323_ADCCONTROL10, 0x38 }, + { ES8323_ADCCONTROL11, 0xb0 }, + { ES8323_ADCCONTROL12, 0x32 }, + { ES8323_ADCCONTROL13, 0x06 }, + { ES8323_ADCCONTROL14, 0x00 }, + { ES8323_DACCONTROL1, 0x00 }, + { ES8323_DACCONTROL2, 0x06 }, + { ES8323_DAC_MUTE, 0x30 }, + { ES8323_LDAC_VOL, 0xc0 }, + { ES8323_RDAC_VOL, 0xc0 }, + { ES8323_DACCONTROL6, 0x08 }, + { ES8323_DACCONTROL7, 0x06 }, + { ES8323_DACCONTROL8, 0x1f }, + { ES8323_DACCONTROL9, 0xf7 }, + { ES8323_DACCONTROL10, 0xfd }, + { ES8323_DACCONTROL11, 0xff }, + { ES8323_DACCONTROL12, 0x1f }, + { ES8323_DACCONTROL13, 0xf7 }, + { ES8323_DACCONTROL14, 0xfd }, + { ES8323_DACCONTROL15, 0xff }, + { ES8323_DACCONTROL16, 0x00 }, + { ES8323_DACCONTROL17, 0x38 }, + { ES8323_DACCONTROL18, 0x38 }, + { ES8323_DACCONTROL19, 0x38 }, + { ES8323_DACCONTROL20, 0x38 }, + { ES8323_DACCONTROL21, 0x38 }, + { ES8323_DACCONTROL22, 0x38 }, + { ES8323_DACCONTROL23, 0x00 }, + { ES8323_LOUT1_VOL, 0x00 }, + { ES8323_ROUT1_VOL, 0x00 }, +}; + +static const char *const es8323_stereo_3d_texts[] = { "No 3D ", "Level 1", "Level 2", "Level 3", + "Level 4", "Level 5", "Level 6", "Level 7" }; +static SOC_ENUM_SINGLE_DECL(es8323_stereo_3d_enum, ES8323_DACCONTROL7, 2, es8323_stereo_3d_texts); + +static const char *const es8323_alc_func_texts[] = { "Off", "Right", "Left", "Stereo" }; +static SOC_ENUM_SINGLE_DECL(es8323_alc_function_enum, + ES8323_ADCCONTROL10, 6, es8323_alc_func_texts); + +static const char *const es8323_ng_type_texts[] = { "Constant PGA Gain", "Mute ADC Output" }; +static SOC_ENUM_SINGLE_DECL(es8323_alc_ng_type_enum, ES8323_ADCCONTROL14, 1, es8323_ng_type_texts); + +static const char *const es8323_deemph_texts[] = { "None", "32Khz", "44.1Khz", "48Khz" }; +static SOC_ENUM_SINGLE_DECL(es8323_playback_deemphasis_enum, + ES8323_DACCONTROL6, 6, es8323_deemph_texts); + +static const char *const es8323_adcpol_texts[] = { "Normal", "L Invert", + "R Invert", "L + R Invert" }; +static SOC_ENUM_SINGLE_DECL(es8323_capture_polarity_enum, + ES8323_ADCCONTROL6, 6, es8323_adcpol_texts); + +static const DECLARE_TLV_DB_SCALE(es8323_adc_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(es8323_dac_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(es8323_out_tlv, -4500, 150, 0); +static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv2, -15, 300, 0); + +static const struct snd_kcontrol_new es8323_snd_controls[] = { + SOC_ENUM("3D Mode", es8323_stereo_3d_enum), + SOC_ENUM("ALC Capture Function", es8323_alc_function_enum), + SOC_ENUM("ALC Capture NG Type", es8323_alc_ng_type_enum), + SOC_ENUM("Playback De-emphasis", es8323_playback_deemphasis_enum), + SOC_ENUM("Capture Polarity", es8323_capture_polarity_enum), + SOC_SINGLE("ALC Capture ZC Switch", ES8323_ADCCONTROL13, 6, 1, 0), + SOC_SINGLE("ALC Capture Decay Time", ES8323_ADCCONTROL12, 4, 15, 0), + SOC_SINGLE("ALC Capture Attack Time", ES8323_ADCCONTROL12, 0, 15, 0), + SOC_SINGLE("ALC Capture NG Threshold", ES8323_ADCCONTROL14, 3, 31, 0), + SOC_SINGLE("ALC Capture NG Switch", ES8323_ADCCONTROL14, 0, 1, 0), + SOC_SINGLE("ZC Timeout Switch", ES8323_ADCCONTROL13, 6, 1, 0), + SOC_SINGLE("Capture Mute Switch", ES8323_ADC_MUTE, 2, 1, 0), + SOC_SINGLE_TLV("Left Channel Capture Volume", ES8323_ADCCONTROL1, 4, 8, + 0, es8323_bypass_tlv), + SOC_SINGLE_TLV("Right Channel Capture Volume", ES8323_ADCCONTROL1, 0, + 8, 0, es8323_bypass_tlv), + SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", ES8323_DACCONTROL17, 3, + 7, 1, es8323_bypass_tlv2), + SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", ES8323_DACCONTROL20, + 3, 7, 1, es8323_bypass_tlv2), + SOC_DOUBLE_R_TLV("PCM Volume", ES8323_LDAC_VOL, ES8323_RDAC_VOL, + 0, 192, 1, es8323_dac_tlv), + SOC_DOUBLE_R_TLV("Capture Digital Volume", ES8323_LADC_VOL, + ES8323_RADC_VOL, 0, 192, 1, es8323_adc_tlv), + SOC_DOUBLE_R_TLV("Output 1 Playback Volume", ES8323_LOUT1_VOL, + ES8323_ROUT1_VOL, 0, 33, 0, es8323_out_tlv), + SOC_DOUBLE_R_TLV("Output 2 Playback Volume", ES8323_LOUT2_VOL, + ES8323_ROUT2_VOL, 0, 33, 0, es8323_out_tlv), +}; + +/* Left DAC Route */ +static const char *const es8323_pga_sell[] = { "Line 1L", "Line 2L", "NC", "DifferentialL" }; +static SOC_ENUM_SINGLE_DECL(es8323_left_dac_enum, ES8323_ADCCONTROL2, 6, es8323_pga_sell); +static const struct snd_kcontrol_new es8323_left_dac_mux_controls = + SOC_DAPM_ENUM("Left DAC Route", es8323_left_dac_enum); + +/* Right DAC Route */ +static const char *const es8323_pga_selr[] = { "Line 1R", "Line 2R", "NC", "DifferentialR" }; +static SOC_ENUM_SINGLE_DECL(es8323_right_dac_enum, ES8323_ADCCONTROL2, 4, es8323_pga_selr); +static const struct snd_kcontrol_new es8323_right_dac_mux_controls = + SOC_DAPM_ENUM("Right DAC Route", es8323_right_dac_enum); + +/* Left Line Mux */ +static const char *const es8323_lin_sell[] = { "Line 1L", "Line 2L", "NC", "MicL" }; +static SOC_ENUM_SINGLE_DECL(es8323_llin_enum, ES8323_DACCONTROL16, 3, es8323_lin_sell); +static const struct snd_kcontrol_new es8323_left_line_controls = + SOC_DAPM_ENUM("LLIN Mux", es8323_llin_enum); + +/* Right Line Mux */ +static const char *const es8323_lin_selr[] = { "Line 1R", "Line 2R", "NC", "MicR" }; +static SOC_ENUM_SINGLE_DECL(es8323_rlin_enum, ES8323_DACCONTROL16, 0, es8323_lin_selr); +static const struct snd_kcontrol_new es8323_right_line_controls = + SOC_DAPM_ENUM("RLIN Mux", es8323_rlin_enum); + +/* Differential Mux */ +static const char *const es8323_diffmux_sel[] = { "Line 1", "Line 2" }; +static SOC_ENUM_SINGLE_DECL(es8323_diffmux_enum, ES8323_ADCCONTROL3, 7, es8323_diffmux_sel); +static const struct snd_kcontrol_new es8323_diffmux_controls = + SOC_DAPM_ENUM("Route2", es8323_diffmux_enum); + +/* Mono ADC Mux */ +static const char *const es8323_mono_adc_mux[] = { "Stereo", "Mono (Left)", "Mono (Right)" }; +static SOC_ENUM_SINGLE_DECL(es8323_mono_adc_mux_enum, ES8323_ADCCONTROL3, 3, es8323_mono_adc_mux); +static const struct snd_kcontrol_new es8323_mono_adc_mux_controls = + SOC_DAPM_ENUM("Mono Mux", es8323_mono_adc_mux_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8323_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", SND_SOC_NOPM, 7, 1, 1), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8323_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Right Playback Switch", SND_SOC_NOPM, 6, 1, 1), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0), +}; + +static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), + + SND_SOC_DAPM_MICBIAS("Mic Bias", SND_SOC_NOPM, 3, 1), + + /* Muxes */ + SND_SOC_DAPM_MUX("Left PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_left_dac_mux_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_right_dac_mux_controls), + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, &es8323_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls), + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, &es8323_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, &es8323_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 6, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 7, 1), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8323_left_mixer_controls[0], + ARRAY_SIZE(es8323_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8323_right_mixer_controls[0], + ARRAY_SIZE(es8323_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 2", SND_SOC_NOPM, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", SND_SOC_NOPM, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", SND_SOC_NOPM, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", SND_SOC_NOPM, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("VREF"), +}; + +static const struct snd_soc_dapm_route es8323_dapm_routes[] = { + /*12.22*/ + {"Left PGA Mux", "Line 1L", "LINPUT1"}, + {"Left PGA Mux", "Line 2L", "LINPUT2"}, + {"Left PGA Mux", "DifferentialL", "Differential Mux"}, + + {"Right PGA Mux", "Line 1R", "RINPUT1"}, + {"Right PGA Mux", "Line 2R", "RINPUT2"}, + {"Right PGA Mux", "DifferentialR", "Differential Mux"}, + + {"Differential Mux", "Line 1", "LINPUT1"}, + {"Differential Mux", "Line 1", "RINPUT1"}, + {"Differential Mux", "Line 2", "LINPUT2"}, + {"Differential Mux", "Line 2", "RINPUT2"}, + + {"Left ADC Mux", "Stereo", "Right PGA Mux"}, + {"Left ADC Mux", "Stereo", "Left PGA Mux"}, + {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, + + {"Right ADC Mux", "Stereo", "Left PGA Mux"}, + {"Right ADC Mux", "Stereo", "Right PGA Mux"}, + {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, + + {"Left ADC Power", NULL, "Left ADC Mux"}, + {"Right ADC Power", NULL, "Right ADC Mux"}, + {"Left ADC", NULL, "Left ADC Power"}, + {"Right ADC", NULL, "Right ADC Power"}, + + {"Left Line Mux", "Line 1L", "LINPUT1"}, + {"Left Line Mux", "Line 2L", "LINPUT2"}, + {"Left Line Mux", "MicL", "Left PGA Mux"}, + + {"Right Line Mux", "Line 1R", "RINPUT1"}, + {"Right Line Mux", "Line 2R", "RINPUT2"}, + {"Right Line Mux", "MicR", "Right PGA Mux"}, + + {"Left Mixer", "Left Playback Switch", "Left DAC"}, + {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, + + {"Right Mixer", "Right Playback Switch", "Right DAC"}, + {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, + + {"Left Out 1", NULL, "Left Mixer"}, + {"LOUT1", NULL, "Left Out 1"}, + {"Right Out 1", NULL, "Right Mixer"}, + {"ROUT1", NULL, "Right Out 1"}, + + {"Left Out 2", NULL, "Left Mixer"}, + {"LOUT2", NULL, "Left Out 2"}, + {"Right Out 2", NULL, "Right Mixer"}, + {"ROUT2", NULL, "Right Out 2"}, +}; + +struct coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct coeff_div es8323_coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0xa, 0x0}, + {11289600, 8000, 1408, 0x9, 0x0}, + {18432000, 8000, 2304, 0xc, 0x0}, + {16934400, 8000, 2112, 0xb, 0x0}, + {12000000, 8000, 1500, 0xb, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x7, 0x0}, + {16934400, 11025, 1536, 0xa, 0x0}, + {12000000, 11025, 1088, 0x9, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0x6, 0x0}, + {18432000, 16000, 1152, 0x8, 0x0}, + {12000000, 16000, 750, 0x7, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x4, 0x0}, + {16934400, 22050, 768, 0x6, 0x0}, + {12000000, 22050, 544, 0x6, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x3, 0x0}, + {18432000, 32000, 576, 0x5, 0x0}, + {12000000, 32000, 375, 0x4, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x2, 0x0}, + {16934400, 44100, 384, 0x3, 0x0}, + {12000000, 44100, 272, 0x3, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x2, 0x0}, + {18432000, 48000, 384, 0x3, 0x0}, + {12000000, 48000, 250, 0x2, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x0, 0x0}, + {16934400, 88200, 192, 0x1, 0x0}, + {12000000, 88200, 136, 0x1, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x0, 0x0}, + {18432000, 96000, 192, 0x1, 0x0}, + {12000000, 96000, 125, 0x0, 0x1}, +}; + +static unsigned int rates_12288[] = { + 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12288 = { + .count = ARRAY_SIZE(rates_12288), + .list = rates_12288, +}; + +static unsigned int rates_112896[] = { + 8000, 11025, 22050, 44100, +}; + +static struct snd_pcm_hw_constraint_list constraints_112896 = { + .count = ARRAY_SIZE(rates_112896), + .list = rates_112896, +}; + +static unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 24000, + 32000, 44100, 48000, 48000, 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(es8323_coeff_div); i++) { + if (es8323_coeff_div[i].rate == rate && + es8323_coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +static int es8323_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + switch (freq) { + case 11289600: + case 18432000: + case 22579200: + case 36864000: + es8323->sysclk_constraints = &constraints_112896; + break; + case 12288000: + case 16934400: + case 24576000: + case 33868800: + es8323->sysclk_constraints = &constraints_12288; + break; + case 12000000: + case 24000000: + es8323->sysclk_constraints = &constraints_12; + break; + default: + return -EINVAL; + } + + es8323->sysclk = freq; + return 0; +} + +static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + u8 iface = snd_soc_component_read(component, ES8323_MASTERMODE); + u8 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE); + u8 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_BC_FP: + iface |= 0x80; + break; + case SND_SOC_DAIFMT_BC_FC: + iface &= 0x7f; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + adciface &= 0xfc; + daciface &= 0xf8; + break; + case SND_SOC_DAIFMT_LEFT_J: + adciface &= 0xfd; + daciface &= 0xf9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + adciface &= 0xfe; + daciface &= 0xfa; + break; + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + adciface &= 0xff; + daciface &= 0xfb; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= 0xdf; + adciface &= 0xdf; + daciface &= 0xbf; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x20; + adciface |= 0x20; + daciface |= 0x40; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + adciface &= 0xdf; + daciface &= 0xbf; + break; + case SND_SOC_DAIFMT_NB_IF: + iface &= 0xdf; + adciface |= 0x20; + daciface |= 0x40; + break; + default: + return -EINVAL; + } + + snd_soc_component_write(component, ES8323_MASTERMODE, iface); + snd_soc_component_write(component, ES8323_ADC_IFACE, adciface); + snd_soc_component_write(component, ES8323_DAC_IFACE, daciface); + + return 0; +} + +static int es8323_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + if (es8323->sysclk) { + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + es8323->sysclk_constraints); + } + + return 0; +} + +static int es8323_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + u16 srate = snd_soc_component_read(component, ES8323_MASTERMODE) & 0x80; + u16 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE) & 0xe3; + u16 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE) & 0xc7; + int coeff; + + coeff = get_coeff(es8323->sysclk, params_rate(params)); + if (coeff < 0) { + coeff = get_coeff(es8323->sysclk / 2, params_rate(params)); + srate |= 0x40; + } + + if (coeff < 0) { + dev_err(component->dev, + "Unable to configure sample rate %dHz with %dHz MCLK\n", + params_rate(params), es8323->sysclk); + return coeff; + } + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adciface |= 0xc; + daciface |= 0x18; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adciface |= 0x4; + daciface |= 0x8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + case SNDRV_PCM_FORMAT_S32_LE: + adciface |= 0x10; + daciface |= 0x20; + break; + } + + snd_soc_component_write(component, ES8323_DAC_IFACE, daciface); + snd_soc_component_write(component, ES8323_ADC_IFACE, adciface); + + snd_soc_component_write(component, ES8323_MASTERMODE, srate); + snd_soc_component_write(component, ES8323_ADCCONTROL5, + es8323_coeff_div[coeff].sr | + (es8323_coeff_div[coeff].usb) << 4); + snd_soc_component_write(component, ES8323_DACCONTROL2, + es8323_coeff_div[coeff].sr | + (es8323_coeff_div[coeff].usb) << 4); + + snd_soc_component_write(component, ES8323_DACPOWER, 0x3c); + + return 0; +} + +static int es8323_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + u32 val = mute ? 0x6 : 0x2; + + snd_soc_component_write(component, ES8323_DAC_MUTE, val); + + return 0; +} + +static const struct snd_soc_dai_ops es8323_ops = { + .startup = es8323_pcm_startup, + .hw_params = es8323_pcm_hw_params, + .set_fmt = es8323_set_dai_fmt, + .set_sysclk = es8323_set_dai_sysclk, + .mute_stream = es8323_mute_stream, +}; + +#define ES8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver es8323_dai = { + .name = "ES8323 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = ES8323_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = ES8323_FORMATS, + }, + .ops = &es8323_ops, + .symmetric_rate = 1, +}; + +static int es8323_probe(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + int ret; + + es8323->component = component; + + es8323->mclk = devm_clk_get_optional(component->dev, "mclk"); + if (IS_ERR(es8323->mclk)) { + dev_err(component->dev, "unable to get mclk\n"); + return PTR_ERR(es8323->mclk); + } + + if (!es8323->mclk) + dev_warn(component->dev, "assuming static mclk\n"); + + ret = clk_prepare_enable(es8323->mclk); + if (ret) { + dev_err(component->dev, "unable to enable mclk\n"); + return ret; + } + + snd_soc_component_write(component, ES8323_CONTROL2, 0x60); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_DACCONTROL17, 0xB8); + + return 0; +} + +static int es8323_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(es8323->mclk); + if (ret) + return ret; + + snd_soc_component_write(component, ES8323_CHIPPOWER, 0xf0); + usleep_range(18000, 20000); + snd_soc_component_write(component, ES8323_DACPOWER, 0x3c); + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_ADCPOWER, 0x09); + snd_soc_component_write(component, ES8323_ADCCONTROL14, 0x00); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_ADCPOWER, 0x59); + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8323->mclk); + snd_soc_component_write(component, ES8323_ADCPOWER, 0xff); + snd_soc_component_write(component, ES8323_DACPOWER, 0xC0); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0xff); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0xff); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0xff); + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7b); + break; + } + + return 0; +} + +static void es8323_remove(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(es8323->mclk); + es8323_set_bias_level(component, SND_SOC_BIAS_OFF); +} + +static int es8323_suspend(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8323->regmap, true); + regcache_mark_dirty(es8323->regmap); + + return 0; +} + +static int es8323_resume(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8323->regmap, false); + regcache_sync(es8323->regmap); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_es8323 = { + .probe = es8323_probe, + .remove = es8323_remove, + .suspend = es8323_suspend, + .resume = es8323_resume, + .set_bias_level = es8323_set_bias_level, + .controls = es8323_snd_controls, + .num_controls = ARRAY_SIZE(es8323_snd_controls), + .dapm_widgets = es8323_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8323_dapm_widgets), + .dapm_routes = es8323_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8323_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config es8323_regmap = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .max_register = 0x53, + .reg_defaults = es8323_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(es8323_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int es8323_i2c_probe(struct i2c_client *i2c_client) +{ + struct es8323_priv *es8323; + struct device *dev = &i2c_client->dev; + + es8323 = devm_kzalloc(dev, sizeof(*es8323), GFP_KERNEL); + if (!es8323) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, es8323); + + es8323->regmap = devm_regmap_init_i2c(i2c_client, &es8323_regmap); + if (IS_ERR(es8323->regmap)) + return PTR_ERR(es8323->regmap); + + return devm_snd_soc_register_component(dev, + &soc_component_dev_es8323, + &es8323_dai, 1); +} + +static const struct i2c_device_id es8323_i2c_id[] = { + { "es8323", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8323_i2c_id); + +static const struct acpi_device_id es8323_acpi_match[] = { + { "ESSX8323", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, es8323_acpi_match); + +static const struct of_device_id es8323_of_match[] = { + { .compatible = "everest,es8323" }, + { } +}; +MODULE_DEVICE_TABLE(of, es8323_of_match); + +static struct i2c_driver es8323_i2c_driver = { + .driver = { + .name = "ES8323", + .acpi_match_table = es8323_acpi_match, + .of_match_table = es8323_of_match, + }, + .probe = es8323_i2c_probe, + .id_table = es8323_i2c_id, +}; +module_i2c_driver(es8323_i2c_driver); + +MODULE_DESCRIPTION("Everest Semi ES8323 ALSA SoC Codec Driver"); +MODULE_AUTHOR("Mark Brown <broonie@kernel.org>"); +MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8323.h b/sound/soc/codecs/es8323.h new file mode 100644 index 000000000000..f986c9301dc6 --- /dev/null +++ b/sound/soc/codecs/es8323.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright Openedhand Ltd. + * + * Author: Richard Purdie <richard@openedhand.com> + * Binbin Zhou <zhoubinbin@loongson.cn> + * + */ + +#ifndef _ES8323_H +#define _ES8323_H + +/* ES8323 register space */ + +/* Chip Control and Power Management */ +#define ES8323_CONTROL1 0x00 +#define ES8323_CONTROL2 0x01 +#define ES8323_CHIPPOWER 0x02 +#define ES8323_ADCPOWER 0x03 +#define ES8323_DACPOWER 0x04 +#define ES8323_CHIPLOPOW1 0x05 +#define ES8323_CHIPLOPOW2 0x06 +#define ES8323_ANAVOLMANAG 0x07 +#define ES8323_MASTERMODE 0x08 + +/* ADC Control */ +#define ES8323_ADCCONTROL1 0x09 +#define ES8323_ADCCONTROL2 0x0a +#define ES8323_ADCCONTROL3 0x0b +#define ES8323_ADCCONTROL4 0x0c +#define ES8323_ADCCONTROL5 0x0d +#define ES8323_ADCCONTROL6 0x0e +#define ES8323_ADC_MUTE 0x0f +#define ES8323_LADC_VOL 0x10 +#define ES8323_RADC_VOL 0x11 +#define ES8323_ADCCONTROL10 0x12 +#define ES8323_ADCCONTROL11 0x13 +#define ES8323_ADCCONTROL12 0x14 +#define ES8323_ADCCONTROL13 0x15 +#define ES8323_ADCCONTROL14 0x16 + +/* DAC Control */ +#define ES8323_DACCONTROL1 0x17 +#define ES8323_DACCONTROL2 0x18 +#define ES8323_DAC_MUTE 0x19 +#define ES8323_LDAC_VOL 0x1a +#define ES8323_RDAC_VOL 0x1b +#define ES8323_DACCONTROL6 0x1c +#define ES8323_DACCONTROL7 0x1d +#define ES8323_DACCONTROL8 0x1e +#define ES8323_DACCONTROL9 0x1f +#define ES8323_DACCONTROL10 0x20 +#define ES8323_DACCONTROL11 0x21 +#define ES8323_DACCONTROL12 0x22 +#define ES8323_DACCONTROL13 0x23 +#define ES8323_DACCONTROL14 0x24 +#define ES8323_DACCONTROL15 0x25 +#define ES8323_DACCONTROL16 0x26 +#define ES8323_DACCONTROL17 0x27 +#define ES8323_DACCONTROL18 0x28 +#define ES8323_DACCONTROL19 0x29 +#define ES8323_DACCONTROL20 0x2a +#define ES8323_DACCONTROL21 0x2b +#define ES8323_DACCONTROL22 0x2c +#define ES8323_DACCONTROL23 0x2d +#define ES8323_LOUT1_VOL 0x2e +#define ES8323_ROUT1_VOL 0x2f +#define ES8323_LOUT2_VOL 0x30 +#define ES8323_ROUT2_VOL 0x31 +#define ES8323_DACCONTROL28 0x32 +#define ES8323_DACCONTROL29 0x33 +#define ES8323_DACCONTROL30 0x34 + +#define ES8323_ADC_IFACE ES8323_ADCCONTROL4 +#define ES8323_ADC_SRATE ES8323_ADCCONTROL5 +#define ES8323_DAC_IFACE ES8323_DACCONTROL1 +#define ES8323_DAC_SRATE ES8323_DACCONTROL2 +#endif diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index d5362b3be484..a5603b617688 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -614,6 +614,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) } else { regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, 0x0F, 0x0F); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40); + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x10); + } } } else { if (!es8326->calibrated) { @@ -640,6 +644,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) ES8326_MUTE_MASK, ~(ES8326_MUTE)); } else { msleep(300); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x50); + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00); + } regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, 0x0F, 0x00); } @@ -821,7 +829,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); - if ((es8326->jack_remove_retry == 1) && (es8326->version != ES8326_VERSION_B)) { + if ((es8326->jack_remove_retry == 1) && (es8326->version < ES8326_VERSION_B)) { if (iface & ES8326_HPINSERT_FLAG) es8326->jack_remove_retry = 2; else @@ -859,7 +867,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) /* * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event */ - if ((es8326->jack_remove_retry == 0) && (es8326->version != ES8326_VERSION_B)) { + if ((es8326->jack_remove_retry == 0) && (es8326->version < ES8326_VERSION_B)) { es8326->jack_remove_retry = 1; dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", es8326->jack_remove_retry); @@ -954,7 +962,7 @@ static int es8326_calibrate(struct snd_soc_component *component) regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); es8326->version = reg; - if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) { + if ((es8326->version >= ES8326_VERSION_B) && (es8326->calibrated == false)) { dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n"); regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0); regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x03); @@ -1047,7 +1055,7 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15); regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 | - ((es8326->version == ES8326_VERSION_B) ? + ((es8326->version >= ES8326_VERSION_B) ? (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); usleep_range(5000, 10000); @@ -1073,6 +1081,10 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); es8326_disable_micbias(es8326->component); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x73, 0x13); + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40); + } msleep(200); regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 74caae52e127..d9df29a26f4f 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -185,84 +185,97 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { /* * hdmi_codec_channel_alloc: speaker configuration available for CEA * - * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct + * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps * The preceding ones have better chances to be selected by * hdmi_codec_get_ch_alloc_table_idx(). */ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { { .ca_id = 0x00, .n_ch = 2, - .mask = FL | FR}, - /* 2.1 */ - { .ca_id = 0x01, .n_ch = 4, - .mask = FL | FR | LFE}, - /* Dolby Surround */ + .mask = FL | FR }, + { .ca_id = 0x03, .n_ch = 4, + .mask = FL | FR | LFE | FC }, { .ca_id = 0x02, .n_ch = 4, .mask = FL | FR | FC }, - /* surround51 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE }, { .ca_id = 0x0b, .n_ch = 6, - .mask = FL | FR | LFE | FC | RL | RR}, - /* surround40 */ - { .ca_id = 0x08, .n_ch = 6, - .mask = FL | FR | RL | RR }, - /* surround41 */ - { .ca_id = 0x09, .n_ch = 6, - .mask = FL | FR | LFE | RL | RR }, - /* surround50 */ + .mask = FL | FR | LFE | FC | RL | RR }, { .ca_id = 0x0a, .n_ch = 6, .mask = FL | FR | FC | RL | RR }, - /* 6.1 */ - { .ca_id = 0x0f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RC }, - /* surround71 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 6, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 6, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 6, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 6, + .mask = FL | FR | RC }, { .ca_id = 0x13, .n_ch = 8, .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, - /* others */ - { .ca_id = 0x03, .n_ch = 8, - .mask = FL | FR | LFE | FC }, - { .ca_id = 0x04, .n_ch = 8, - .mask = FL | FR | RC}, - { .ca_id = 0x05, .n_ch = 8, - .mask = FL | FR | LFE | RC }, - { .ca_id = 0x06, .n_ch = 8, - .mask = FL | FR | FC | RC }, - { .ca_id = 0x07, .n_ch = 8, - .mask = FL | FR | LFE | FC | RC }, - { .ca_id = 0x0c, .n_ch = 8, - .mask = FL | FR | RC | RL | RR }, - { .ca_id = 0x0d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RC }, - { .ca_id = 0x0e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RC }, - { .ca_id = 0x10, .n_ch = 8, - .mask = FL | FR | RL | RR | RLC | RRC }, - { .ca_id = 0x11, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, { .ca_id = 0x12, .n_ch = 8, .mask = FL | FR | FC | RL | RR | RLC | RRC }, - { .ca_id = 0x14, .n_ch = 8, - .mask = FL | FR | FLC | FRC }, - { .ca_id = 0x15, .n_ch = 8, - .mask = FL | FR | LFE | FLC | FRC }, - { .ca_id = 0x16, .n_ch = 8, - .mask = FL | FR | FC | FLC | FRC }, - { .ca_id = 0x17, .n_ch = 8, - .mask = FL | FR | LFE | FC | FLC | FRC }, - { .ca_id = 0x18, .n_ch = 8, - .mask = FL | FR | RC | FLC | FRC }, - { .ca_id = 0x19, .n_ch = 8, - .mask = FL | FR | LFE | RC | FLC | FRC }, - { .ca_id = 0x1a, .n_ch = 8, - .mask = FL | FR | RC | FC | FLC | FRC }, - { .ca_id = 0x1b, .n_ch = 8, - .mask = FL | FR | LFE | RC | FC | FLC | FRC }, - { .ca_id = 0x1c, .n_ch = 8, - .mask = FL | FR | RL | RR | FLC | FRC }, - { .ca_id = 0x1d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | FLC | FRC }, { .ca_id = 0x1e, .n_ch = 8, .mask = FL | FR | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x1f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, + { .ca_id = 0x0b, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR }, + { .ca_id = 0x0a, .n_ch = 8, + .mask = FL | FR | FC | RL | RR }, + { .ca_id = 0x09, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 8, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 8, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 8, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 8, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 8, + .mask = FL | FR | RC }, + { .ca_id = 0x03, .n_ch = 8, + .mask = FL | FR | LFE | FC }, + { .ca_id = 0x02, .n_ch = 8, + .mask = FL | FR | FC }, + { .ca_id = 0x01, .n_ch = 8, + .mask = FL | FR | LFE }, }; struct hdmi_codec_priv { @@ -371,7 +384,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hdmi_codec_priv *hcp = info->private_data; - map = info->chmap[hcp->chmap_idx].map; + if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) + map = info->chmap[hcp->chmap_idx].map; for (i = 0; i < info->max_channels; i++) { if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 8b0645c63462..8915f5250695 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -480,12 +480,18 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1), SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1), + SOC_SINGLE("DACL Volume", M98088_REG_2F_LVL_DAI1_PLAY, 0, 15, 1), + SOC_SINGLE("DACR Volume", M98088_REG_31_LVL_DAI2_PLAY, 0, 15, 1), + SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0), SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0), SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0), SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0), + SOC_SINGLE("Left HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 4, 1, 0), + SOC_SINGLE("Right HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 5, 1, 0), + SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0), SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0), @@ -515,10 +521,8 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { /* Left speaker mixer switch */ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0), @@ -529,10 +533,8 @@ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = { /* Right speaker mixer switch */ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0), @@ -543,10 +545,8 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = { /* Left headphone mixer switch */ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0), @@ -557,10 +557,8 @@ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = { /* Right headphone mixer switch */ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0), @@ -571,10 +569,8 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = { /* Left earpiece/receiver mixer switch */ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0), @@ -585,10 +581,8 @@ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = { /* Right earpiece/receiver mixer switch */ static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0), @@ -717,13 +711,9 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0), SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "HiFi Playback", - M98088_REG_4D_PWR_EN_OUT, 1, 0), - SND_SOC_DAPM_DAC("DACR1", "HiFi Playback", - M98088_REG_4D_PWR_EN_OUT, 0, 0), - SND_SOC_DAPM_DAC("DACL2", "Aux Playback", + SND_SOC_DAPM_DAC("DACL", "HiFi Playback", M98088_REG_4D_PWR_EN_OUT, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Aux Playback", + SND_SOC_DAPM_DAC("DACR", "HiFi Playback", M98088_REG_4D_PWR_EN_OUT, 0, 0), SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT, @@ -819,10 +809,8 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { static const struct snd_soc_dapm_route max98088_audio_map[] = { /* Left headphone output mixer */ - {"Left HP Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left HP Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left HP Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left HP Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left HP Mixer", "Left DAC Switch", "DACL"}, + {"Left HP Mixer", "Right DAC Switch", "DACR"}, {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left HP Mixer", "INA1 Switch", "INA1 Input"}, @@ -831,10 +819,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left HP Mixer", "INB2 Switch", "INB2 Input"}, /* Right headphone output mixer */ - {"Right HP Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right HP Mixer", "Left DAC2 Switch", "DACL2" }, - {"Right HP Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right HP Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right HP Mixer", "Left DAC Switch", "DACL"}, + {"Right HP Mixer", "Right DAC Switch", "DACR"}, {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right HP Mixer", "INA1 Switch", "INA1 Input"}, @@ -843,10 +829,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Right HP Mixer", "INB2 Switch", "INB2 Input"}, /* Left speaker output mixer */ - {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left SPK Mixer", "Left DAC Switch", "DACL"}, + {"Left SPK Mixer", "Right DAC Switch", "DACR"}, {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left SPK Mixer", "INA1 Switch", "INA1 Input"}, @@ -855,10 +839,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left SPK Mixer", "INB2 Switch", "INB2 Input"}, /* Right speaker output mixer */ - {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"}, - {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right SPK Mixer", "Left DAC Switch", "DACL"}, + {"Right SPK Mixer", "Right DAC Switch", "DACR"}, {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right SPK Mixer", "INA1 Switch", "INA1 Input"}, @@ -867,10 +849,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Right SPK Mixer", "INB2 Switch", "INB2 Input"}, /* Earpiece/Receiver output mixer */ - {"Left REC Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left REC Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left REC Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left REC Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left REC Mixer", "Left DAC Switch", "DACL"}, + {"Left REC Mixer", "Right DAC Switch", "DACR"}, {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left REC Mixer", "INA1 Switch", "INA1 Input"}, @@ -879,10 +859,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left REC Mixer", "INB2 Switch", "INB2 Input"}, /* Earpiece/Receiver output mixer */ - {"Right REC Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right REC Mixer", "Left DAC2 Switch", "DACL2"}, - {"Right REC Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right REC Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right REC Mixer", "Left DAC Switch", "DACL"}, + {"Right REC Mixer", "Right DAC Switch", "DACR"}, {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right REC Mixer", "INA1 Switch", "INA1 Input"}, diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index de5c4db05c8f..edb95f869a4a 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -287,10 +287,8 @@ static int nau8821_biq_coeff_get(struct snd_kcontrol *kcontrol, if (!component->regmap) return -EINVAL; - regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1, + return regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1, ucontrol->value.bytes.data, params->max); - - return 0; } static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, @@ -299,6 +297,7 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes_ext *params = (void *)kcontrol->private_value; void *data; + int ret; if (!component->regmap) return -EINVAL; @@ -308,12 +307,12 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, if (!data) return -ENOMEM; - regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1, + ret = regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1, data, params->max); kfree(data); - return 0; + return ret; } static const char * const nau8821_adc_decimation[] = { diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c new file mode 100644 index 000000000000..796e1410496f --- /dev/null +++ b/sound/soc/codecs/ntp8835.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the NTP8835/NTP8835C Audio Amplifiers + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + * + * Author: Igor Prusov <ivprusov@salutedevices.com> + */ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/bits.h> +#include <linux/reset.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include <sound/initval.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-component.h> +#include <sound/tlv.h> + +#include "ntpfw.h" + +#define NTP8835_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define NTP8835_INPUT_FMT 0x0 +#define NTP8835_INPUT_FMT_MASTER_MODE BIT(0) +#define NTP8835_INPUT_FMT_GSA_MODE BIT(1) +#define NTP8835_GSA_FMT 0x1 +#define NTP8835_GSA_BS_MASK GENMASK(3, 2) +#define NTP8835_GSA_BS(x) ((x) << 2) +#define NTP8835_GSA_RIGHT_J BIT(0) +#define NTP8835_GSA_LSB BIT(1) +#define NTP8835_MCLK_FREQ_CTRL 0x2 +#define NTP8835_MCLK_FREQ_MCF GENMASK(1, 0) +#define NTP8835_SOFT_MUTE 0x26 +#define NTP8835_SOFT_MUTE_SM1 BIT(0) +#define NTP8835_SOFT_MUTE_SM2 BIT(1) +#define NTP8835_SOFT_MUTE_SM3 BIT(2) +#define NTP8835_PWM_SWITCH 0x27 +#define NTP8835_PWM_SWITCH_POF1 BIT(0) +#define NTP8835_PWM_SWITCH_POF2 BIT(1) +#define NTP8835_PWM_SWITCH_POF3 BIT(2) +#define NTP8835_PWM_MASK_CTRL0 0x28 +#define NTP8835_PWM_MASK_CTRL0_OUT_LOW BIT(1) +#define NTP8835_PWM_MASK_CTRL0_FPMLD BIT(2) +#define NTP8835_MASTER_VOL 0x2e +#define NTP8835_CHNL_A_VOL 0x2f +#define NTP8835_CHNL_B_VOL 0x30 +#define NTP8835_CHNL_C_VOL 0x31 +#define REG_MAX NTP8835_CHNL_C_VOL + +#define NTP8835_FW_NAME "eq_8835.bin" +#define NTP8835_FW_MAGIC 0x38383335 /* "8835" */ + +struct ntp8835_priv { + struct i2c_client *i2c; + struct reset_control *reset; + unsigned int format; + struct clk *mclk; + unsigned int mclk_rate; +}; + +static const DECLARE_TLV_DB_RANGE(ntp8835_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(-15000, 0, 0), + 2, 6, TLV_DB_SCALE_ITEM(-15000, 1000, 0), + 7, 0xff, TLV_DB_SCALE_ITEM(-10000, 50, 0), +); + +static int ntp8835_mute_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->access = + (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE); + uinfo->count = 1; + + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + uinfo->value.integer.step = 1; + + return 0; +} + +static int ntp8835_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + val = snd_soc_component_read(component, NTP8835_SOFT_MUTE); + + ucontrol->value.integer.value[0] = val ? 0 : 1; + return 0; +} + +static int ntp8835_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + val = ucontrol->value.integer.value[0] ? 0 : 7; + + snd_soc_component_write(component, NTP8835_SOFT_MUTE, val); + + return 0; +} + +static const struct snd_kcontrol_new ntp8835_vol_control[] = { + SOC_SINGLE_TLV("Playback Volume", NTP8835_MASTER_VOL, 0, + 0xff, 0, ntp8835_vol_scale), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Playback Switch", + .info = ntp8835_mute_info, + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, + .get = ntp8835_mute_get, + .put = ntp8835_mute_put, + }, +}; + +static void ntp8835_reset_gpio(struct ntp8835_priv *ntp8835) +{ + /* + * Proper initialization sequence for NTP835 amplifier requires driving + * /RESET signal low during power up for at least 0.1us. The sequence is, + * according to NTP8835 datasheet, 6.2 Timing Sequence (recommended): + * Deassert for T2 >= 1ms... + */ + reset_control_deassert(ntp8835->reset); + fsleep(1000); + + /* ...Assert for T3 >= 0.1us... */ + reset_control_assert(ntp8835->reset); + fsleep(1); + + /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */ + reset_control_deassert(ntp8835->reset); + fsleep(500); +} + +static const struct reg_sequence ntp8835_sound_on[] = { + { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_FPMLD }, + { NTP8835_PWM_SWITCH, 0x00 }, + { NTP8835_SOFT_MUTE, 0x00 }, +}; + +static const struct reg_sequence ntp8835_sound_off[] = { + { NTP8835_SOFT_MUTE, NTP8835_SOFT_MUTE_SM1 | + NTP8835_SOFT_MUTE_SM2 | + NTP8835_SOFT_MUTE_SM3 }, + + { NTP8835_PWM_SWITCH, NTP8835_PWM_SWITCH_POF1 | + NTP8835_PWM_SWITCH_POF2 | + NTP8835_PWM_SWITCH_POF3 }, + + { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_OUT_LOW | + NTP8835_PWM_MASK_CTRL0_FPMLD }, +}; + +static int ntp8835_load_firmware(struct ntp8835_priv *ntp8835) +{ + int ret; + + ret = ntpfw_load(ntp8835->i2c, NTP8835_FW_NAME, NTP8835_FW_MAGIC); + if (ret == -ENOENT) { + dev_warn_once(&ntp8835->i2c->dev, + "Could not find firmware %s\n", NTP8835_FW_NAME); + return 0; + } + + return ret; +} + +static int ntp8835_snd_suspend(struct snd_soc_component *component) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(component->regmap, true); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8835_sound_off, + ARRAY_SIZE(ntp8835_sound_off)); + + /* + * According to NTP8835 datasheet, 6.2 Timing Sequence (recommended): + * wait after sound off for T6 >= 0.5ms + */ + fsleep(500); + reset_control_assert(ntp8835->reset); + + regcache_mark_dirty(component->regmap); + clk_disable_unprepare(ntp8835->mclk); + + return 0; +} + +static int ntp8835_snd_resume(struct snd_soc_component *component) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + int ret; + + ntp8835_reset_gpio(ntp8835); + ret = clk_prepare_enable(ntp8835->mclk); + if (ret) + return ret; + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8835_sound_on, + ARRAY_SIZE(ntp8835_sound_on)); + + ret = ntp8835_load_firmware(ntp8835); + if (ret) { + dev_err(&ntp8835->i2c->dev, "Failed to load firmware\n"); + return ret; + } + + regcache_cache_only(component->regmap, false); + snd_soc_component_cache_sync(component); + + return 0; +} + +static int ntp8835_probe(struct snd_soc_component *component) +{ + int ret; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + + ret = snd_soc_add_component_controls(component, ntp8835_vol_control, + ARRAY_SIZE(ntp8835_vol_control)); + if (ret) + return dev_err_probe(dev, ret, "Failed to add controls\n"); + + ret = ntp8835_load_firmware(ntp8835); + if (ret) + return dev_err_probe(dev, ret, "Failed to load firmware\n"); + + return 0; +} + +static const struct snd_soc_dapm_widget ntp8835_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), + SND_SOC_DAPM_OUTPUT("OUT3"), +}; + +static const struct snd_soc_dapm_route ntp8835_dapm_routes[] = { + { "OUT1", NULL, "AIFIN" }, + { "OUT2", NULL, "AIFIN" }, + { "OUT3", NULL, "AIFIN" }, +}; + +static int ntp8835_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + switch (freq) { + case 12288000: + case 24576000: + case 18432000: + ntp8835->mclk_rate = freq; + break; + default: + ntp8835->mclk_rate = 0; + dev_err(component->dev, "Unsupported MCLK value: %u", freq); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_component_driver soc_component_ntp8835 = { + .probe = ntp8835_probe, + .suspend = ntp8835_snd_suspend, + .resume = ntp8835_snd_resume, + .dapm_widgets = ntp8835_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ntp8835_dapm_widgets), + .dapm_routes = ntp8835_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ntp8835_dapm_routes), + .set_sysclk = ntp8835_set_component_sysclk, +}; + +static int ntp8835_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + unsigned int input_fmt = 0; + unsigned int gsa_fmt = 0; + unsigned int gsa_fmt_mask; + unsigned int mcf; + int ret; + + switch (ntp8835->mclk_rate) { + case 12288000: + mcf = 0; + break; + case 24576000: + mcf = 1; + break; + case 18432000: + mcf = 2; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, NTP8835_MCLK_FREQ_CTRL, + NTP8835_MCLK_FREQ_MCF, mcf); + if (ret) + return ret; + + switch (ntp8835->format) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + input_fmt |= NTP8835_INPUT_FMT_GSA_MODE; + gsa_fmt |= NTP8835_GSA_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + input_fmt |= NTP8835_INPUT_FMT_GSA_MODE; + break; + } + + ret = snd_soc_component_update_bits(component, NTP8835_INPUT_FMT, + NTP8835_INPUT_FMT_MASTER_MODE | + NTP8835_INPUT_FMT_GSA_MODE, + input_fmt); + + if (!(input_fmt & NTP8835_INPUT_FMT_GSA_MODE) || ret < 0) + return ret; + + switch (params_width(params)) { + case 24: + gsa_fmt |= NTP8835_GSA_BS(0); + break; + case 20: + gsa_fmt |= NTP8835_GSA_BS(1); + break; + case 18: + gsa_fmt |= NTP8835_GSA_BS(2); + break; + case 16: + gsa_fmt |= NTP8835_GSA_BS(3); + break; + default: + return -EINVAL; + } + + gsa_fmt_mask = NTP8835_GSA_BS_MASK | + NTP8835_GSA_RIGHT_J | + NTP8835_GSA_LSB; + return snd_soc_component_update_bits(component, NTP8835_GSA_FMT, + gsa_fmt_mask, gsa_fmt); +} + +static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + ntp8835->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + return 0; +}; + +static const struct snd_soc_dai_ops ntp8835_dai_ops = { + .hw_params = ntp8835_hw_params, + .set_fmt = ntp8835_set_fmt, +}; + +static struct snd_soc_dai_driver ntp8835_dai = { + .name = "ntp8835-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 3, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = NTP8835_FORMATS, + }, + .ops = &ntp8835_dai_ops, +}; + +static const struct regmap_config ntp8835_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, + .cache_type = REGCACHE_MAPLE, +}; + +static int ntp8835_i2c_probe(struct i2c_client *i2c) +{ + struct ntp8835_priv *ntp8835; + struct regmap *regmap; + int ret; + + ntp8835 = devm_kzalloc(&i2c->dev, sizeof(*ntp8835), GFP_KERNEL); + if (!ntp8835) + return -ENOMEM; + + ntp8835->i2c = i2c; + + ntp8835->reset = devm_reset_control_get_shared(&i2c->dev, NULL); + if (IS_ERR(ntp8835->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->reset), + "Failed to get reset\n"); + + ret = reset_control_deassert(ntp8835->reset); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to deassert reset\n"); + + dev_set_drvdata(&i2c->dev, ntp8835); + + ntp8835_reset_gpio(ntp8835); + + regmap = devm_regmap_init_i2c(i2c, &ntp8835_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Failed to allocate regmap\n"); + + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8835, + &ntp8835_dai, 1); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to register component\n"); + + ntp8835->mclk = devm_clk_get_enabled(&i2c->dev, "mclk"); + if (IS_ERR(ntp8835->mclk)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->mclk), "failed to get mclk\n"); + + return 0; +} + +static const struct i2c_device_id ntp8835_i2c_id[] = { + { "ntp8835", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id); + +static const struct of_device_id ntp8835_of_match[] = { + {.compatible = "neofidelity,ntp8835",}, + {} +}; +MODULE_DEVICE_TABLE(of, ntp8835_of_match); + +static struct i2c_driver ntp8835_i2c_driver = { + .probe = ntp8835_i2c_probe, + .id_table = ntp8835_i2c_id, + .driver = { + .name = "ntp8835", + .of_match_table = ntp8835_of_match, + }, +}; +module_i2c_driver(ntp8835_i2c_driver); + +MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>"); +MODULE_DESCRIPTION("NTP8835 Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c new file mode 100644 index 000000000000..0493ab6acbe4 --- /dev/null +++ b/sound/soc/codecs/ntp8918.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the NTP8918 Audio Amplifier + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + * + * Author: Igor Prusov <ivprusov@salutedevices.com> + */ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/reset.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> + +#include <sound/initval.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-component.h> +#include <sound/tlv.h> + +#include "ntpfw.h" + +#define NTP8918_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + +#define NTP8918_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define NTP8918_INPUT_FMT 0x0 +#define NTP8918_INPUT_FMT_MASTER_MODE BIT(0) +#define NTP8918_INPUT_FMT_GSA_MODE BIT(1) +#define NTP8918_GSA_FMT 0x1 +#define NTP8918_GSA_BS_MASK GENMASK(3, 2) +#define NTP8918_GSA_BS(x) ((x) << 2) +#define NTP8918_GSA_RIGHT_J BIT(0) +#define NTP8918_GSA_LSB BIT(1) +#define NTP8918_MCLK_FREQ_CTRL 0x2 +#define NTP8918_MCLK_FREQ_MCF GENMASK(1, 0) +#define NTP8918_MASTER_VOL 0x0C +#define NTP8918_CHNL_A_VOL 0x17 +#define NTP8918_CHNL_B_VOL 0x18 +#define NTP8918_SOFT_MUTE 0x33 +#define NTP8918_SOFT_MUTE_SM1 BIT(0) +#define NTP8918_SOFT_MUTE_SM2 BIT(1) +#define NTP8918_PWM_SWITCH 0x34 +#define NTP8918_PWM_MASK_CTRL0 0x35 +#define REG_MAX NTP8918_PWM_MASK_CTRL0 + +#define NTP8918_FW_NAME "eq_8918.bin" +#define NTP8918_FW_MAGIC 0x38393138 /* "8918" */ + +struct ntp8918_priv { + struct i2c_client *i2c; + struct clk *bck; + struct reset_control *reset; + unsigned int format; +}; + +static const DECLARE_TLV_DB_SCALE(ntp8918_master_vol_scale, -12550, 50, 0); + +static const struct snd_kcontrol_new ntp8918_vol_control[] = { + SOC_SINGLE_RANGE_TLV("Playback Volume", NTP8918_MASTER_VOL, 0, + 0x04, 0xff, 0, ntp8918_master_vol_scale), + SOC_SINGLE("Playback Switch", NTP8918_PWM_MASK_CTRL0, 1, 1, 1), +}; + +static void ntp8918_reset_gpio(struct ntp8918_priv *ntp8918) +{ + /* + * Proper initialization sequence for NTP8918 amplifier requires driving + * /RESET signal low during power up for at least 0.1us. The sequence is, + * according to NTP8918 datasheet, 6.2 Timing Sequence 1: + * Deassert for T2 >= 1ms... + */ + reset_control_deassert(ntp8918->reset); + fsleep(1000); + + /* ...Assert for T3 >= 0.1us... */ + reset_control_assert(ntp8918->reset); + fsleep(1); + + /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */ + reset_control_deassert(ntp8918->reset); + fsleep(500); +} + +static const struct reg_sequence ntp8918_sound_off[] = { + { NTP8918_MASTER_VOL, 0 }, +}; + +static const struct reg_sequence ntp8918_sound_on[] = { + { NTP8918_MASTER_VOL, 0b11 }, +}; + +static int ntp8918_load_firmware(struct ntp8918_priv *ntp8918) +{ + int ret; + + ret = ntpfw_load(ntp8918->i2c, NTP8918_FW_NAME, NTP8918_FW_MAGIC); + if (ret == -ENOENT) { + dev_warn_once(&ntp8918->i2c->dev, "Could not find firmware %s\n", + NTP8918_FW_NAME); + return 0; + } + + return ret; +} + +static int ntp8918_snd_suspend(struct snd_soc_component *component) +{ + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(component->regmap, true); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8918_sound_off, + ARRAY_SIZE(ntp8918_sound_off)); + + /* + * According to NTP8918 datasheet, 6.2 Timing Sequence 1: + * wait after sound off for T6 >= 0.5ms + */ + fsleep(500); + reset_control_assert(ntp8918->reset); + + regcache_mark_dirty(component->regmap); + clk_disable_unprepare(ntp8918->bck); + + return 0; +} + +static int ntp8918_snd_resume(struct snd_soc_component *component) +{ + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + int ret; + + ret = clk_prepare_enable(ntp8918->bck); + if (ret) + return ret; + + ntp8918_reset_gpio(ntp8918); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8918_sound_on, + ARRAY_SIZE(ntp8918_sound_on)); + + ret = ntp8918_load_firmware(ntp8918); + if (ret) { + dev_err(&ntp8918->i2c->dev, "Failed to load firmware\n"); + return ret; + } + + regcache_cache_only(component->regmap, false); + snd_soc_component_cache_sync(component); + + return 0; +} + +static int ntp8918_probe(struct snd_soc_component *component) +{ + int ret; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + + ret = snd_soc_add_component_controls(component, ntp8918_vol_control, + ARRAY_SIZE(ntp8918_vol_control)); + if (ret) + return dev_err_probe(dev, ret, "Failed to add controls\n"); + + ret = ntp8918_load_firmware(ntp8918); + if (ret) + return dev_err_probe(dev, ret, "Failed to load firmware\n"); + + return 0; +} + +static const struct snd_soc_dapm_widget ntp8918_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), +}; + +static const struct snd_soc_dapm_route ntp8918_dapm_routes[] = { + { "OUT1", NULL, "AIFIN" }, + { "OUT2", NULL, "AIFIN" }, +}; + +static const struct snd_soc_component_driver soc_component_ntp8918 = { + .probe = ntp8918_probe, + .suspend = ntp8918_snd_suspend, + .resume = ntp8918_snd_resume, + .dapm_widgets = ntp8918_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ntp8918_dapm_widgets), + .dapm_routes = ntp8918_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ntp8918_dapm_routes), +}; + +static int ntp8918_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + unsigned int input_fmt = 0; + unsigned int gsa_fmt = 0; + unsigned int gsa_fmt_mask; + unsigned int mcf; + int bclk; + int ret; + + bclk = snd_soc_params_to_bclk(params); + switch (bclk) { + case 3072000: + case 2822400: + mcf = 0; + break; + case 6144000: + mcf = 1; + break; + case 2048000: + mcf = 2; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, NTP8918_MCLK_FREQ_CTRL, + NTP8918_MCLK_FREQ_MCF, mcf); + if (ret) + return ret; + + switch (ntp8918->format) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + input_fmt |= NTP8918_INPUT_FMT_GSA_MODE; + gsa_fmt |= NTP8918_GSA_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + input_fmt |= NTP8918_INPUT_FMT_GSA_MODE; + break; + } + + ret = snd_soc_component_update_bits(component, NTP8918_INPUT_FMT, + NTP8918_INPUT_FMT_MASTER_MODE | + NTP8918_INPUT_FMT_GSA_MODE, + input_fmt); + + if (!(input_fmt & NTP8918_INPUT_FMT_GSA_MODE) || ret < 0) + return ret; + + switch (params_width(params)) { + case 24: + gsa_fmt |= NTP8918_GSA_BS(0); + break; + case 20: + gsa_fmt |= NTP8918_GSA_BS(1); + break; + case 18: + gsa_fmt |= NTP8918_GSA_BS(2); + break; + case 16: + gsa_fmt |= NTP8918_GSA_BS(3); + break; + default: + return -EINVAL; + } + + gsa_fmt_mask = NTP8918_GSA_BS_MASK | + NTP8918_GSA_RIGHT_J | + NTP8918_GSA_LSB; + return snd_soc_component_update_bits(component, NTP8918_GSA_FMT, + gsa_fmt_mask, gsa_fmt); +} + +static int ntp8918_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + ntp8918->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + return 0; +} + +static int ntp8918_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + unsigned int mute_mask = NTP8918_SOFT_MUTE_SM1 | + NTP8918_SOFT_MUTE_SM2; + + return snd_soc_component_update_bits(dai->component, NTP8918_SOFT_MUTE, + mute_mask, mute ? mute_mask : 0); +} + +static const struct snd_soc_dai_ops ntp8918_dai_ops = { + .hw_params = ntp8918_hw_params, + .set_fmt = ntp8918_set_fmt, + .mute_stream = ntp8918_digital_mute, +}; + +static struct snd_soc_dai_driver ntp8918_dai = { + .name = "ntp8918-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = NTP8918_RATES, + .formats = NTP8918_FORMATS, + }, + .ops = &ntp8918_dai_ops, +}; + +static const struct regmap_config ntp8918_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, + .cache_type = REGCACHE_MAPLE, +}; + +static int ntp8918_i2c_probe(struct i2c_client *i2c) +{ + struct ntp8918_priv *ntp8918; + int ret; + struct regmap *regmap; + + ntp8918 = devm_kzalloc(&i2c->dev, sizeof(*ntp8918), GFP_KERNEL); + if (!ntp8918) + return -ENOMEM; + + ntp8918->i2c = i2c; + + ntp8918->reset = devm_reset_control_get_shared(&i2c->dev, NULL); + if (IS_ERR(ntp8918->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->reset), "Failed to get reset\n"); + + dev_set_drvdata(&i2c->dev, ntp8918); + + ntp8918_reset_gpio(ntp8918); + + regmap = devm_regmap_init_i2c(i2c, &ntp8918_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Failed to allocate regmap\n"); + + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8918, + &ntp8918_dai, 1); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to register component\n"); + + ntp8918->bck = devm_clk_get_enabled(&i2c->dev, "bck"); + if (IS_ERR(ntp8918->bck)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->bck), "failed to get bck clock\n"); + + return 0; +} + +static const struct i2c_device_id ntp8918_i2c_id[] = { + { "ntp8918", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ntp8918_i2c_id); + +static const struct of_device_id ntp8918_of_match[] = { + {.compatible = "neofidelity,ntp8918"}, + {} +}; +MODULE_DEVICE_TABLE(of, ntp8918_of_match); + +static struct i2c_driver ntp8918_i2c_driver = { + .probe = ntp8918_i2c_probe, + .id_table = ntp8918_i2c_id, + .driver = { + .name = "ntp8918", + .of_match_table = ntp8918_of_match, + }, +}; +module_i2c_driver(ntp8918_i2c_driver); + +MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>"); +MODULE_DESCRIPTION("NTP8918 Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c new file mode 100644 index 000000000000..5ced2e966ab7 --- /dev/null +++ b/sound/soc/codecs/ntpfw.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntpfw.c - Firmware helper functions for Neofidelity codecs + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + */ + +#include <linux/i2c.h> +#include <linux/firmware.h> +#include <linux/module.h> + +#include "ntpfw.h" + +struct ntpfw_chunk { + __be16 length; + u8 step; + u8 data[]; +} __packed; + +struct ntpfw_header { + __be32 magic; +} __packed; + +static bool ntpfw_verify(struct device *dev, const u8 *buf, size_t buf_size, u32 magic) +{ + const struct ntpfw_header *header = (struct ntpfw_header *)buf; + u32 buf_magic; + + if (buf_size <= sizeof(*header)) { + dev_err(dev, "Failed to load firmware: image too small\n"); + return false; + } + + buf_magic = be32_to_cpu(header->magic); + if (buf_magic != magic) { + dev_err(dev, "Failed to load firmware: invalid magic 0x%x:\n", buf_magic); + return false; + } + + return true; +} + +static bool ntpfw_verify_chunk(struct device *dev, const struct ntpfw_chunk *chunk, size_t buf_size) +{ + size_t chunk_size; + + if (buf_size <= sizeof(*chunk)) { + dev_err(dev, "Failed to load firmware: chunk size too big\n"); + return false; + } + + if (chunk->step != 2 && chunk->step != 5) { + dev_err(dev, "Failed to load firmware: invalid chunk step: %d\n", chunk->step); + return false; + } + + chunk_size = be16_to_cpu(chunk->length); + if (chunk_size > buf_size) { + dev_err(dev, "Failed to load firmware: invalid chunk length\n"); + return false; + } + + if (chunk_size % chunk->step) { + dev_err(dev, "Failed to load firmware: chunk length and step mismatch\n"); + return false; + } + + return true; +} + +static int ntpfw_send_chunk(struct i2c_client *i2c, const struct ntpfw_chunk *chunk) +{ + int ret; + size_t i; + size_t length = be16_to_cpu(chunk->length); + + for (i = 0; i < length; i += chunk->step) { + ret = i2c_master_send(i2c, &chunk->data[i], chunk->step); + if (ret != chunk->step) { + dev_err(&i2c->dev, "I2C send failed: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + } + + return 0; +} + +int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) +{ + struct device *dev = &i2c->dev; + const struct ntpfw_chunk *chunk; + const struct firmware *fw; + const u8 *data; + size_t leftover; + int ret; + + ret = request_firmware(&fw, name, dev); + if (ret) { + dev_warn(dev, "request_firmware '%s' failed with %d\n", + name, ret); + return ret; + } + + if (!ntpfw_verify(dev, fw->data, fw->size, magic)) { + ret = -EINVAL; + goto done; + } + + data = fw->data + sizeof(struct ntpfw_header); + leftover = fw->size - sizeof(struct ntpfw_header); + + while (leftover) { + chunk = (struct ntpfw_chunk *)data; + + if (!ntpfw_verify_chunk(dev, chunk, leftover)) { + ret = -EINVAL; + goto done; + } + + ret = ntpfw_send_chunk(i2c, chunk); + if (ret) + goto done; + + data += be16_to_cpu(chunk->length) + sizeof(*chunk); + leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk); + } + +done: + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(ntpfw_load); + +MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>"); +MODULE_DESCRIPTION("Helper for loading Neofidelity amplifiers firmware"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h new file mode 100644 index 000000000000..1cf10d5480ee --- /dev/null +++ b/sound/soc/codecs/ntpfw.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/** + * ntpfw.h - Firmware helper functions for Neofidelity codecs + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + */ + +#ifndef __NTPFW_H__ +#define __NTPFW_H__ +#include <linux/i2c.h> +#include <linux/firmware.h> + +/** + * ntpfw_load - load firmware to amplifier over i2c interface. + * + * @i2c Pointer to amplifier's I2C client. + * @name Firmware file name. + * @magic Magic number to validate firmware. + * @return 0 or error code upon error. + */ +int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic); + +#endif /* __NTPFW_H__ */ diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 451a8fd8fac5..13443f569ddb 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -566,7 +566,7 @@ static int pcm186x_set_bias_level(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { +static const struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .set_bias_level = pcm186x_set_bias_level, .controls = pcm1863_snd_controls, .num_controls = ARRAY_SIZE(pcm1863_snd_controls), @@ -579,7 +579,7 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .endianness = 1, }; -static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { +static const struct snd_soc_component_driver soc_codec_dev_pcm1865 = { .set_bias_level = pcm186x_set_bias_level, .controls = pcm1865_snd_controls, .num_controls = ARRAY_SIZE(pcm1865_snd_controls), diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index 3401a25341e6..9bca53de2475 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -24,7 +24,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = { }, }; -static struct snd_soc_component_driver soc_component_dev_pcm5102a = { +static const struct snd_soc_component_driver soc_component_dev_pcm5102a = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, diff --git a/sound/soc/codecs/rt-sdw-common.c b/sound/soc/codecs/rt-sdw-common.c new file mode 100644 index 000000000000..ad61943ce75f --- /dev/null +++ b/sound/soc/codecs/rt-sdw-common.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt-sdw-common.c +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// + +/* + * This file defines common functions used with Realtek soundwire codecs. + */ + +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/bitops.h> +#include <linux/soundwire/sdw_registers.h> +#include <sound/jack.h> + +#include "rt-sdw-common.h" + +/** + * rt_sdca_index_write - Write a value to Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @value: value. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int rt_sdca_index_write(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int value) +{ + unsigned int addr = (nid << 20) | reg; + int ret; + + ret = regmap_write(map, addr, value); + if (ret < 0) + pr_err("Failed to set value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_index_write); + +/** + * rt_sdca_index_read - Read value from Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @value: value. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int rt_sdca_index_read(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int *value) +{ + unsigned int addr = (nid << 20) | reg; + int ret; + + ret = regmap_read(map, addr, value); + if (ret < 0) + pr_err("Failed to get value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_index_read); + +/** + * rt_sdca_index_update_bits - Update value on Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @mask: Bitmask to change + * @val: New value for bitmask + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ + +int rt_sdca_index_update_bits(struct regmap *map, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt_sdca_index_read(map, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + return rt_sdca_index_write(map, nid, reg, tmp); +} +EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits); + +/** + * rt_sdca_btn_type - Decision of button type. + * + * @buffer: UMP message buffer. + * + * A button type will be returned regarding to buffer, + * it returns zero if buffer cannot be recognized. + */ +int rt_sdca_btn_type(unsigned char *buffer) +{ + u8 btn_type = 0; + int ret = 0; + + btn_type |= buffer[0] & 0xf; + btn_type |= (buffer[0] >> 4) & 0xf; + btn_type |= buffer[1] & 0xf; + btn_type |= (buffer[1] >> 4) & 0xf; + + if (btn_type & BIT(0)) + ret |= SND_JACK_BTN_2; + if (btn_type & BIT(1)) + ret |= SND_JACK_BTN_3; + if (btn_type & BIT(2)) + ret |= SND_JACK_BTN_0; + if (btn_type & BIT(3)) + ret |= SND_JACK_BTN_1; + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_btn_type); + +/** + * rt_sdca_headset_detect - Headset jack type detection. + * + * @map: map for setting. + * @entity_id: SDCA entity ID. + * + * A headset jack type will be returned, a negative errno will + * be returned in error cases. + */ +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id) +{ + unsigned int det_mode, jack_type; + int ret; + + /* get detected_mode */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, + RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + + if (ret < 0) + goto io_error; + + switch (det_mode) { + case 0x03: + jack_type = SND_JACK_HEADPHONE; + break; + case 0x05: + jack_type = SND_JACK_HEADSET; + break; + default: + jack_type = 0; + break; + } + + /* write selected_mode */ + if (det_mode) { + ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, + RT_SDCA_CTL_SELECTED_MODE, 0), det_mode); + if (ret < 0) + goto io_error; + } + + return jack_type; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_headset_detect); + +/** + * rt_sdca_button_detect - Read UMP message and decide button type. + * + * @map: map for setting. + * @entity_id: SDCA entity ID. + * @hid_buf_addr: HID buffer address. + * @hid_id: Report ID for HID. + * + * A button type will be returned regarding to buffer, + * it returns zero if buffer cannot be recognized. + */ +int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id, + unsigned int hid_buf_addr, unsigned int hid_id) +{ + unsigned int btn_type = 0, offset, idx, val, owner; + unsigned char buf[3]; + int ret; + + /* get current UMP message owner */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner); + if (ret < 0) + return 0; + + /* if owner is device then there is no button event from device */ + if (owner == 1) + return 0; + + /* read UMP message offset */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto _end_btn_det_; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(map, hid_buf_addr + offset + idx, &val); + if (ret < 0) + goto _end_btn_det_; + buf[idx] = val & 0xff; + } + /* Report ID for HID */ + if (buf[0] == hid_id) + btn_type = rt_sdca_btn_type(&buf[1]); + +_end_btn_det_: + /* Host is owner, so set back to device */ + if (owner == 0) + /* set owner to device */ + regmap_write(map, + SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + + return btn_type; +} +EXPORT_SYMBOL_GPL(rt_sdca_button_detect); + +MODULE_DESCRIPTION("Realtek soundwire common functions"); +MODULE_AUTHOR("jack yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt-sdw-common.h b/sound/soc/codecs/rt-sdw-common.h new file mode 100644 index 000000000000..4759516feb38 --- /dev/null +++ b/sound/soc/codecs/rt-sdw-common.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// +// rt-sdw-common.h +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// + +/* + * This file defines common functions used with Realtek soundwire codecs. + */ + +#ifndef __RT_SDW_COMMON_H__ +#define __RT_SDW_COMMON_H__ + +#define SDCA_NUM_JACK_CODEC 0x01 +#define SDCA_NUM_MIC_ARRAY 0x02 +#define SDCA_NUM_HID 0x03 +#define SDCA_NUM_AMP 0x04 +#define RT_SDCA_CTL_SELECTED_MODE 0x01 +#define RT_SDCA_CTL_DETECTED_MODE 0x02 +#define RT_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 + +struct rt_sdca_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +#define RT_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \ + ((unsigned long)&(struct rt_sdca_dmic_kctrl_priv) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .invert = xinvert}) + +#define RT_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount, \ + xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = xinfo, \ + .get = xget, \ + .put = xput, \ + .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)} + +#define RT_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, xcount, xmax, tlv_array, xinfo) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = xinfo, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) } + + +int rt_sdca_index_write(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int value); +int rt_sdca_index_read(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int *value); +int rt_sdca_index_update_bits(struct regmap *map, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val); +int rt_sdca_btn_type(unsigned char *buffer); +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id); +int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id, + unsigned int hid_buf_addr, unsigned int hid_id); + +#endif /* __RT_SDW_COMMON_H__ */ diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index f4e1ea29c265..3510c3819074 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -21,6 +21,7 @@ #include <sound/tlv.h> #include <sound/sdw.h> #include "rt1320-sdw.h" +#include "rt-sdw-common.h" /* * The 'blind writes' is an SDCA term to deal with platform-specific initialization. @@ -89,6 +90,25 @@ static const struct reg_sequence rt1320_blind_write[] = { { 0xc019, 0x10 }, { 0xd487, 0x3f }, { 0xd486, 0xc3 }, + { 0x3fc2bfc7, 0x00 }, + { 0x3fc2bfc6, 0x00 }, + { 0x3fc2bfc5, 0x00 }, + { 0x3fc2bfc4, 0x01 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x02 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x11 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x82 }, + { 0x1000db06, 0x04 }, + { 0x1000db07, 0xf1 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0x40 }, + { 0x0000d540, 0x01 }, + { 0xd172, 0x2a }, + { 0xc5d6, 0x01 }, }; static const struct reg_sequence rt1320_vc_blind_write[] = { @@ -148,6 +168,12 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xd487, 0x3b }, { 0xd486, 0xc3 }, { 0xc598, 0x04 }, + { 0xdb03, 0xf0 }, + { 0xdb09, 0x00 }, + { 0xdb08, 0x7a }, + { 0xdb19, 0x02 }, + { 0xdb07, 0x5a }, + { 0xdb05, 0x45 }, { 0xd500, 0x00 }, { 0xd500, 0x17 }, { 0xd600, 0x01 }, @@ -164,1913 +190,6 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 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 }, @@ -2109,1346 +228,41 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = { { 0x0000d540, 0x01 }, { 0x0000c081, 0xfc }, { 0x0000f01e, 0x80 }, + { 0xc01b, 0xfc }, + { 0xc5d1, 0x89 }, + { 0xc5d8, 0x0a }, + { 0xc5f7, 0x22 }, + { 0xc5f6, 0x22 }, + { 0xc065, 0xa5 }, + { 0xc06b, 0x0a }, + { 0xd172, 0x2a }, + { 0xc5d6, 0x01 }, { 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. - */ -static const struct reg_sequence rt1320_patch_code_write[] = { - { 0x10007000, 0x37 }, - { 0x10007001, 0x77 }, - { 0x10007002, 0x00 }, - { 0x10007003, 0x10 }, - { 0x10007004, 0xb7 }, - { 0x10007005, 0xe7 }, - { 0x10007006, 0x00 }, - { 0x10007007, 0x10 }, - { 0x10007008, 0x13 }, - { 0x10007009, 0x07 }, - { 0x1000700a, 0x07 }, - { 0x1000700b, 0x40 }, - { 0x1000700c, 0x23 }, - { 0x1000700d, 0xae }, - { 0x1000700e, 0xe7 }, - { 0x1000700f, 0xda }, - { 0x10007010, 0x37 }, - { 0x10007011, 0x77 }, - { 0x10007012, 0x00 }, - { 0x10007013, 0x10 }, - { 0x10007014, 0x13 }, - { 0x10007015, 0x07 }, - { 0x10007016, 0x47 }, - { 0x10007017, 0x61 }, - { 0x10007018, 0x23 }, - { 0x10007019, 0xa4 }, - { 0x1000701a, 0xe7 }, - { 0x1000701b, 0xde }, - { 0x1000701c, 0x37 }, - { 0x1000701d, 0x77 }, - { 0x1000701e, 0x00 }, - { 0x1000701f, 0x10 }, - { 0x10007020, 0x13 }, - { 0x10007021, 0x07 }, - { 0x10007022, 0x07 }, - { 0x10007023, 0x52 }, - { 0x10007024, 0x23 }, - { 0x10007025, 0xae }, - { 0x10007026, 0xe7 }, - { 0x10007027, 0xde }, - { 0x10007028, 0x37 }, - { 0x10007029, 0x77 }, - { 0x1000702a, 0x00 }, - { 0x1000702b, 0x10 }, - { 0x1000702c, 0x13 }, - { 0x1000702d, 0x07 }, - { 0x1000702e, 0x47 }, - { 0x1000702f, 0x54 }, - { 0x10007030, 0x23 }, - { 0x10007031, 0xaa }, - { 0x10007032, 0xe7 }, - { 0x10007033, 0xe4 }, - { 0x10007034, 0x37 }, - { 0x10007035, 0x87 }, - { 0x10007036, 0x00 }, - { 0x10007037, 0x10 }, - { 0x10007038, 0x13 }, - { 0x10007039, 0x07 }, - { 0x1000703a, 0x47 }, - { 0x1000703b, 0x81 }, - { 0x1000703c, 0x23 }, - { 0x1000703d, 0xa2 }, - { 0x1000703e, 0xe7 }, - { 0x1000703f, 0xe8 }, - { 0x10007040, 0x23 }, - { 0x10007041, 0xa4 }, - { 0x10007042, 0xe7 }, - { 0x10007043, 0xe8 }, - { 0x10007044, 0x37 }, - { 0x10007045, 0x77 }, - { 0x10007046, 0x00 }, - { 0x10007047, 0x10 }, - { 0x10007048, 0x13 }, - { 0x10007049, 0x07 }, - { 0x1000704a, 0x07 }, - { 0x1000704b, 0x59 }, - { 0x1000704c, 0x23 }, - { 0x1000704d, 0xa8 }, - { 0x1000704e, 0xe7 }, - { 0x1000704f, 0xea }, - { 0x10007050, 0x37 }, - { 0x10007051, 0x77 }, - { 0x10007052, 0x00 }, - { 0x10007053, 0x10 }, - { 0x10007054, 0x13 }, - { 0x10007055, 0x07 }, - { 0x10007056, 0x07 }, - { 0x10007057, 0x78 }, - { 0x10007058, 0x23 }, - { 0x10007059, 0xa6 }, - { 0x1000705a, 0xe7 }, - { 0x1000705b, 0xec }, - { 0x1000705c, 0x67 }, - { 0x1000705d, 0x80 }, - { 0x1000705e, 0x00 }, - { 0x1000705f, 0x00 }, - { 0x10007400, 0x37 }, - { 0x10007401, 0xd7 }, - { 0x10007402, 0x00 }, - { 0x10007403, 0x00 }, - { 0x10007404, 0x83 }, - { 0x10007405, 0x27 }, - { 0x10007406, 0x47 }, - { 0x10007407, 0x56 }, - { 0x10007408, 0xb7 }, - { 0x10007409, 0x06 }, - { 0x1000740a, 0x00 }, - { 0x1000740b, 0x02 }, - { 0x1000740c, 0xb3 }, - { 0x1000740d, 0xf7 }, - { 0x1000740e, 0xd7 }, - { 0x1000740f, 0x00 }, - { 0x10007410, 0x63 }, - { 0x10007411, 0x8a }, - { 0x10007412, 0x07 }, - { 0x10007413, 0x00 }, - { 0x10007414, 0x93 }, - { 0x10007415, 0x06 }, - { 0x10007416, 0x10 }, - { 0x10007417, 0x00 }, - { 0x10007418, 0x23 }, - { 0x10007419, 0x83 }, - { 0x1000741a, 0xd1 }, - { 0x1000741b, 0x44 }, - { 0x1000741c, 0x93 }, - { 0x1000741d, 0x07 }, - { 0x1000741e, 0xf0 }, - { 0x1000741f, 0xff }, - { 0x10007420, 0x23 }, - { 0x10007421, 0x22 }, - { 0x10007422, 0xf7 }, - { 0x10007423, 0x56 }, - { 0x10007424, 0x37 }, - { 0x10007425, 0xd7 }, - { 0x10007426, 0x00 }, - { 0x10007427, 0x00 }, - { 0x10007428, 0x83 }, - { 0x10007429, 0x27 }, - { 0x1000742a, 0x47 }, - { 0x1000742b, 0x58 }, - { 0x1000742c, 0x93 }, - { 0x1000742d, 0xf7 }, - { 0x1000742e, 0x17 }, - { 0x1000742f, 0x00 }, - { 0x10007430, 0x63 }, - { 0x10007431, 0x86 }, - { 0x10007432, 0x07 }, - { 0x10007433, 0x00 }, - { 0x10007434, 0x93 }, - { 0x10007435, 0x07 }, - { 0x10007436, 0x10 }, - { 0x10007437, 0x00 }, - { 0x10007438, 0x23 }, - { 0x10007439, 0x22 }, - { 0x1000743a, 0xf7 }, - { 0x1000743b, 0x58 }, - { 0x1000743c, 0xb7 }, - { 0x1000743d, 0xd7 }, - { 0x1000743e, 0x00 }, - { 0x1000743f, 0x00 }, - { 0x10007440, 0x03 }, - { 0x10007441, 0xa7 }, - { 0x10007442, 0x47 }, - { 0x10007443, 0x58 }, - { 0x10007444, 0xb7 }, - { 0x10007445, 0x07 }, - { 0x10007446, 0x00 }, - { 0x10007447, 0x04 }, - { 0x10007448, 0x33 }, - { 0x10007449, 0x77 }, - { 0x1000744a, 0xf7 }, - { 0x1000744b, 0x00 }, - { 0x1000744c, 0x93 }, - { 0x1000744d, 0x07 }, - { 0x1000744e, 0x00 }, - { 0x1000744f, 0x00 }, - { 0x10007450, 0x63 }, - { 0x10007451, 0x0e }, - { 0x10007452, 0x07 }, - { 0x10007453, 0x04 }, - { 0x10007454, 0x37 }, - { 0x10007455, 0x07 }, - { 0x10007456, 0x00 }, - { 0x10007457, 0x11 }, - { 0x10007458, 0x03 }, - { 0x10007459, 0x47 }, - { 0x1000745a, 0x87 }, - { 0x1000745b, 0x0e }, - { 0x1000745c, 0x93 }, - { 0x1000745d, 0x06 }, - { 0x1000745e, 0x40 }, - { 0x1000745f, 0x00 }, - { 0x10007460, 0x13 }, - { 0x10007461, 0x77 }, - { 0x10007462, 0xf7 }, - { 0x10007463, 0x0f }, - { 0x10007464, 0x63 }, - { 0x10007465, 0x02 }, - { 0x10007466, 0xd7 }, - { 0x10007467, 0x0a }, - { 0x10007468, 0x93 }, - { 0x10007469, 0x06 }, - { 0x1000746a, 0x70 }, - { 0x1000746b, 0x00 }, - { 0x1000746c, 0x63 }, - { 0x1000746d, 0x10 }, - { 0x1000746e, 0xd7 }, - { 0x1000746f, 0x04 }, - { 0x10007470, 0x93 }, - { 0x10007471, 0x07 }, - { 0x10007472, 0x60 }, - { 0x10007473, 0x06 }, - { 0x10007474, 0x37 }, - { 0x10007475, 0xd7 }, - { 0x10007476, 0x00 }, - { 0x10007477, 0x00 }, - { 0x10007478, 0x83 }, - { 0x10007479, 0x46 }, - { 0x1000747a, 0x77 }, - { 0x1000747b, 0xa6 }, - { 0x1000747c, 0x93 }, - { 0x1000747d, 0xe6 }, - { 0x1000747e, 0x06 }, - { 0x1000747f, 0xf8 }, - { 0x10007480, 0x93 }, - { 0x10007481, 0xf6 }, - { 0x10007482, 0xf6 }, - { 0x10007483, 0x0f }, - { 0x10007484, 0xa3 }, - { 0x10007485, 0x03 }, - { 0x10007486, 0xd7 }, - { 0x10007487, 0xa6 }, - { 0x10007488, 0x83 }, - { 0x10007489, 0x46 }, - { 0x1000748a, 0x77 }, - { 0x1000748b, 0xa8 }, - { 0x1000748c, 0x93 }, - { 0x1000748d, 0xe6 }, - { 0x1000748e, 0x06 }, - { 0x1000748f, 0xf8 }, - { 0x10007490, 0x93 }, - { 0x10007491, 0xf6 }, - { 0x10007492, 0xf6 }, - { 0x10007493, 0x0f }, - { 0x10007494, 0xa3 }, - { 0x10007495, 0x03 }, - { 0x10007496, 0xd7 }, - { 0x10007497, 0xa8 }, - { 0x10007498, 0xb7 }, - { 0x10007499, 0xc6 }, - { 0x1000749a, 0x00 }, - { 0x1000749b, 0x00 }, - { 0x1000749c, 0x23 }, - { 0x1000749d, 0x84 }, - { 0x1000749e, 0xf6 }, - { 0x1000749f, 0x06 }, - { 0x100074a0, 0xa3 }, - { 0x100074a1, 0x84 }, - { 0x100074a2, 0xf6 }, - { 0x100074a3, 0x06 }, - { 0x100074a4, 0xb7 }, - { 0x100074a5, 0x06 }, - { 0x100074a6, 0x00 }, - { 0x100074a7, 0x04 }, - { 0x100074a8, 0x23 }, - { 0x100074a9, 0x22 }, - { 0x100074aa, 0xd7 }, - { 0x100074ab, 0x58 }, - { 0x100074ac, 0x37 }, - { 0x100074ad, 0xd7 }, - { 0x100074ae, 0x00 }, - { 0x100074af, 0x00 }, - { 0x100074b0, 0x03 }, - { 0x100074b1, 0x27 }, - { 0x100074b2, 0x47 }, - { 0x100074b3, 0x58 }, - { 0x100074b4, 0xb7 }, - { 0x100074b5, 0x06 }, - { 0x100074b6, 0x00 }, - { 0x100074b7, 0x08 }, - { 0x100074b8, 0x33 }, - { 0x100074b9, 0x77 }, - { 0x100074ba, 0xd7 }, - { 0x100074bb, 0x00 }, - { 0x100074bc, 0x63 }, - { 0x100074bd, 0x04 }, - { 0x100074be, 0x07 }, - { 0x100074bf, 0x04 }, - { 0x100074c0, 0x37 }, - { 0x100074c1, 0x07 }, - { 0x100074c2, 0x00 }, - { 0x100074c3, 0x11 }, - { 0x100074c4, 0x03 }, - { 0x100074c5, 0x47 }, - { 0x100074c6, 0xc7 }, - { 0x100074c7, 0x0e }, - { 0x100074c8, 0x93 }, - { 0x100074c9, 0x06 }, - { 0x100074ca, 0x40 }, - { 0x100074cb, 0x00 }, - { 0x100074cc, 0x13 }, - { 0x100074cd, 0x77 }, - { 0x100074ce, 0xf7 }, - { 0x100074cf, 0x0f }, - { 0x100074d0, 0x63 }, - { 0x100074d1, 0x00 }, - { 0x100074d2, 0xd7 }, - { 0x100074d3, 0x04 }, - { 0x100074d4, 0x93 }, - { 0x100074d5, 0x06 }, - { 0x100074d6, 0x70 }, - { 0x100074d7, 0x00 }, - { 0x100074d8, 0x63 }, - { 0x100074d9, 0x00 }, - { 0x100074da, 0xd7 }, - { 0x100074db, 0x04 }, - { 0x100074dc, 0x63 }, - { 0x100074dd, 0x84 }, - { 0x100074de, 0x07 }, - { 0x100074df, 0x02 }, - { 0x100074e0, 0xb7 }, - { 0x100074e1, 0xd6 }, - { 0x100074e2, 0x00 }, - { 0x100074e3, 0x00 }, - { 0x100074e4, 0x03 }, - { 0x100074e5, 0xc7 }, - { 0x100074e6, 0x56 }, - { 0x100074e7, 0xa4 }, - { 0x100074e8, 0x13 }, - { 0x100074e9, 0x67 }, - { 0x100074ea, 0x07 }, - { 0x100074eb, 0xf8 }, - { 0x100074ec, 0x13 }, - { 0x100074ed, 0x77 }, - { 0x100074ee, 0xf7 }, - { 0x100074ef, 0x0f }, - { 0x100074f0, 0xa3 }, - { 0x100074f1, 0x82 }, - { 0x100074f2, 0xe6 }, - { 0x100074f3, 0xa4 }, - { 0x100074f4, 0x37 }, - { 0x100074f5, 0xc7 }, - { 0x100074f6, 0x00 }, - { 0x100074f7, 0x00 }, - { 0x100074f8, 0x23 }, - { 0x100074f9, 0x02 }, - { 0x100074fa, 0xf7 }, - { 0x100074fb, 0x06 }, - { 0x100074fc, 0xb7 }, - { 0x100074fd, 0x07 }, - { 0x100074fe, 0x00 }, - { 0x100074ff, 0x08 }, - { 0x10007500, 0x23 }, - { 0x10007501, 0xa2 }, - { 0x10007502, 0xf6 }, - { 0x10007503, 0x58 }, - { 0x10007504, 0x67 }, - { 0x10007505, 0x80 }, - { 0x10007506, 0x00 }, - { 0x10007507, 0x00 }, - { 0x10007508, 0x93 }, - { 0x10007509, 0x07 }, - { 0x1000750a, 0x80 }, - { 0x1000750b, 0x08 }, - { 0x1000750c, 0x6f }, - { 0x1000750d, 0xf0 }, - { 0x1000750e, 0x9f }, - { 0x1000750f, 0xf6 }, - { 0x10007510, 0x93 }, - { 0x10007511, 0x07 }, - { 0x10007512, 0x80 }, - { 0x10007513, 0x08 }, - { 0x10007514, 0x6f }, - { 0x10007515, 0xf0 }, - { 0x10007516, 0xdf }, - { 0x10007517, 0xfc }, - { 0x10007518, 0x93 }, - { 0x10007519, 0x07 }, - { 0x1000751a, 0x60 }, - { 0x1000751b, 0x06 }, - { 0x1000751c, 0x6f }, - { 0x1000751d, 0xf0 }, - { 0x1000751e, 0x5f }, - { 0x1000751f, 0xfc }, - { 0x10007520, 0x37 }, - { 0x10007521, 0xd7 }, - { 0x10007522, 0x00 }, - { 0x10007523, 0x00 }, - { 0x10007524, 0x83 }, - { 0x10007525, 0x27 }, - { 0x10007526, 0x07 }, - { 0x10007527, 0x53 }, - { 0x10007528, 0xb7 }, - { 0x10007529, 0x06 }, - { 0x1000752a, 0x02 }, - { 0x1000752b, 0x00 }, - { 0x1000752c, 0xb3 }, - { 0x1000752d, 0xf7 }, - { 0x1000752e, 0xd7 }, - { 0x1000752f, 0x00 }, - { 0x10007530, 0x63 }, - { 0x10007531, 0x88 }, - { 0x10007532, 0x07 }, - { 0x10007533, 0x00 }, - { 0x10007534, 0x13 }, - { 0x10007535, 0x06 }, - { 0x10007536, 0xa0 }, - { 0x10007537, 0x05 }, - { 0x10007538, 0x23 }, - { 0x10007539, 0xa8 }, - { 0x1000753a, 0xc1 }, - { 0x1000753b, 0x56 }, - { 0x1000753c, 0x23 }, - { 0x1000753d, 0x28 }, - { 0x1000753e, 0xd7 }, - { 0x1000753f, 0x52 }, - { 0x10007540, 0x67 }, - { 0x10007541, 0x80 }, - { 0x10007542, 0x00 }, - { 0x10007543, 0x00 }, - { 0x10007544, 0x37 }, - { 0x10007545, 0xd7 }, - { 0x10007546, 0x00 }, - { 0x10007547, 0x10 }, - { 0x10007548, 0x83 }, - { 0x10007549, 0x47 }, - { 0x1000754a, 0x07 }, - { 0x1000754b, 0xd9 }, - { 0x1000754c, 0x93 }, - { 0x1000754d, 0x06 }, - { 0x1000754e, 0x20 }, - { 0x1000754f, 0x00 }, - { 0x10007550, 0x93 }, - { 0x10007551, 0xf7 }, - { 0x10007552, 0xf7 }, - { 0x10007553, 0x0f }, - { 0x10007554, 0x63 }, - { 0x10007555, 0x9c }, - { 0x10007556, 0xd7 }, - { 0x10007557, 0x02 }, - { 0x10007558, 0xb7 }, - { 0x10007559, 0xc6 }, - { 0x1000755a, 0x00 }, - { 0x1000755b, 0x00 }, - { 0x1000755c, 0x83 }, - { 0x1000755d, 0xc7 }, - { 0x1000755e, 0x26 }, - { 0x1000755f, 0x04 }, - { 0x10007560, 0x93 }, - { 0x10007561, 0xf7 }, - { 0x10007562, 0xf7 }, - { 0x10007563, 0x07 }, - { 0x10007564, 0x23 }, - { 0x10007565, 0x81 }, - { 0x10007566, 0xf6 }, - { 0x10007567, 0x04 }, - { 0x10007568, 0xb7 }, - { 0x10007569, 0xd6 }, - { 0x1000756a, 0x00 }, - { 0x1000756b, 0x00 }, - { 0x1000756c, 0x83 }, - { 0x1000756d, 0xc7 }, - { 0x1000756e, 0xa6 }, - { 0x1000756f, 0xe1 }, - { 0x10007570, 0x93 }, - { 0x10007571, 0xf7 }, - { 0x10007572, 0xf7 }, - { 0x10007573, 0x07 }, - { 0x10007574, 0x23 }, - { 0x10007575, 0x8d }, - { 0x10007576, 0xf6 }, - { 0x10007577, 0xe0 }, - { 0x10007578, 0x23 }, - { 0x10007579, 0x08 }, - { 0x1000757a, 0x07 }, - { 0x1000757b, 0xd8 }, - { 0x1000757c, 0x83 }, - { 0x1000757d, 0x47 }, - { 0x1000757e, 0x47 }, - { 0x1000757f, 0xd9 }, - { 0x10007580, 0x93 }, - { 0x10007581, 0x87 }, - { 0x10007582, 0x17 }, - { 0x10007583, 0x00 }, - { 0x10007584, 0x93 }, - { 0x10007585, 0xf7 }, - { 0x10007586, 0xf7 }, - { 0x10007587, 0x0f }, - { 0x10007588, 0x23 }, - { 0x10007589, 0x0a }, - { 0x1000758a, 0xf7 }, - { 0x1000758b, 0xd8 }, - { 0x1000758c, 0x67 }, - { 0x1000758d, 0x80 }, - { 0x1000758e, 0x00 }, - { 0x1000758f, 0x00 }, - { 0x10007590, 0xb7 }, - { 0x10007591, 0xd7 }, - { 0x10007592, 0x00 }, - { 0x10007593, 0x00 }, - { 0x10007594, 0x83 }, - { 0x10007595, 0xc7 }, - { 0x10007596, 0x07 }, - { 0x10007597, 0x47 }, - { 0x10007598, 0x93 }, - { 0x10007599, 0xf7 }, - { 0x1000759a, 0x07 }, - { 0x1000759b, 0x01 }, - { 0x1000759c, 0x63 }, - { 0x1000759d, 0x8a }, - { 0x1000759e, 0x07 }, - { 0x1000759f, 0x06 }, - { 0x100075a0, 0x63 }, - { 0x100075a1, 0x02 }, - { 0x100075a2, 0x05 }, - { 0x100075a3, 0x06 }, - { 0x100075a4, 0x37 }, - { 0x100075a5, 0xc7 }, - { 0x100075a6, 0x00 }, - { 0x100075a7, 0x00 }, - { 0x100075a8, 0x83 }, - { 0x100075a9, 0x27 }, - { 0x100075aa, 0xc7 }, - { 0x100075ab, 0x5f }, - { 0x100075ac, 0x23 }, - { 0x100075ad, 0xae }, - { 0x100075ae, 0xf1 }, - { 0x100075af, 0x40 }, - { 0x100075b0, 0xb7 }, - { 0x100075b1, 0x06 }, - { 0x100075b2, 0x00 }, - { 0x100075b3, 0x10 }, - { 0x100075b4, 0xb3 }, - { 0x100075b5, 0xf7 }, - { 0x100075b6, 0xd7 }, - { 0x100075b7, 0x00 }, - { 0x100075b8, 0x63 }, - { 0x100075b9, 0x8c }, - { 0x100075ba, 0x07 }, - { 0x100075bb, 0x04 }, - { 0x100075bc, 0x83 }, - { 0x100075bd, 0x47 }, - { 0x100075be, 0x07 }, - { 0x100075bf, 0x56 }, - { 0x100075c0, 0x93 }, - { 0x100075c1, 0xf7 }, - { 0x100075c2, 0x87 }, - { 0x100075c3, 0x01 }, - { 0x100075c4, 0x63 }, - { 0x100075c5, 0x86 }, - { 0x100075c6, 0x07 }, - { 0x100075c7, 0x04 }, - { 0x100075c8, 0x83 }, - { 0x100075c9, 0x47 }, - { 0x100075ca, 0x17 }, - { 0x100075cb, 0x08 }, - { 0x100075cc, 0x93 }, - { 0x100075cd, 0xf7 }, - { 0x100075ce, 0x47 }, - { 0x100075cf, 0x00 }, - { 0x100075d0, 0x63 }, - { 0x100075d1, 0x80 }, - { 0x100075d2, 0x07 }, - { 0x100075d3, 0x04 }, - { 0x100075d4, 0xb7 }, - { 0x100075d5, 0xc7 }, - { 0x100075d6, 0xc2 }, - { 0x100075d7, 0x3f }, - { 0x100075d8, 0x93 }, - { 0x100075d9, 0x87 }, - { 0x100075da, 0x07 }, - { 0x100075db, 0xfc }, - { 0x100075dc, 0x83 }, - { 0x100075dd, 0xa7 }, - { 0x100075de, 0x47 }, - { 0x100075df, 0x00 }, - { 0x100075e0, 0x93 }, - { 0x100075e1, 0xd7 }, - { 0x100075e2, 0x17 }, - { 0x100075e3, 0x00 }, - { 0x100075e4, 0x93 }, - { 0x100075e5, 0xf7 }, - { 0x100075e6, 0x17 }, - { 0x100075e7, 0x00 }, - { 0x100075e8, 0x63 }, - { 0x100075e9, 0x84 }, - { 0x100075ea, 0x07 }, - { 0x100075eb, 0x02 }, - { 0x100075ec, 0x23 }, - { 0x100075ed, 0x8a }, - { 0x100075ee, 0xf1 }, - { 0x100075ef, 0x40 }, - { 0x100075f0, 0xb7 }, - { 0x100075f1, 0x07 }, - { 0x100075f2, 0x00 }, - { 0x100075f3, 0xc0 }, - { 0x100075f4, 0x37 }, - { 0x100075f5, 0xf7 }, - { 0x100075f6, 0x00 }, - { 0x100075f7, 0x00 }, - { 0x100075f8, 0x93 }, - { 0x100075f9, 0x87 }, - { 0x100075fa, 0xf7 }, - { 0x100075fb, 0xff }, - { 0x100075fc, 0x23 }, - { 0x100075fd, 0x2c }, - { 0x100075fe, 0xf7 }, - { 0x100075ff, 0x06 }, - { 0x10007600, 0x67 }, - { 0x10007601, 0x80 }, - { 0x10007602, 0x00 }, - { 0x10007603, 0x00 }, - { 0x10007604, 0x23 }, - { 0x10007605, 0x8a }, - { 0x10007606, 0x01 }, - { 0x10007607, 0x40 }, - { 0x10007608, 0xb7 }, - { 0x10007609, 0xf7 }, - { 0x1000760a, 0x00 }, - { 0x1000760b, 0x00 }, - { 0x1000760c, 0x23 }, - { 0x1000760d, 0xac }, - { 0x1000760e, 0x07 }, - { 0x1000760f, 0x06 }, - { 0x10007610, 0x67 }, - { 0x10007611, 0x80 }, - { 0x10007612, 0x00 }, - { 0x10007613, 0x00 }, - { 0x10007614, 0x13 }, - { 0x10007615, 0x01 }, - { 0x10007616, 0x01 }, - { 0x10007617, 0xff }, - { 0x10007618, 0x23 }, - { 0x10007619, 0x26 }, - { 0x1000761a, 0x11 }, - { 0x1000761b, 0x00 }, - { 0x1000761c, 0x23 }, - { 0x1000761d, 0x24 }, - { 0x1000761e, 0x81 }, - { 0x1000761f, 0x00 }, - { 0x10007620, 0x37 }, - { 0x10007621, 0xc7 }, - { 0x10007622, 0x00 }, - { 0x10007623, 0x00 }, - { 0x10007624, 0x83 }, - { 0x10007625, 0x47 }, - { 0x10007626, 0x07 }, - { 0x10007627, 0x56 }, - { 0x10007628, 0x93 }, - { 0x10007629, 0xf7 }, - { 0x1000762a, 0x17 }, - { 0x1000762b, 0x00 }, - { 0x1000762c, 0x63 }, - { 0x1000762d, 0x98 }, - { 0x1000762e, 0x07 }, - { 0x1000762f, 0x00 }, - { 0x10007630, 0x83 }, - { 0x10007631, 0x47 }, - { 0x10007632, 0x07 }, - { 0x10007633, 0x56 }, - { 0x10007634, 0x93 }, - { 0x10007635, 0xf7 }, - { 0x10007636, 0x27 }, - { 0x10007637, 0x00 }, - { 0x10007638, 0x63 }, - { 0x10007639, 0x82 }, - { 0x1000763a, 0x07 }, - { 0x1000763b, 0x08 }, - { 0x1000763c, 0x37 }, - { 0x1000763d, 0xd4 }, - { 0x1000763e, 0x00 }, - { 0x1000763f, 0x00 }, - { 0x10007640, 0x83 }, - { 0x10007641, 0x47 }, - { 0x10007642, 0x14 }, - { 0x10007643, 0x47 }, - { 0x10007644, 0x93 }, - { 0x10007645, 0xf7 }, - { 0x10007646, 0x27 }, - { 0x10007647, 0x00 }, - { 0x10007648, 0x63 }, - { 0x10007649, 0x8a }, - { 0x1000764a, 0x07 }, - { 0x1000764b, 0x06 }, - { 0x1000764c, 0x93 }, - { 0x1000764d, 0x05 }, - { 0x1000764e, 0x10 }, - { 0x1000764f, 0x00 }, - { 0x10007650, 0x13 }, - { 0x10007651, 0x05 }, - { 0x10007652, 0x20 }, - { 0x10007653, 0x10 }, - { 0x10007654, 0xef }, - { 0x10007655, 0xa0 }, - { 0x10007656, 0x8f }, - { 0x10007657, 0x9a }, - { 0x10007658, 0x37 }, - { 0x10007659, 0x05 }, - { 0x1000765a, 0x01 }, - { 0x1000765b, 0x00 }, - { 0x1000765c, 0x93 }, - { 0x1000765d, 0x05 }, - { 0x1000765e, 0x00 }, - { 0x1000765f, 0x01 }, - { 0x10007660, 0x13 }, - { 0x10007661, 0x05 }, - { 0x10007662, 0xb5 }, - { 0x10007663, 0xa0 }, - { 0x10007664, 0xef }, - { 0x10007665, 0xa0 }, - { 0x10007666, 0x8f }, - { 0x10007667, 0x99 }, - { 0x10007668, 0x83 }, - { 0x10007669, 0x47 }, - { 0x1000766a, 0x24 }, - { 0x1000766b, 0xe0 }, - { 0x1000766c, 0x13 }, - { 0x1000766d, 0x05 }, - { 0x1000766e, 0x80 }, - { 0x1000766f, 0x3e }, - { 0x10007670, 0x93 }, - { 0x10007671, 0x05 }, - { 0x10007672, 0x00 }, - { 0x10007673, 0x00 }, - { 0x10007674, 0x93 }, - { 0x10007675, 0xe7 }, - { 0x10007676, 0x07 }, - { 0x10007677, 0xf8 }, - { 0x10007678, 0x93 }, - { 0x10007679, 0xf7 }, - { 0x1000767a, 0xf7 }, - { 0x1000767b, 0x0f }, - { 0x1000767c, 0x23 }, - { 0x1000767d, 0x01 }, - { 0x1000767e, 0xf4 }, - { 0x1000767f, 0xe0 }, - { 0x10007680, 0x83 }, - { 0x10007681, 0x47 }, - { 0x10007682, 0x24 }, - { 0x10007683, 0xe0 }, - { 0x10007684, 0x93 }, - { 0x10007685, 0xf7 }, - { 0x10007686, 0xf7 }, - { 0x10007687, 0x0f }, - { 0x10007688, 0x93 }, - { 0x10007689, 0xe7 }, - { 0x1000768a, 0x07 }, - { 0x1000768b, 0x04 }, - { 0x1000768c, 0x23 }, - { 0x1000768d, 0x01 }, - { 0x1000768e, 0xf4 }, - { 0x1000768f, 0xe0 }, - { 0x10007690, 0xef }, - { 0x10007691, 0xe0 }, - { 0x10007692, 0x8f }, - { 0x10007693, 0xb9 }, - { 0x10007694, 0x83 }, - { 0x10007695, 0x47 }, - { 0x10007696, 0x34 }, - { 0x10007697, 0xe0 }, - { 0x10007698, 0x93 }, - { 0x10007699, 0xf7 }, - { 0x1000769a, 0x07 }, - { 0x1000769b, 0x02 }, - { 0x1000769c, 0xe3 }, - { 0x1000769d, 0x9c }, - { 0x1000769e, 0x07 }, - { 0x1000769f, 0xfe }, - { 0x100076a0, 0x37 }, - { 0x100076a1, 0x05 }, - { 0x100076a2, 0x01 }, - { 0x100076a3, 0x00 }, - { 0x100076a4, 0x93 }, - { 0x100076a5, 0x05 }, - { 0x100076a6, 0x00 }, - { 0x100076a7, 0x00 }, - { 0x100076a8, 0x13 }, - { 0x100076a9, 0x05 }, - { 0x100076aa, 0xb5 }, - { 0x100076ab, 0xa0 }, - { 0x100076ac, 0xef }, - { 0x100076ad, 0xa0 }, - { 0x100076ae, 0x0f }, - { 0x100076af, 0x95 }, - { 0x100076b0, 0x83 }, - { 0x100076b1, 0x47 }, - { 0x100076b2, 0x14 }, - { 0x100076b3, 0x47 }, - { 0x100076b4, 0x93 }, - { 0x100076b5, 0xf7 }, - { 0x100076b6, 0xd7 }, - { 0x100076b7, 0x0f }, - { 0x100076b8, 0xa3 }, - { 0x100076b9, 0x08 }, - { 0x100076ba, 0xf4 }, - { 0x100076bb, 0x46 }, - { 0x100076bc, 0x03 }, - { 0x100076bd, 0xa7 }, - { 0x100076be, 0x01 }, - { 0x100076bf, 0x57 }, - { 0x100076c0, 0x93 }, - { 0x100076c1, 0x07 }, - { 0x100076c2, 0xa0 }, - { 0x100076c3, 0x05 }, - { 0x100076c4, 0x63 }, - { 0x100076c5, 0x14 }, - { 0x100076c6, 0xf7 }, - { 0x100076c7, 0x04 }, - { 0x100076c8, 0x37 }, - { 0x100076c9, 0x07 }, - { 0x100076ca, 0x00 }, - { 0x100076cb, 0x11 }, - { 0x100076cc, 0x83 }, - { 0x100076cd, 0x47 }, - { 0x100076ce, 0x07 }, - { 0x100076cf, 0x01 }, - { 0x100076d0, 0x13 }, - { 0x100076d1, 0x06 }, - { 0x100076d2, 0x30 }, - { 0x100076d3, 0x00 }, - { 0x100076d4, 0x93 }, - { 0x100076d5, 0xf7 }, - { 0x100076d6, 0xf7 }, - { 0x100076d7, 0x0f }, - { 0x100076d8, 0x63 }, - { 0x100076d9, 0x9a }, - { 0x100076da, 0xc7 }, - { 0x100076db, 0x02 }, - { 0x100076dc, 0x03 }, - { 0x100076dd, 0x47 }, - { 0x100076de, 0x87 }, - { 0x100076df, 0x01 }, - { 0x100076e0, 0x13 }, - { 0x100076e1, 0x77 }, - { 0x100076e2, 0xf7 }, - { 0x100076e3, 0x0f }, - { 0x100076e4, 0x63 }, - { 0x100076e5, 0x14 }, - { 0x100076e6, 0xf7 }, - { 0x100076e7, 0x02 }, - { 0x100076e8, 0x37 }, - { 0x100076e9, 0xd7 }, - { 0x100076ea, 0x00 }, - { 0x100076eb, 0x00 }, - { 0x100076ec, 0x83 }, - { 0x100076ed, 0x47 }, - { 0x100076ee, 0x37 }, - { 0x100076ef, 0x54 }, - { 0x100076f0, 0x93 }, - { 0x100076f1, 0xf7 }, - { 0x100076f2, 0xf7 }, - { 0x100076f3, 0x0f }, - { 0x100076f4, 0x93 }, - { 0x100076f5, 0xe7 }, - { 0x100076f6, 0x07 }, - { 0x100076f7, 0x02 }, - { 0x100076f8, 0xa3 }, - { 0x100076f9, 0x01 }, - { 0x100076fa, 0xf7 }, - { 0x100076fb, 0x54 }, - { 0x100076fc, 0x83 }, - { 0x100076fd, 0x47 }, - { 0x100076fe, 0x37 }, - { 0x100076ff, 0x54 }, - { 0x10007700, 0x93 }, - { 0x10007701, 0xf7 }, - { 0x10007702, 0xf7 }, - { 0x10007703, 0x0d }, - { 0x10007704, 0xa3 }, - { 0x10007705, 0x01 }, - { 0x10007706, 0xf7 }, - { 0x10007707, 0x54 }, - { 0x10007708, 0x23 }, - { 0x10007709, 0xa8 }, - { 0x1000770a, 0x01 }, - { 0x1000770b, 0x56 }, - { 0x1000770c, 0xb7 }, - { 0x1000770d, 0xd7 }, - { 0x1000770e, 0x00 }, - { 0x1000770f, 0x10 }, - { 0x10007710, 0x03 }, - { 0x10007711, 0xc7 }, - { 0x10007712, 0x07 }, - { 0x10007713, 0xd9 }, - { 0x10007714, 0x93 }, - { 0x10007715, 0x06 }, - { 0x10007716, 0x10 }, - { 0x10007717, 0x00 }, - { 0x10007718, 0x13 }, - { 0x10007719, 0x77 }, - { 0x1000771a, 0xf7 }, - { 0x1000771b, 0x0f }, - { 0x1000771c, 0x63 }, - { 0x1000771d, 0x1a }, - { 0x1000771e, 0xd7 }, - { 0x1000771f, 0x04 }, - { 0x10007720, 0x03 }, - { 0x10007721, 0xc7 }, - { 0x10007722, 0x27 }, - { 0x10007723, 0xd9 }, - { 0x10007724, 0x13 }, - { 0x10007725, 0x07 }, - { 0x10007726, 0x17 }, - { 0x10007727, 0x00 }, - { 0x10007728, 0x13 }, - { 0x10007729, 0x77 }, - { 0x1000772a, 0xf7 }, - { 0x1000772b, 0x0f }, - { 0x1000772c, 0x23 }, - { 0x1000772d, 0x89 }, - { 0x1000772e, 0xe7 }, - { 0x1000772f, 0xd8 }, - { 0x10007730, 0x83 }, - { 0x10007731, 0xc6 }, - { 0x10007732, 0x27 }, - { 0x10007733, 0xd9 }, - { 0x10007734, 0x03 }, - { 0x10007735, 0xc7 }, - { 0x10007736, 0x17 }, - { 0x10007737, 0xd9 }, - { 0x10007738, 0x93 }, - { 0x10007739, 0xf6 }, - { 0x1000773a, 0xf6 }, - { 0x1000773b, 0x0f }, - { 0x1000773c, 0x13 }, - { 0x1000773d, 0x77 }, - { 0x1000773e, 0xf7 }, - { 0x1000773f, 0x0f }, - { 0x10007740, 0x63 }, - { 0x10007741, 0xe8 }, - { 0x10007742, 0xe6 }, - { 0x10007743, 0x02 }, - { 0x10007744, 0xb7 }, - { 0x10007745, 0xd6 }, - { 0x10007746, 0x00 }, - { 0x10007747, 0x00 }, - { 0x10007748, 0x03 }, - { 0x10007749, 0xc7 }, - { 0x1000774a, 0xa6 }, - { 0x1000774b, 0xe1 }, - { 0x1000774c, 0x13 }, - { 0x1000774d, 0x67 }, - { 0x1000774e, 0x07 }, - { 0x1000774f, 0xf8 }, - { 0x10007750, 0x13 }, - { 0x10007751, 0x77 }, - { 0x10007752, 0xf7 }, - { 0x10007753, 0x0f }, - { 0x10007754, 0x23 }, - { 0x10007755, 0x8d }, - { 0x10007756, 0xe6 }, - { 0x10007757, 0xe0 }, - { 0x10007758, 0x03 }, - { 0x10007759, 0xc7 }, - { 0x1000775a, 0x37 }, - { 0x1000775b, 0xd9 }, - { 0x1000775c, 0x13 }, - { 0x1000775d, 0x07 }, - { 0x1000775e, 0x17 }, - { 0x1000775f, 0x00 }, - { 0x10007760, 0x13 }, - { 0x10007761, 0x77 }, - { 0x10007762, 0xf7 }, - { 0x10007763, 0x0f }, - { 0x10007764, 0xa3 }, - { 0x10007765, 0x89 }, - { 0x10007766, 0xe7 }, - { 0x10007767, 0xd8 }, - { 0x10007768, 0x13 }, - { 0x10007769, 0x07 }, - { 0x1000776a, 0x20 }, - { 0x1000776b, 0x00 }, - { 0x1000776c, 0x23 }, - { 0x1000776d, 0x88 }, - { 0x1000776e, 0xe7 }, - { 0x1000776f, 0xd8 }, - { 0x10007770, 0x83 }, - { 0x10007771, 0x20 }, - { 0x10007772, 0xc1 }, - { 0x10007773, 0x00 }, - { 0x10007774, 0x03 }, - { 0x10007775, 0x24 }, - { 0x10007776, 0x81 }, - { 0x10007777, 0x00 }, - { 0x10007778, 0x13 }, - { 0x10007779, 0x01 }, - { 0x1000777a, 0x01 }, - { 0x1000777b, 0x01 }, - { 0x1000777c, 0x67 }, - { 0x1000777d, 0x80 }, - { 0x1000777e, 0x00 }, - { 0x1000777f, 0x00 }, - { 0x10007780, 0x03 }, - { 0x10007781, 0xc7 }, - { 0x10007782, 0xa1 }, - { 0x10007783, 0x40 }, - { 0x10007784, 0x93 }, - { 0x10007785, 0x06 }, - { 0x10007786, 0x10 }, - { 0x10007787, 0x00 }, - { 0x10007788, 0x63 }, - { 0x10007789, 0x16 }, - { 0x1000778a, 0xd7 }, - { 0x1000778b, 0x00 }, - { 0x1000778c, 0xb7 }, - { 0x1000778d, 0xd6 }, - { 0x1000778e, 0x00 }, - { 0x1000778f, 0x10 }, - { 0x10007790, 0xa3 }, - { 0x10007791, 0x8a }, - { 0x10007792, 0xe6 }, - { 0x10007793, 0xd8 }, - { 0x10007794, 0x83 }, - { 0x10007795, 0xc7 }, - { 0x10007796, 0xa1 }, - { 0x10007797, 0x40 }, - { 0x10007798, 0x63 }, - { 0x10007799, 0x9c }, - { 0x1000779a, 0x07 }, - { 0x1000779b, 0x06 }, - { 0x1000779c, 0x13 }, - { 0x1000779d, 0x01 }, - { 0x1000779e, 0x01 }, - { 0x1000779f, 0xff }, - { 0x100077a0, 0x23 }, - { 0x100077a1, 0x22 }, - { 0x100077a2, 0x91 }, - { 0x100077a3, 0x00 }, - { 0x100077a4, 0x23 }, - { 0x100077a5, 0x26 }, - { 0x100077a6, 0x11 }, - { 0x100077a7, 0x00 }, - { 0x100077a8, 0x23 }, - { 0x100077a9, 0x24 }, - { 0x100077aa, 0x81 }, - { 0x100077ab, 0x00 }, - { 0x100077ac, 0xb7 }, - { 0x100077ad, 0xc4 }, - { 0x100077ae, 0x00 }, - { 0x100077af, 0x00 }, - { 0x100077b0, 0x83 }, - { 0x100077b1, 0xc7 }, - { 0x100077b2, 0x04 }, - { 0x100077b3, 0x56 }, - { 0x100077b4, 0x13 }, - { 0x100077b5, 0x07 }, - { 0x100077b6, 0x80 }, - { 0x100077b7, 0x01 }, - { 0x100077b8, 0x93 }, - { 0x100077b9, 0xf7 }, - { 0x100077ba, 0xf7 }, - { 0x100077bb, 0x0f }, - { 0x100077bc, 0x63 }, - { 0x100077bd, 0x70 }, - { 0x100077be, 0xf7 }, - { 0x100077bf, 0x04 }, - { 0x100077c0, 0x37 }, - { 0x100077c1, 0xd4 }, - { 0x100077c2, 0x00 }, - { 0x100077c3, 0x10 }, - { 0x100077c4, 0x83 }, - { 0x100077c5, 0x47 }, - { 0x100077c6, 0x54 }, - { 0x100077c7, 0xd9 }, - { 0x100077c8, 0x93 }, - { 0x100077c9, 0xf7 }, - { 0x100077ca, 0xf7 }, - { 0x100077cb, 0x0f }, - { 0x100077cc, 0x63 }, - { 0x100077cd, 0x88 }, - { 0x100077ce, 0x07 }, - { 0x100077cf, 0x02 }, - { 0x100077d0, 0x93 }, - { 0x100077d1, 0x07 }, - { 0x100077d2, 0x10 }, - { 0x100077d3, 0x00 }, - { 0x100077d4, 0x23 }, - { 0x100077d5, 0x82 }, - { 0x100077d6, 0xf4 }, - { 0x100077d7, 0x58 }, - { 0x100077d8, 0x03 }, - { 0x100077d9, 0x45 }, - { 0x100077da, 0x64 }, - { 0x100077db, 0xd9 }, - { 0x100077dc, 0xb7 }, - { 0x100077dd, 0x15 }, - { 0x100077de, 0x00 }, - { 0x100077df, 0x00 }, - { 0x100077e0, 0x93 }, - { 0x100077e1, 0x85 }, - { 0x100077e2, 0x85 }, - { 0x100077e3, 0x38 }, - { 0x100077e4, 0x13 }, - { 0x100077e5, 0x75 }, - { 0x100077e6, 0xf5 }, - { 0x100077e7, 0x0f }, - { 0x100077e8, 0xef }, - { 0x100077e9, 0xe0 }, - { 0x100077ea, 0x9f }, - { 0x100077eb, 0xd0 }, - { 0x100077ec, 0x93 }, - { 0x100077ed, 0x55 }, - { 0x100077ee, 0xf5 }, - { 0x100077ef, 0x41 }, - { 0x100077f0, 0xef }, - { 0x100077f1, 0xe0 }, - { 0x100077f2, 0x8f }, - { 0x100077f3, 0xa3 }, - { 0x100077f4, 0x23 }, - { 0x100077f5, 0x82 }, - { 0x100077f6, 0x04 }, - { 0x100077f7, 0x58 }, - { 0x100077f8, 0xa3 }, - { 0x100077f9, 0x0a }, - { 0x100077fa, 0x04 }, - { 0x100077fb, 0xd8 }, - { 0x100077fc, 0x83 }, - { 0x100077fd, 0x20 }, - { 0x100077fe, 0xc1 }, - { 0x100077ff, 0x00 }, - { 0x10007800, 0x03 }, - { 0x10007801, 0x24 }, - { 0x10007802, 0x81 }, - { 0x10007803, 0x00 }, - { 0x10007804, 0x83 }, - { 0x10007805, 0x24 }, - { 0x10007806, 0x41 }, - { 0x10007807, 0x00 }, - { 0x10007808, 0x13 }, - { 0x10007809, 0x01 }, - { 0x1000780a, 0x01 }, - { 0x1000780b, 0x01 }, - { 0x1000780c, 0x67 }, - { 0x1000780d, 0x80 }, - { 0x1000780e, 0x00 }, - { 0x1000780f, 0x00 }, - { 0x10007810, 0x67 }, - { 0x10007811, 0x80 }, - { 0x10007812, 0x00 }, - { 0x10007813, 0x00 }, - { 0x10007814, 0x13 }, - { 0x10007815, 0x01 }, - { 0x10007816, 0x01 }, - { 0x10007817, 0xff }, - { 0x10007818, 0x23 }, - { 0x10007819, 0x26 }, - { 0x1000781a, 0x11 }, - { 0x1000781b, 0x00 }, - { 0x1000781c, 0xef }, - { 0x1000781d, 0xd0 }, - { 0x1000781e, 0x8f }, - { 0x1000781f, 0x86 }, - { 0x10007820, 0x83 }, - { 0x10007821, 0xc7 }, - { 0x10007822, 0x11 }, - { 0x10007823, 0x42 }, - { 0x10007824, 0x63 }, - { 0x10007825, 0x86 }, - { 0x10007826, 0x07 }, - { 0x10007827, 0x00 }, - { 0x10007828, 0x03 }, - { 0x10007829, 0xc7 }, - { 0x1000782a, 0x01 }, - { 0x1000782b, 0x42 }, - { 0x1000782c, 0x63 }, - { 0x1000782d, 0x10 }, - { 0x1000782e, 0x07 }, - { 0x1000782f, 0x02 }, - { 0x10007830, 0x83 }, - { 0x10007831, 0xc6 }, - { 0x10007832, 0x21 }, - { 0x10007833, 0x41 }, - { 0x10007834, 0x13 }, - { 0x10007835, 0x07 }, - { 0x10007836, 0xf0 }, - { 0x10007837, 0x01 }, - { 0x10007838, 0x13 }, - { 0x10007839, 0x05 }, - { 0x1000783a, 0xf0 }, - { 0x1000783b, 0x01 }, - { 0x1000783c, 0x63 }, - { 0x1000783d, 0x98 }, - { 0x1000783e, 0xe6 }, - { 0x1000783f, 0x02 }, - { 0x10007840, 0x63 }, - { 0x10007841, 0x8a }, - { 0x10007842, 0x07 }, - { 0x10007843, 0x02 }, - { 0x10007844, 0x83 }, - { 0x10007845, 0xc7 }, - { 0x10007846, 0x01 }, - { 0x10007847, 0x42 }, - { 0x10007848, 0x63 }, - { 0x10007849, 0x86 }, - { 0x1000784a, 0x07 }, - { 0x1000784b, 0x02 }, - { 0x1000784c, 0x83 }, - { 0x1000784d, 0xc7 }, - { 0x1000784e, 0x31 }, - { 0x1000784f, 0x42 }, - { 0x10007850, 0x63 }, - { 0x10007851, 0x86 }, - { 0x10007852, 0x07 }, - { 0x10007853, 0x00 }, - { 0x10007854, 0x83 }, - { 0x10007855, 0xc7 }, - { 0x10007856, 0x21 }, - { 0x10007857, 0x42 }, - { 0x10007858, 0x63 }, - { 0x10007859, 0x9e }, - { 0x1000785a, 0x07 }, - { 0x1000785b, 0x00 }, - { 0x1000785c, 0x03 }, - { 0x1000785d, 0xc7 }, - { 0x1000785e, 0x21 }, - { 0x1000785f, 0x41 }, - { 0x10007860, 0x93 }, - { 0x10007861, 0x07 }, - { 0x10007862, 0xb0 }, - { 0x10007863, 0x01 }, - { 0x10007864, 0x63 }, - { 0x10007865, 0x08 }, - { 0x10007866, 0xf7 }, - { 0x10007867, 0x00 }, - { 0x10007868, 0x13 }, - { 0x10007869, 0x05 }, - { 0x1000786a, 0xb0 }, - { 0x1000786b, 0x01 }, - { 0x1000786c, 0xef }, - { 0x1000786d, 0xd0 }, - { 0x1000786e, 0x0f }, - { 0x1000786f, 0xcf }, - { 0x10007870, 0xef }, - { 0x10007871, 0xd0 }, - { 0x10007872, 0x8f }, - { 0x10007873, 0xa4 }, - { 0x10007874, 0x93 }, - { 0x10007875, 0x06 }, - { 0x10007876, 0x10 }, - { 0x10007877, 0x00 }, - { 0x10007878, 0xa3 }, - { 0x10007879, 0x89 }, - { 0x1000787a, 0xd1 }, - { 0x1000787b, 0x40 }, - { 0x1000787c, 0x37 }, - { 0x1000787d, 0xd7 }, - { 0x1000787e, 0x00 }, - { 0x1000787f, 0x10 }, - { 0x10007880, 0x83 }, - { 0x10007881, 0x47 }, - { 0x10007882, 0x07 }, - { 0x10007883, 0xd9 }, - { 0x10007884, 0x93 }, - { 0x10007885, 0xf7 }, - { 0x10007886, 0xf7 }, - { 0x10007887, 0x0f }, - { 0x10007888, 0x63 }, - { 0x10007889, 0x90 }, - { 0x1000788a, 0x07 }, - { 0x1000788b, 0x02 }, - { 0x1000788c, 0x37 }, - { 0x1000788d, 0xc6 }, - { 0x1000788e, 0x00 }, - { 0x1000788f, 0x00 }, - { 0x10007890, 0x83 }, - { 0x10007891, 0x47 }, - { 0x10007892, 0x26 }, - { 0x10007893, 0x04 }, - { 0x10007894, 0x93 }, - { 0x10007895, 0xe7 }, - { 0x10007896, 0x07 }, - { 0x10007897, 0xf8 }, - { 0x10007898, 0x93 }, - { 0x10007899, 0xf7 }, - { 0x1000789a, 0xf7 }, - { 0x1000789b, 0x0f }, - { 0x1000789c, 0x23 }, - { 0x1000789d, 0x01 }, - { 0x1000789e, 0xf6 }, - { 0x1000789f, 0x04 }, - { 0x100078a0, 0x23 }, - { 0x100078a1, 0x08 }, - { 0x100078a2, 0xd7 }, - { 0x100078a3, 0xd8 }, - { 0x100078a4, 0x23 }, - { 0x100078a5, 0x09 }, - { 0x100078a6, 0x07 }, - { 0x100078a7, 0xd8 }, - { 0x100078a8, 0x83 }, - { 0x100078a9, 0x20 }, - { 0x100078aa, 0xc1 }, - { 0x100078ab, 0x00 }, - { 0x100078ac, 0x13 }, - { 0x100078ad, 0x01 }, - { 0x100078ae, 0x01 }, - { 0x100078af, 0x01 }, - { 0x100078b0, 0x67 }, - { 0x100078b1, 0x80 }, - { 0x100078b2, 0x00 }, - { 0x100078b3, 0x00 }, - { 0x3fc2bfc7, 0x00 }, - { 0x3fc2bfc6, 0x00 }, - { 0x3fc2bfc5, 0x00 }, - { 0x3fc2bfc4, 0x01 }, - { 0x0000d486, 0x43 }, - { 0x1000db00, 0x02 }, - { 0x1000db01, 0x00 }, - { 0x1000db02, 0x11 }, - { 0x1000db03, 0x00 }, - { 0x1000db04, 0x00 }, - { 0x1000db05, 0x82 }, - { 0x1000db06, 0x04 }, - { 0x1000db07, 0xf1 }, - { 0x1000db08, 0x00 }, - { 0x1000db09, 0x00 }, - { 0x1000db0a, 0x40 }, - { 0x0000d540, 0x01 }, -}; - static const struct reg_default rt1320_reg_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 }, { 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_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 }, }; static const struct reg_default rt1320_mbq_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, }; @@ -3514,6 +328,17 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case 0x1000f021: case 0x3fe2e000 ... 0x3fe2e003: case 0x3fc2ab80 ... 0x3fc2abd4: + /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02): + /* 0x40880900/0x40880980 */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + /* 0x40881500 */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): /* 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): @@ -3596,6 +421,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0x3fc2bf80 ... 0x3fc2bf83: case 0x3fc2bfc0 ... 0x3fc2bfc7: case 0x3fe2e000 ... 0x3fe2e003: + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): 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): @@ -3609,6 +435,10 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg) { switch (reg) { + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02): return true; @@ -3664,7 +494,7 @@ static int rt1320_read_prop(struct sdw_slave *slave) prop->lane_control_support = true; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = BIT(4); + prop->source_ports = BIT(4) | BIT(8) | BIT(10); prop->sink_ports = BIT(1); nval = hweight32(prop->source_ports); @@ -3708,7 +538,8 @@ 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) +static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func, + unsigned char entity, unsigned char ps) { unsigned int delay = 1000, val; @@ -3717,8 +548,7 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned /* 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); + SDW_SDCA_CTL(func, entity, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val); if (val == ps) break; @@ -3733,17 +563,88 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned return 0; } +/* + * The 'patch code' is written to the patch code area. + * The patch code area is used for SDCA register expansion flexibility. + */ +static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) +{ + struct sdw_slave *slave = rt1320->sdw_slave; + const struct firmware *patch; + const char *filename; + unsigned int addr, val; + const unsigned char *ptr; + int ret, i; + + if (rt1320->version_id <= RT1320_VB) + filename = RT1320_VAB_MCU_PATCH; + else + filename = RT1320_VC_MCU_PATCH; + + /* load the patch code here */ + ret = request_firmware(&patch, filename, &slave->dev); + if (ret) { + dev_err(&slave->dev, "%s: Failed to load %s firmware", __func__, filename); + regmap_write(rt1320->regmap, 0xc598, 0x00); + regmap_write(rt1320->regmap, 0x10007000, 0x67); + regmap_write(rt1320->regmap, 0x10007001, 0x80); + regmap_write(rt1320->regmap, 0x10007002, 0x00); + regmap_write(rt1320->regmap, 0x10007003, 0x00); + } else { + ptr = (const unsigned char *)patch->data; + if ((patch->size % 8) == 0) { + for (i = 0; i < patch->size; i += 8) { + addr = (ptr[i] & 0xff) | (ptr[i + 1] & 0xff) << 8 | + (ptr[i + 2] & 0xff) << 16 | (ptr[i + 3] & 0xff) << 24; + val = (ptr[i + 4] & 0xff) | (ptr[i + 5] & 0xff) << 8 | + (ptr[i + 6] & 0xff) << 16 | (ptr[i + 7] & 0xff) << 24; + + if (addr > 0x10007fff || addr < 0x10007000) { + dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr); + goto _exit_; + } + if (val > 0xff) { + dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val); + goto _exit_; + } + regmap_write(rt1320->regmap, addr, val); + } + } +_exit_: + release_firmware(patch); + } +} + +static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) +{ + unsigned int i, reg, val, delay; + + for (i = 0; i < ARRAY_SIZE(rt1320_blind_write); i++) { + reg = rt1320_blind_write[i].reg; + val = rt1320_blind_write[i].def; + delay = rt1320_blind_write[i].delay_us; + + if (reg == 0x3fc2bfc7) + rt1320_load_mcu_patch(rt1320); + + regmap_write(rt1320->regmap, reg, val); + if (delay) + usleep_range(delay, delay + 1000); + } +} + 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_blind_write); i++) { + reg = rt1320_vc_blind_write[i].reg; + val = rt1320_vc_blind_write[i].def; + delay = rt1320_vc_blind_write[i].delay_us; - 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 == 0x3fc2bf83) + rt1320_load_mcu_patch(rt1320); if ((reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) && (val == 0x00)) { @@ -3762,6 +663,9 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) regmap_write(rt1320->regmap, reg, val); if (delay) usleep_range(delay, delay + 1000); + + if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val); } } @@ -3799,13 +703,10 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) /* initialization 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) { + if (rt1320->version_id < RT1320_VC) + rt1320_vab_preset(rt1320); + else rt1320_vc_preset(rt1320); - } regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), @@ -3870,6 +771,34 @@ static int rt1320_update_status(struct sdw_slave *slave, return rt1320_io_init(&slave->dev, slave); } +static int rt1320_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps3); + break; + default: + break; + } + + return 0; +} + static int rt1320_pde23_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -3883,13 +812,13 @@ static int rt1320_pde23_event(struct snd_soc_dapm_widget *w, regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0); - rt1320_pde_transition_delay(rt1320, ps0); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 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_pde_transition_delay(rt1320, ps3); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps3); break; default: break; @@ -3908,6 +837,13 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, unsigned int gain_l_val, gain_r_val; unsigned int lvalue, rvalue; const unsigned int interval_offset = 0xc0; + unsigned int changed = 0, reg_base; + struct rt_sdca_dmic_kctrl_priv *p; + unsigned int regvalue[4], gain_val[4], i; + int err; + + if (strstr(ucontrol->id.name, "FU Capture Volume")) + goto _dmic_vol_; regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue); regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue); @@ -3933,7 +869,48 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val); /* Rch */ regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val); + goto _done_; + +_dmic_vol_: + p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value[i]); + } + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]); + } + + if (err < 0) + dev_err(&rt1320->sdw_slave->dev, "0x%08x can't be set\n", reg_base + i); + } + +_done_: return 1; } @@ -3946,6 +923,11 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; const unsigned int interval_offset = 0xc0; + unsigned int reg_base, regvalue, ctl, i; + struct rt_sdca_dmic_kctrl_priv *p; + + if (strstr(ucontrol->id.name, "FU Capture Volume")) + goto _dmic_vol_; regmap_read(rt1320->mbq_regmap, mc->reg, &read_l); regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r); @@ -3959,6 +941,121 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = ctl_l; ucontrol->value.integer.value[1] = ctl_r; + goto _done_; + +_dmic_vol_: + p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value); + } + + ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); + ucontrol->value.integer.value[i] = ctl; + } +_done_: + return 0; +} + +static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) { + ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00; + + if (i < 2) + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + else + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt1320_dmic_fu_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt1320->fu_mixer_mute[i]; + + return 0; +} + +static int rt1320_dmic_fu_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt1320->fu_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt1320->fu_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt1320_set_fu_capture_ctl(rt1320); + if (err < 0) + return err; + + return changed; +} + +static int rt1320_dmic_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static int rt1320_dmic_fu_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt1320->fu_dapm_mute = false; + rt1320_set_fu_capture_ctl(rt1320); + break; + case SND_SOC_DAPM_PRE_PMD: + rt1320->fu_dapm_mute = true; + rt1320_set_fu_capture_ctl(rt1320); + break; + } return 0; } @@ -3979,6 +1076,7 @@ static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum, rt1320_rx_data_ch_select); static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const struct snd_kcontrol_new rt1320_snd_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume", @@ -3986,6 +1084,13 @@ static const struct snd_kcontrol_new rt1320_snd_controls[] = { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv), SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum), + + RT_SDCA_FU_CTRL("FU Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), + 1, 1, 4, rt1320_dmic_fu_info, rt1320_dmic_fu_capture_get, rt1320_dmic_fu_capture_put), + RT_SDCA_EXT_TLV("FU Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), + rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info), }; static const struct snd_kcontrol_new rt1320_spk_l_dac = @@ -4001,12 +1106,19 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = { /* Audio Interface */ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP8-10TX", "DP8-10 Capture", 0, SND_SOC_NOPM, 0, 0), /* Digital Interface */ SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, rt1320_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt1320_pde11_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC("FU 113", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("FU 14", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA_E("FU", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1320_dmic_fu_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Output */ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac), @@ -4017,6 +1129,8 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = { /* Input */ SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SIGGEN("AEC Gen"), + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), }; static const struct snd_soc_dapm_route rt1320_dapm_routes[] = { @@ -4029,6 +1143,13 @@ static const struct snd_soc_dapm_route rt1320_dapm_routes[] = { { "AEC Data", NULL, "AEC Gen" }, { "DP4TX", NULL, "AEC Data" }, + + {"DP8-10TX", NULL, "FU"}, + {"FU", NULL, "PDE 11"}, + {"FU", NULL, "FU 113"}, + {"FU", NULL, "FU 14"}, + {"FU 113", NULL, "DMIC1"}, + {"FU 14", NULL, "DMIC2"}, }; static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -4052,6 +1173,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, snd_soc_component_get_drvdata(component); struct sdw_stream_config stream_config; struct sdw_port_config port_config; + struct sdw_port_config dmic_port_config[2]; struct sdw_stream_runtime *sdw_stream; int retval; unsigned int sampling_rate; @@ -4076,12 +1198,23 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, } else { if (dai->id == RT1320_AIF1) port_config.num = 4; - else + else if (dai->id == RT1320_AIF2) { + dmic_port_config[0].ch_mask = BIT(0) | BIT(1); + dmic_port_config[0].num = 8; + dmic_port_config[1].ch_mask = BIT(0) | BIT(1); + dmic_port_config[1].num = 10; + } else return -EINVAL; } - retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + if (dai->id == RT1320_AIF1) + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, &port_config, 1, sdw_stream); + else if (dai->id == RT1320_AIF2) + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + dmic_port_config, 2, sdw_stream); + else + return -EINVAL; if (retval) { dev_err(dai->dev, "%s: Unable to configure port\n", __func__); return retval; @@ -4114,9 +1247,18 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, } /* set sampling frequency */ - regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), - sampling_rate); + if (dai->id == RT1320_AIF1) + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + else { + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + } return 0; } @@ -4207,6 +1349,19 @@ static struct snd_soc_dai_driver rt1320_sdw_dai[] = { }, .ops = &rt1320_aif_dai_ops, }, + /* DMIC: DP8 2ch + DP10 2ch */ + { + .name = "rt1320-aif2", + .id = RT1320_AIF2, + .capture = { + .stream_name = "DP8-10 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT1320_STEREO_RATES, + .formats = RT1320_FORMATS, + }, + .ops = &rt1320_aif_dai_ops, + }, }; static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, @@ -4234,6 +1389,9 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, rt1320->hw_init = false; rt1320->first_hw_init = false; rt1320->version_id = -1; + rt1320->fu_dapm_mute = true; + rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] = + rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true; ret = devm_snd_soc_register_component(dev, &soc_component_sdw_rt1320, diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index 1fbc1fcd71cf..23b321aee6a9 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -26,6 +26,7 @@ /* RT1320 SDCA Control - function number */ #define FUNC_NUM_AMP 0x04 +#define FUNC_NUM_MIC 0x02 /* RT1320 SDCA entity */ #define RT1320_SDCA_ENT0 0x00 @@ -69,6 +70,7 @@ enum { RT1320_AIF1, + RT1320_AIF2, }; /* @@ -82,6 +84,8 @@ enum rt1320_version_id { }; #define RT1320_VER_B_ID 0x07392238 +#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" +#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" struct rt1320_sdw_priv { struct snd_soc_component *component; @@ -92,6 +96,8 @@ struct rt1320_sdw_priv { bool hw_init; bool first_hw_init; int version_id; + bool fu_dapm_mute; + bool fu_mixer_mute[4]; }; #endif /* __RT1320_SDW_H__ */ diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 90d5aaddbd5b..549aa31faed4 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -507,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver); MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver"); MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_SDCA); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index e210c574bb74..78dbf9eed494 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -18,6 +18,7 @@ #include <linux/pm_runtime.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/sdca.h> #include <linux/soundwire/sdw_registers.h> #include <linux/slab.h> #include <sound/soc-dapm.h> @@ -1652,6 +1653,17 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, if (ret < 0) return ret; + /* only add the dmic component if a SMART_MIC function is exposed in ACPI */ + if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) { + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt712_dmic, + rt712_sdca_dmic_dai, + ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; + rt712->dmic_function_found = true; + } + /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); @@ -1799,7 +1811,6 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) { struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); - int ret = 0; unsigned int val; struct sdw_slave_prop *prop = &slave->prop; @@ -1829,15 +1840,22 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt712->version_id = (val & 0x0f00) >> 8; dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id); - if (rt712->version_id == RT712_VA) + if (rt712->version_id == RT712_VA) { + if (rt712->dmic_function_found) { + dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n", + __func__); + goto suspend; + } + rt712_sdca_va_io_init(rt712); - else { - /* multilanes and DMIC are supported by rt712vb */ - ret = devm_snd_soc_register_component(dev, - &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); - if (ret < 0) - return ret; + } else { + if (!rt712->dmic_function_found) { + dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n", + __func__); + goto suspend; + } + /* multilanes and DMIC are supported by rt712vb */ prop->lane_control_support = true; rt712_sdca_vb_io_init(rt712); } @@ -1862,10 +1880,12 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt712->hw_init = true; + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + +suspend: pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); - dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); return 0; } diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index 2169f2f726b9..a08491496d90 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -36,6 +36,7 @@ struct rt712_sdca_priv { unsigned int scp_sdca_stat2; unsigned int hw_id; unsigned int version_id; + bool dmic_function_found; bool fu0f_dapm_mute; bool fu0f_mixer_l_mute; bool fu0f_mixer_r_mute; diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c new file mode 100644 index 000000000000..c71453da088a --- /dev/null +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt721-sdca-sdw.c -- rt721 SDCA ALSA SoC audio driver +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/pm_runtime.h> +#include <linux/soundwire/sdw_registers.h> + +#include "rt721-sdca.h" +#include "rt721-sdca-sdw.h" +#include "rt-sdw-common.h" + +static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01 ... 0x2f0a: + case 0x2f35: + case 0x2f50: + case 0x2f51: + case 0x2f58 ... 0x2f5d: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV, + RT721_SDCA_CTL_XUV, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_SELECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, + RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01: + case 0x2f51: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV, + RT721_SDCA_CTL_XUV, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, + RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0900007: + case 0x0a00005: + case 0x0c00005: + case 0x0d00014: + case 0x0310100: + case 0x2000001: + case 0x2000002: + case 0x2000003: + case 0x2000013: + case 0x200003c: + case 0x2000046: + case 0x5810000: + case 0x5810036: + case 0x5810037: + case 0x5810038: + case 0x5810039: + case 0x5b10018: + case 0x5b10019: + case 0x5f00045: + case 0x5f00048: + case 0x6100000: + case 0x6100005: + case 0x6100006: + case 0x610000d: + case 0x6100010: + case 0x6100011: + case 0x6100013: + case 0x6100015: + case 0x6100017: + case 0x6100025: + case 0x6100029: + case 0x610002c ... 0x610002f: + case 0x6100053 ... 0x6100055: + case 0x6100057: + case 0x610005a: + case 0x610005b: + case 0x610006a: + case 0x610006d: + case 0x6100092: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_04): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R): + return true; + default: + return false; + } +} + +static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0310100: + case 0x0a00005: + case 0x0c00005: + case 0x0d00014: + case 0x2000000: + case 0x200000d: + case 0x2000019: + case 0x2000020: + case 0x2000030: + case 0x2000046: + case 0x2000067: + case 0x2000084: + case 0x2000086: + case 0x5810000: + case 0x5810036: + case 0x5810037: + case 0x5810038: + case 0x5810039: + case 0x5b10018: + case 0x5b10019: + return true; + default: + return false; + } +} + +static const struct regmap_config rt721_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt721_sdca_readable_register, + .volatile_reg = rt721_sdca_volatile_register, + .max_register = 0x44ffffff, + .reg_defaults = rt721_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt721_sdca_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt721_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt721_sdca_mbq_readable_register, + .volatile_reg = rt721_sdca_mbq_volatile_register, + .max_register = 0x41000312, + .reg_defaults = rt721_sdca_mbq_defaults, + .num_reg_defaults = ARRAY_SIZE(rt721_sdca_mbq_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt721_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt721->hw_init = false; + + if (status == SDW_SLAVE_ATTACHED) { + if (rt721->hs_jack) { + /* + * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then + * if the device attached again, we will need to set the setting back. + * It could avoid losing the jack detection interrupt. + * This also could sync with the cache value as the rt721_sdca_jack_init set. + */ + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + } + } + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt721->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt721_sdca_io_init(&slave->dev, slave); +} + +static int rt721_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + sdw_slave_read_prop(slave); + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* + * port = 1 for headphone playback + * port = 2 for headset-mic capture + * port = 3 for speaker playback + * port = 6 for digital-mic capture + */ + prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */ + prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 1380; + + /* wake-up event */ + prop->wake_capable = 1; + + /* Three data lanes are supported by rt721-sdca codec */ + prop->lane_control_support = true; + + return 0; +} + +static int rt721_sdca_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + int ret, stat; + int count = 0, retry = 3; + unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; + + if (cancel_delayed_work_sync(&rt721->jack_detect_work)) { + dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__); + /* avoid the HID owner doesn't change to device */ + if (rt721->scp_sdca_stat2) + scp_sdca_stat2 = rt721->scp_sdca_stat2; + } + + /* + * The critical section below intentionally protects a rather large piece of code. + * We don't want to allow the system suspend to disable an interrupt while we are + * processing it, which could be problematic given the quirky SoundWire interrupt + * scheme. We do want however to prevent new workqueues from being scheduled if + * the disable_irq flag was set during system suspend. + */ + mutex_lock(&rt721->disable_irq_lock); + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + + rt721->scp_sdca_stat1 = ret; + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + + rt721->scp_sdca_stat2 = ret; + if (scp_sdca_stat2) + rt721->scp_sdca_stat2 |= scp_sdca_stat2; + do { + /* clear flag */ + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { + ret = sdw_update_no_pm(rt721->slave, SDW_SCP_SDCA_INT1, + SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); + if (ret < 0) + goto io_error; + } + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { + ret = sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INT2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + if (ret < 0) + goto io_error; + } + + /* check if flag clear or not */ + ret = sdw_read_no_pm(rt721->slave, SDW_DP0_INT); + if (ret < 0) + goto io_error; + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; + + stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; + + count++; + } while (stat != 0 && count < retry); + + if (stat) + dev_warn(&slave->dev, + "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt721->scp_sdca_stat1, rt721->scp_sdca_stat2); + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + + if (status->sdca_cascade && !rt721->disable_irq) + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_detect_work, msecs_to_jiffies(280)); + + mutex_unlock(&rt721->disable_irq_lock); + + return 0; + +io_error: + mutex_unlock(&rt721->disable_irq_lock); + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static const struct sdw_slave_ops rt721_sdca_slave_ops = { + .read_prop = rt721_sdca_read_prop, + .interrupt_callback = rt721_sdca_interrupt_callback, + .update_status = rt721_sdca_update_status, +}; + +static int rt721_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap, *mbq_regmap; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt721_sdca_mbq_regmap); + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); + + regmap = devm_regmap_init_sdw(slave, &rt721_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt721_sdca_init(&slave->dev, regmap, mbq_regmap, slave); +} + +static int rt721_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + + if (rt721->hw_init) { + cancel_delayed_work_sync(&rt721->jack_detect_work); + cancel_delayed_work_sync(&rt721->jack_btn_check_work); + } + + if (rt721->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt721->calibrate_mutex); + mutex_destroy(&rt721->disable_irq_lock); + + return 0; +} + +static const struct sdw_device_id rt721_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x721, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt721_sdca_id); + +static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + + if (!rt721->hw_init) + return 0; + + cancel_delayed_work_sync(&rt721->jack_detect_work); + cancel_delayed_work_sync(&rt721->jack_btn_check_work); + + regcache_cache_only(rt721->regmap, true); + regcache_cache_only(rt721->mbq_regmap, true); + + return 0; +} + +static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev) +{ + struct rt721_sdca_priv *rt721_sdca = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret1, ret2; + + if (!rt721_sdca->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt721_sdca->disable_irq_lock); + rt721_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + mutex_unlock(&rt721_sdca->disable_irq_lock); + + if (ret1 < 0 || ret2 < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); + } + + return rt721_sdca_dev_suspend(dev); +} + +#define RT721_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt721_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt721->first_hw_init) + return 0; + + if (!slave->unattach_request) { + mutex_lock(&rt721->disable_irq_lock); + if (rt721->disable_irq == true) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + rt721->disable_irq = false; + } + mutex_unlock(&rt721->disable_irq_lock); + goto regmap_sync; + } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT721_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt721->regmap, false); + regcache_sync(rt721->regmap); + regcache_cache_only(rt721->mbq_regmap, false); + regcache_sync(rt721->mbq_regmap); + return 0; +} + +static const struct dev_pm_ops rt721_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt721_sdca_sdw_driver = { + .driver = { + .name = "rt721-sdca", + .owner = THIS_MODULE, + .pm = &rt721_sdca_pm, + }, + .probe = rt721_sdca_sdw_probe, + .remove = rt721_sdca_sdw_remove, + .ops = &rt721_sdca_slave_ops, + .id_table = rt721_sdca_id, +}; +module_sdw_driver(rt721_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h new file mode 100644 index 000000000000..214b31b82583 --- /dev/null +++ b/sound/soc/codecs/rt721-sdca-sdw.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt721-sdca-sdw.h -- RT721 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef __RT721_SDW_H__ +#define __RT721_SDW_H__ + +#include <linux/regmap.h> +#include <linux/soundwire/sdw_registers.h> + +static const struct reg_default rt721_sdca_reg_defaults[] = { + { 0x202d, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x08 }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0e }, + { 0x2f06, 0x01 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f35, 0x00 }, + { 0x2f50, 0xf0 }, + { 0x2f58, 0x07 }, + { 0x2f59, 0x07 }, + { 0x2f5a, 0x00 }, + { 0x2f5b, 0x07 }, + { 0x2f5c, 0x27 }, + { 0x2f5d, 0x07 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, +}; + +static const struct reg_default rt721_sdca_mbq_defaults[] = { + { 0x0900007, 0xc004 }, + { 0x2000001, 0x0000 }, + { 0x2000002, 0x0000 }, + { 0x2000003, 0x0000 }, + { 0x2000013, 0x8001 }, + { 0x200003c, 0x0000 }, + { 0x2000046, 0x3400 }, + { 0x5f00044, 0x6040 }, + { 0x5f00045, 0x3333 }, + { 0x5f00048, 0x0000 }, + { 0x6100005, 0x0005 }, + { 0x6100006, 0x0000 }, + { 0x610000d, 0x0051 }, + { 0x6100010, 0x0180 }, + { 0x6100011, 0x0000 }, + { 0x6100013, 0x0000 }, + { 0x6100015, 0x0000 }, + { 0x6100017, 0x8049 }, + { 0x6100025, 0x1000 }, + { 0x6100029, 0x0809 }, + { 0x610002c, 0x2828 }, + { 0x610002d, 0x2929 }, + { 0x610002e, 0x3529 }, + { 0x610002f, 0x2901 }, + { 0x6100053, 0x2630 }, + { 0x6100054, 0x2a2a }, + { 0x6100055, 0x152f }, + { 0x6100057, 0x2200 }, + { 0x610005a, 0x2a4b }, + { 0x610005b, 0x2a00 }, + { 0x610006a, 0x0102 }, + { 0x610006d, 0x0102 }, + { 0x6100092, 0x4f61 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN, + CH_L), 0xfe00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN, + CH_R), 0xfe00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_01), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_02), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_03), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_04), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R), + 0x0000 }, +}; + +#endif /* __RT721_SDW_H__ */ diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c new file mode 100644 index 000000000000..1c9f32e405cf --- /dev/null +++ b/sound/soc/codecs/rt721-sdca.c @@ -0,0 +1,1545 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt721-sdca.c -- rt721 SDCA ALSA SoC audio driver +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include <linux/bitops.h> +#include <sound/core.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <sound/initval.h> +#include <sound/jack.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <sound/pcm.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/slab.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +#include "rt721-sdca.h" +#include "rt-sdw-common.h" + +static void rt721_sdca_jack_detect_handler(struct work_struct *work) +{ + struct rt721_sdca_priv *rt721 = + container_of(work, struct rt721_sdca_priv, jack_detect_work.work); + int btn_type = 0; + + if (!rt721->hs_jack) + return; + + if (!rt721->component->card || !rt721->component->card->instantiated) + return; + + /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ + if (rt721->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + rt721->jack_type = rt_sdca_headset_detect(rt721->regmap, + RT721_SDCA_ENT_GE49); + if (rt721->jack_type < 0) + return; + } + + /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */ + if (rt721->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8) + btn_type = rt_sdca_button_detect(rt721->regmap, + RT721_SDCA_ENT_HID01, RT721_BUF_ADDR_HID1, + RT721_SDCA_HID_ID); + + if (rt721->jack_type == 0) + btn_type = 0; + + dev_dbg(&rt721->slave->dev, + "in %s, jack_type=%d\n", __func__, rt721->jack_type); + dev_dbg(&rt721->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + dev_dbg(&rt721->slave->dev, + "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt721->scp_sdca_stat1, rt721->scp_sdca_stat2); + + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_btn_check_work, msecs_to_jiffies(200)); + } +} + +static void rt721_sdca_btn_check_handler(struct work_struct *work) +{ + struct rt721_sdca_priv *rt721 = + container_of(work, struct rt721_sdca_priv, jack_btn_check_work.work); + int btn_type = 0, ret, idx; + unsigned int det_mode, offset, val; + unsigned char buf[3]; + + ret = regmap_read(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (det_mode) { + /* read UMP message offset */ + ret = regmap_read(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto io_error; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt721->regmap, + RT721_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto io_error; + buf[idx] = val & 0xff; + } + /* Report ID for HID1 */ + if (buf[0] == 0x11) + btn_type = rt_sdca_btn_type(&buf[1]); + } else + rt721->jack_type = 0; + + dev_dbg(&rt721->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt721_sdca_dmic_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL9, 0x2a2a); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL10, 0x2a00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL6, 0x2a2a); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL5, 0x2626); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL8, 0x1e00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL7, 0x1515); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL3, 0x0304); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL4, 0x0304); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_CTL1, 0x0000); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01); + regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b40); + regmap_write(rt721->regmap, 0x2f5c, 0x25); +} + +static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421); + regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL6, 0x5561); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG, + RT721_GPIO_PAD_CTRL5, 0x8003); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00); +} + +static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_GE_REL_CTRL1, 0x8011); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL3, 0xcf00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL4, 0x000f); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL1, 0x1100); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL5, 0x0c12); + rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL, + RT721_JD_1PIN_GAT_CTRL2, 0xc002); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b40); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3333); + regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036); + regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL1, 0x0140); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL18, 0x5522); + regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000); + regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL, + RT721_CBJ_A0_GAT_CTRL1, 0x2a02); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL4, 0xa105); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3b33); + regmap_write(rt721->mbq_regmap, 0x310400, 0x3023); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3f33); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON13, 0x6048); + regmap_write(rt721->mbq_regmap, 0x310401, 0x3000); + regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00); + regmap_write(rt721->mbq_regmap, 0x310300, 0x000f); + regmap_write(rt721->mbq_regmap, 0x310301, 0x3000); + regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON17, 0x0008); + rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL, + RT721_DAC_2CH_CTRL3, 0x55ff); + rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL, + RT721_DAC_2CH_CTRL4, 0xcc00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_MBIAS_LV_CTRL2, 0x6677); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF2_LV_CTRL1, 0x7600); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL2, 0x1234); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL3, 0x3512); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL1, 0x4040); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL4, 0x1201); + regmap_write(rt721->regmap, 0x2f58, 0x07); +} + +static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) +{ + mutex_lock(&rt721->calibrate_mutex); + if (rt721->hs_jack) { + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + dev_dbg(&rt721->slave->dev, "in %s enable\n", __func__); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_UAJ_CTL, 0x036E); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU03, + RT721_SDCA_CTL_SELECTED_MODE, 0), 0); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU0D, + RT721_SDCA_CTL_SELECTED_MODE, 0), 0); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_XU_REL_CTRL, 0x0000); + rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_GE_REL_CTRL1, 0x4000, 0x4000); + } + mutex_unlock(&rt721->calibrate_mutex); +} + +static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int ret; + + rt721->hs_jack = hs_jack; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); + return 0; + } + + rt721_sdca_jack_init(rt721); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + + return 0; +} + +/* For SDCA control DAC/ADC Gain */ +static int rt721_sdca_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int adc_vol_flag = 0, changed = 0; + unsigned int lvalue, rvalue; + const unsigned int interval_offset = 0xc0; + const unsigned int tendA = 0x200; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt721->mbq_regmap, mc->reg, &lvalue); + regmap_read(rt721->mbq_regmap, mc->rreg, &rvalue); + + /* L Channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + + if (mc->shift == 8) { + /* boost gain */ + gain_l_val = gain_l_val * tendB; + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (gain_l_val == 0) + gain_l_val = 0x8000; + else + gain_l_val = (gain_l_val - 1) * tendA; + } else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset); + else + gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset); + gain_l_val &= 0xffff; + } + + /* R Channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + + if (mc->shift == 8) { + /* boost gain */ + gain_r_val = gain_r_val * tendB; + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (gain_r_val == 0) + gain_r_val = 0x8000; + else + gain_r_val = (gain_r_val - 1) * tendA; + } else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset); + else + gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset); + gain_r_val &= 0xffff; + } + + if (lvalue != gain_l_val || rvalue != gain_r_val) + changed = 1; + else + return 0; + + /* Lch*/ + regmap_write(rt721->mbq_regmap, mc->reg, gain_l_val); + + /* Rch */ + regmap_write(rt721->mbq_regmap, mc->rreg, gain_r_val); + + regmap_read(rt721->mbq_regmap, mc->reg, &read_l); + regmap_read(rt721->mbq_regmap, mc->rreg, &read_r); + if (read_r == gain_r_val && read_l == gain_l_val) + return changed; + + return -EIO; +} + +static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt721->mbq_regmap, mc->reg, &read_l); + regmap_read(rt721->mbq_regmap, mc->rreg, &read_r); + + if (mc->shift == 8) /* boost gain */ + ctl_l = read_l / tendB; + else { + if (adc_vol_flag) + ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset); + else + ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset); + } + + if (read_l != read_r) { + if (mc->shift == 8) /* boost gain */ + ctl_r = read_r / tendB; + else { /* ADC/DAC gain */ + if (adc_vol_flag) + ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset); + else + ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset); + } + } else { + ctl_r = ctl_l; + } + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + + return 0; +} + +static int rt721_sdca_set_fu1e_capture_ctl(struct rt721_sdca_priv *rt721) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt721->fu1e_mixer_mute); i++) { + ch_mute = rt721->fu1e_dapm_mute || rt721->fu1e_mixer_mute[i]; + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt721_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt721->fu1e_mixer_mute[i]; + + return 0; +} + +static int rt721_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt721->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt721->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt721_sdca_set_fu1e_capture_ctl(rt721); + if (err < 0) + return err; + + return changed; +} + +static int rt721_sdca_set_fu0f_capture_ctl(struct rt721_sdca_priv *rt721) +{ + int err; + unsigned int ch_l, ch_r; + + ch_l = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_r = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_L), ch_l); + if (err < 0) + return err; + + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_R), ch_r); + if (err < 0) + return err; + + return 0; +} + +static int rt721_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt721->fu0f_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt721->fu0f_mixer_r_mute; + return 0; +} + +static int rt721_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int err, changed = 0; + + if (rt721->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] || + rt721->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1]) + changed = 1; + + rt721->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt721->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt721_sdca_set_fu0f_capture_ctl(rt721); + if (err < 0) + return err; + + return changed; +} + +static int rt721_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static int rt721_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int regvalue, ctl, i; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt721->mbq_regmap, p->reg_base + i, ®value); + + if (!adc_vol_flag) /* boost gain */ + ctl = regvalue / boost_step; + else /* ADC gain */ + ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt721_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int gain_val[4]; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int regvalue[4]; + const unsigned int interval_offset = 0xc0; + int err; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt721->mbq_regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + if (!adc_vol_flag) /* boost gain */ + gain_val[i] = gain_val[i] * boost_step; + else { /* ADC gain */ + gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + } + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt721->mbq_regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt721->slave->dev, "%#08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); +static const DECLARE_TLV_DB_SCALE(mic2_boost_vol_tlv, -200, 200, 0); + +static const struct snd_kcontrol_new rt721_sdca_controls[] = { + /* Headphone playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv), + /* Headset mic capture settings */ + SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt721_sdca_fu0f_capture_get, rt721_sdca_fu0f_capture_put), + SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_R), 1, 0x15, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic2_boost_vol_tlv), + /* AMP playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv), + /* DMIC capture settings */ + RT_SDCA_FU_CTRL("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4, rt721_sdca_fu_info, + rt721_sdca_fu1e_capture_get, rt721_sdca_fu1e_capture_put), + RT_SDCA_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_VOLUME, CH_01), + rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put, + 4, 0x3f, mic_vol_tlv, rt721_sdca_fu_info), + RT_SDCA_EXT_TLV("FU15 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, + RT721_SDCA_CTL_FU_CH_GAIN, CH_01), + rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put, + 4, 3, boost_vol_tlv, rt721_sdca_fu_info), +}; + +static int rt721_sdca_adc_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft, mask; + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) { + mask_sft = 12; + mask = 0x7; + } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) { + mask_sft = 10; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) { + mask_sft = 8; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) { + mask_sft = 6; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) { + mask_sft = 4; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) { + mask_sft = 2; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) { + mask_sft = 0; + mask = 0x3; + } else + return -EINVAL; + + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &val); + + ucontrol->value.enumerated.item[0] = (val >> mask_sft) & mask; + + return 0; +} + +static int rt721_sdca_adc_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft, mask; + unsigned int check; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) { + mask_sft = 12; + mask = 0x7; + } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) { + mask_sft = 10; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) { + mask_sft = 8; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) { + mask_sft = 6; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) { + mask_sft = 4; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) { + mask_sft = 2; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) { + mask_sft = 0; + mask = 0x3; + } else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &val2); + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) + val2 = (val2 >> mask_sft) & 0x7; + else + val2 = (val2 >> mask_sft) & 0x3; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) { + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &check); + rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, mask << mask_sft, + val << mask_sft); + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc09_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", +}; +static const char * const adc07_10_mux_text[] = { + "DMIC1 RE", + "DMIC1 FE", + "DMIC2 RE", + "DMIC2 FE", +}; + +static SOC_ENUM_SINGLE_DECL( + rt721_adc09_enum, SND_SOC_NOPM, 0, adc09_mux_text); +static SOC_ENUM_SINGLE_DECL( + rt721_dmic_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); + +static const struct snd_kcontrol_new rt721_sdca_adc09_mux = + SOC_DAPM_ENUM_EXT("ADC 09 Mux", rt721_adc09_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc08_r_mux = + SOC_DAPM_ENUM_EXT("ADC 08 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc08_l_mux = + SOC_DAPM_ENUM_EXT("ADC 08 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc10_r_mux = + SOC_DAPM_ENUM_EXT("ADC 10 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc10_l_mux = + SOC_DAPM_ENUM_EXT("ADC 10 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc07_r_mux = + SOC_DAPM_ENUM_EXT("ADC 07 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc07_l_mux = + SOC_DAPM_ENUM_EXT("ADC 07 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); + + +static int rt721_sdca_fu42_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(100); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu21_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu113_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt721->fu1e_dapm_mute = false; + rt721_sdca_set_fu1e_capture_ctl(rt721); + break; + case SND_SOC_DAPM_PRE_PMD: + rt721->fu1e_dapm_mute = true; + rt721_sdca_set_fu1e_capture_ctl(rt721); + break; + } + return 0; +} + +static int rt721_sdca_fu36_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt721->fu0f_dapm_mute = false; + rt721_sdca_set_fu0f_capture_ctl(rt721); + break; + case SND_SOC_DAPM_PRE_PMD: + rt721->fu0f_dapm_mute = true; + rt721_sdca_set_fu0f_capture_ctl(rt721); + break; + } + return 0; +} + +static int rt721_sdca_pde47_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde41_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde34_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt721_sdca_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + SND_SOC_DAPM_INPUT("DMIC1_2"), + SND_SOC_DAPM_INPUT("DMIC3_4"), + + SND_SOC_DAPM_SUPPLY("PDE 41", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde41_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde47_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde34_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu21_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 23", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu42_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu36_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu113_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 09 Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc09_mux), + SND_SOC_DAPM_MUX("ADC 08 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc08_r_mux), + SND_SOC_DAPM_MUX("ADC 08 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc08_l_mux), + SND_SOC_DAPM_MUX("ADC 10 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc10_r_mux), + SND_SOC_DAPM_MUX("ADC 10 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc10_l_mux), + SND_SOC_DAPM_MUX("ADC 07 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc07_r_mux), + SND_SOC_DAPM_MUX("ADC 07 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc07_l_mux), + + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt721_sdca_audio_map[] = { + {"FU 42", NULL, "DP1RX"}, + {"FU 21", NULL, "DP3RX"}, + {"FU 23", NULL, "DP3RX"}, + + {"ADC 09 Mux", "MIC2", "MIC2"}, + {"ADC 09 Mux", "LINE1", "LINE1"}, + {"ADC 09 Mux", "LINE2", "LINE2"}, + {"ADC 07 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 07 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 07 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 07 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 07 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 07 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 07 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 07 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 08 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 08 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 08 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 08 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 08 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 08 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 08 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 08 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 10 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 10 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 10 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 10 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 10 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 10 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 10 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 10 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"FU 36", NULL, "PDE 34"}, + {"FU 36", NULL, "ADC 09 Mux"}, + {"FU 113", NULL, "PDE 11"}, + {"FU 113", NULL, "ADC 07 R Mux"}, + {"FU 113", NULL, "ADC 07 L Mux"}, + {"FU 113", NULL, "ADC 10 R Mux"}, + {"FU 113", NULL, "ADC 10 L Mux"}, + {"DP2TX", NULL, "FU 36"}, + {"DP6TX", NULL, "FU 113"}, + + {"HP", NULL, "PDE 47"}, + {"HP", NULL, "FU 42"}, + {"SPK", NULL, "PDE 41"}, + {"SPK", NULL, "FU 21"}, + {"SPK", NULL, "FU 23"}, +}; + +static int rt721_sdca_parse_dt(struct rt721_sdca_priv *rt721, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", &rt721->jd_src); + + return 0; +} + +static int rt721_sdca_probe(struct snd_soc_component *component) +{ + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int ret; + + rt721_sdca_parse_dt(rt721, &rt721->slave->dev); + rt721->component = component; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver soc_sdca_dev_rt721 = { + .probe = rt721_sdca_probe, + .controls = rt721_sdca_controls, + .num_controls = ARRAY_SIZE(rt721_sdca_controls), + .dapm_widgets = rt721_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt721_sdca_dapm_widgets), + .dapm_routes = rt721_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt721_sdca_audio_map), + .set_jack = rt721_sdca_set_jack_detect, + .endianness = 1, +}; + +static int rt721_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt721_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + int retval, port, num_channels; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt721->slave) + return -EINVAL; + + /* + * RT721_AIF1 with port = 1 for headphone playback + * RT721_AIF1 with port = 2 for headset-mic capture + * RT721_AIF2 with port = 3 for speaker playback + * RT721_AIF3 with port = 6 for digital-mic capture + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + if (dai->id == RT721_AIF1) + port = 1; + else if (dai->id == RT721_AIF2) + port = 3; + else + return -EINVAL; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT721_AIF1) + port = 2; + else if (dai->id == RT721_AIF3) + port = 6; + else + return -EINVAL; + } + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt721->slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) > 16) { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 8000: + sampling_rate = RT721_SDCA_RATE_8000HZ; + break; + case 16000: + sampling_rate = RT721_SDCA_RATE_16000HZ; + break; + case 24000: + sampling_rate = RT721_SDCA_RATE_24000HZ; + break; + case 32000: + sampling_rate = RT721_SDCA_RATE_32000HZ; + break; + case 44100: + sampling_rate = RT721_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT721_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT721_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT721_SDCA_RATE_192000HZ; + break; + case 384000: + sampling_rate = RT721_SDCA_RATE_384000HZ; + break; + case 768000: + sampling_rate = RT721_SDCA_RATE_768000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + if (dai->id == RT721_AIF1) { + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + } + + if (dai->id == RT721_AIF2) + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + if (dai->id == RT721_AIF3) + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + return 0; +} + +static int rt721_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt721->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt721->slave, sdw_stream); + return 0; +} + +#define RT721_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT721_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops rt721_sdca_ops = { + .hw_params = rt721_sdca_pcm_hw_params, + .hw_free = rt721_sdca_pcm_hw_free, + .set_stream = rt721_sdca_set_sdw_stream, + .shutdown = rt721_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt721_sdca_dai[] = { + { + .name = "rt721-sdca-aif1", + .id = RT721_AIF1, + .playback = { + .stream_name = "DP1 Headphone Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .capture = { + .stream_name = "DP2 Headset Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + }, + { + .name = "rt721-sdca-aif2", + .id = RT721_AIF2, + .playback = { + .stream_name = "DP3 Speaker Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + }, + { + .name = "rt721-sdca-aif3", + .id = RT721_AIF3, + .capture = { + .stream_name = "DP6 DMic Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + } +}; + +int rt721_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721; + + rt721 = devm_kzalloc(dev, sizeof(*rt721), GFP_KERNEL); + if (!rt721) + return -ENOMEM; + + dev_set_drvdata(dev, rt721); + rt721->slave = slave; + rt721->regmap = regmap; + rt721->mbq_regmap = mbq_regmap; + + regcache_cache_only(rt721->regmap, true); + regcache_cache_only(rt721->mbq_regmap, true); + + mutex_init(&rt721->calibrate_mutex); + mutex_init(&rt721->disable_irq_lock); + + INIT_DELAYED_WORK(&rt721->jack_detect_work, rt721_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt721->jack_btn_check_work, rt721_sdca_btn_check_handler); + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt721->hw_init = false; + rt721->first_hw_init = false; + rt721->fu1e_dapm_mute = true; + rt721->fu0f_dapm_mute = true; + rt721->fu0f_mixer_l_mute = rt721->fu0f_mixer_r_mute = true; + rt721->fu1e_mixer_mute[0] = rt721->fu1e_mixer_mute[1] = + rt721->fu1e_mixer_mute[2] = rt721->fu1e_mixer_mute[3] = true; + + return devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai)); +} + +int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + + rt721->disable_irq = false; + + if (rt721->hw_init) + return 0; + + regcache_cache_only(rt721->regmap, false); + regcache_cache_only(rt721->mbq_regmap, false); + if (rt721->first_hw_init) { + regcache_cache_bypass(rt721->regmap, true); + regcache_cache_bypass(rt721->mbq_regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + rt721_sdca_dmic_preset(rt721); + rt721_sdca_amp_preset(rt721); + rt721_sdca_jack_preset(rt721); + if (rt721->first_hw_init) { + regcache_cache_bypass(rt721->regmap, false); + regcache_mark_dirty(rt721->regmap); + regcache_cache_bypass(rt721->mbq_regmap, false); + regcache_mark_dirty(rt721->mbq_regmap); + } else + rt721->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt721->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h new file mode 100644 index 000000000000..0a82c107b19a --- /dev/null +++ b/sound/soc/codecs/rt721-sdca.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt721-sdca.h -- RT721 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef __RT721_H__ +#define __RT721_H__ + +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/soc.h> +#include <linux/workqueue.h> + +struct rt721_sdca_priv { + struct regmap *regmap; + struct regmap *mbq_regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; + struct mutex calibrate_mutex; + struct mutex disable_irq_lock; + bool disable_irq; + /* For Headset jack & Headphone */ + unsigned int scp_sdca_stat1; + unsigned int scp_sdca_stat2; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + int jack_type; + int jd_src; + bool fu0f_dapm_mute; + bool fu0f_mixer_l_mute; + bool fu0f_mixer_r_mute; + /* For DMIC */ + bool fu1e_dapm_mute; + bool fu1e_mixer_mute[4]; +}; + +struct rt721_sdca_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +/* NID */ +#define RT721_ANA_POW_PART 0x01 +#define RT721_DAC_CTRL 0x04 +#define RT721_JD_CTRL 0x09 +#define RT721_CBJ_CTRL 0x0a +#define RT721_CAP_PORT_CTRL 0x0c +#define RT721_CLASD_AMP_CTRL 0x0d +#define RT721_VENDOR_REG 0x20 +#define RT721_RC_CALIB_CTRL 0x40 +#define RT721_VENDOR_EQ_L 0x53 +#define RT721_VENDOR_EQ_R 0x54 +#define RT721_VENDOR_HP_CALI 0x56 +#define RT721_VENDOR_CHARGE_PUMP 0x57 +#define RT721_VENDOR_CLASD_CALI 0x58 +#define RT721_VENDOR_IMS_DRE 0x5b +#define RT721_VENDOR_SPK_EFUSE 0x5c +#define RT721_VENDOR_LEVEL_CTRL 0x5d +#define RT721_VENDOR_ANA_CTL 0x5f +#define RT721_HDA_SDCA_FLOAT 0x61 + +/* Index (NID:01h) */ +#define RT721_MBIAS_LV_CTRL2 0x07 +#define RT721_VREF1_HV_CTRL1 0x0a +#define RT721_VREF2_LV_CTRL1 0x0b + +/* Index (NID:04h) */ +#define RT721_DAC_2CH_CTRL3 0x02 +#define RT721_DAC_2CH_CTRL4 0x03 + +/* Index (NID:09h) */ +#define RT721_JD_1PIN_GAT_CTRL2 0x07 + +/* Index (NID:0ah) */ +#define RT721_CBJ_A0_GAT_CTRL1 0x04 +#define RT721_CBJ_A0_GAT_CTRL2 0x05 + +/* Index (NID:0Ch) */ +#define RT721_HP_AMP_2CH_CAL1 0x05 +#define RT721_HP_AMP_2CH_CAL4 0x08 +#define RT721_HP_AMP_2CH_CAL18 0x1b + +/* Index (NID:0dh) */ +#define RT721_CLASD_AMP_2CH_CAL 0x14 + +/* Index (NID:20h) */ +#define RT721_JD_PRODUCT_NUM 0x00 +#define RT721_ANALOG_BIAS_CTL3 0x04 +#define RT721_JD_CTRL1 0x09 +#define RT721_LDO2_3_CTL1 0x0e +#define RT721_GPIO_PAD_CTRL5 0x13 +#define RT721_LDO1_CTL 0x1a +#define RT721_HP_JD_CTRL 0x24 +#define RT721_VD_HIDDEN_CTRL 0x26 +#define RT721_CLSD_CTRL6 0x3c +#define RT721_COMBO_JACK_AUTO_CTL1 0x45 +#define RT721_COMBO_JACK_AUTO_CTL2 0x46 +#define RT721_COMBO_JACK_AUTO_CTL3 0x47 +#define RT721_DIGITAL_MISC_CTRL4 0x4a +#define RT721_VREFO_GAT 0x63 +#define RT721_FSM_CTL 0x67 +#define RT721_SDCA_INTR_REC 0x82 +#define RT721_SW_CONFIG1 0x8a +#define RT721_SW_CONFIG2 0x8b + +/* Index (NID:40h) */ +#define RT721_RC_CALIB_CTRL0 0x00 + +/* Index (NID:58h) */ +#define RT721_DAC_DC_CALI_CTL1 0x01 +#define RT721_DAC_DC_CALI_CTL2 0x02 +#define RT721_DAC_DC_CALI_CTL3 0x03 + +/* Index (NID:5fh) */ +#define RT721_MISC_POWER_CTL0 0x00 +#define RT721_MISC_POWER_CTL31 0x31 +#define RT721_UAJ_TOP_TCON13 0x44 +#define RT721_UAJ_TOP_TCON14 0x45 +#define RT721_UAJ_TOP_TCON17 0x48 + +/* Index (NID:61h) */ +#define RT721_HDA_LEGACY_MUX_CTL0 0x00 +#define RT721_HDA_LEGACY_UAJ_CTL 0x02 +#define RT721_HDA_LEGACY_CTL1 0x05 +#define RT721_HDA_LEGACY_RESET_CTL 0x06 +#define RT721_XU_REL_CTRL 0x0c +#define RT721_GE_REL_CTRL1 0x0d +#define RT721_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e +#define RT721_GE_SDCA_RST_CTRL 0x10 +#define RT721_INT_RST_EN_CTRL 0x11 +#define RT721_XU_EVENT_EN 0x13 +#define RT721_INLINE_CTL2 0x17 +#define RT721_UMP_HID_CTRL1 0x18 +#define RT721_UMP_HID_CTRL2 0x19 +#define RT721_UMP_HID_CTRL3 0x1a +#define RT721_UMP_HID_CTRL4 0x1b +#define RT721_UMP_HID_CTRL5 0x1c +#define RT721_FUNC_FLOAT_CTL0 0x22 +#define RT721_FUNC_FLOAT_CTL1 0x23 +#define RT721_FUNC_FLOAT_CTL2 0x24 +#define RT721_FUNC_FLOAT_CTL3 0x25 +#define RT721_ENT_FLOAT_CTL0 0x29 +#define RT721_ENT_FLOAT_CTL1 0x2c +#define RT721_ENT_FLOAT_CTL2 0x2d +#define RT721_ENT_FLOAT_CTL3 0x2e +#define RT721_ENT_FLOAT_CTL4 0x2f +#define RT721_CH_FLOAT_CTL1 0x45 +#define RT721_CH_FLOAT_CTL2 0x46 +#define RT721_ENT_FLOAT_CTL5 0x53 +#define RT721_ENT_FLOAT_CTL6 0x54 +#define RT721_ENT_FLOAT_CTL7 0x55 +#define RT721_ENT_FLOAT_CTL8 0x57 +#define RT721_ENT_FLOAT_CTL9 0x5a +#define RT721_ENT_FLOAT_CTL10 0x5b +#define RT721_CH_FLOAT_CTL3 0x6a +#define RT721_CH_FLOAT_CTL4 0x6d +#define RT721_CH_FLOAT_CTL5 0x70 +#define RT721_CH_FLOAT_CTL6 0x92 + +/* Parameter & Verb control 01 (0x26)(NID:20h) */ +#define RT721_HIDDEN_REG_SW_RESET (0x1 << 14) + +/* Buffer address for HID */ +#define RT721_BUF_ADDR_HID1 0x44030000 +#define RT721_BUF_ADDR_HID2 0x44030020 + +/* RT721 SDCA Control - function number */ +#define FUNC_NUM_JACK_CODEC 0x01 +#define FUNC_NUM_MIC_ARRAY 0x02 +#define FUNC_NUM_HID 0x03 +#define FUNC_NUM_AMP 0x04 + +/* RT721 SDCA entity */ +#define RT721_SDCA_ENT_HID01 0x01 +#define RT721_SDCA_ENT_XUV 0x03 +#define RT721_SDCA_ENT_GE49 0x49 +#define RT721_SDCA_ENT_USER_FU05 0x05 +#define RT721_SDCA_ENT_USER_FU06 0x06 +#define RT721_SDCA_ENT_USER_FU0F 0x0f +#define RT721_SDCA_ENT_USER_FU10 0x19 +#define RT721_SDCA_ENT_USER_FU1E 0x1e +#define RT721_SDCA_ENT_FU15 0x15 +#define RT721_SDCA_ENT_PDE23 0x23 +#define RT721_SDCA_ENT_PDE40 0x40 +#define RT721_SDCA_ENT_PDE41 0x41 +#define RT721_SDCA_ENT_PDE11 0x11 +#define RT721_SDCA_ENT_PDE12 0x12 +#define RT721_SDCA_ENT_PDE2A 0x2a +#define RT721_SDCA_ENT_CS01 0x01 +#define RT721_SDCA_ENT_CS11 0x11 +#define RT721_SDCA_ENT_CS1F 0x1f +#define RT721_SDCA_ENT_CS1C 0x1c +#define RT721_SDCA_ENT_CS31 0x31 +#define RT721_SDCA_ENT_OT23 0x42 +#define RT721_SDCA_ENT_IT26 0x26 +#define RT721_SDCA_ENT_IT09 0x09 +#define RT721_SDCA_ENT_PLATFORM_FU15 0x15 +#define RT721_SDCA_ENT_PLATFORM_FU44 0x44 +#define RT721_SDCA_ENT_XU03 0x03 +#define RT721_SDCA_ENT_XU0D 0x0d +#define RT721_SDCA_ENT_FU55 0x55 + +/* RT721 SDCA control */ +#define RT721_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT721_SDCA_CTL_FU_MUTE 0x01 +#define RT721_SDCA_CTL_FU_VOLUME 0x02 +#define RT721_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT721_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11 +#define RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 +#define RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13 +#define RT721_SDCA_CTL_SELECTED_MODE 0x01 +#define RT721_SDCA_CTL_DETECTED_MODE 0x02 +#define RT721_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT721_SDCA_CTL_VENDOR_DEF 0x30 +#define RT721_SDCA_CTL_XUV 0x34 +#define RT721_SDCA_CTL_FU_CH_GAIN 0x0b + +/* RT721 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 +#define CH_08 0x08 +#define CH_09 0x09 +#define CH_0A 0x0a + +/* sample frequency index */ +#define RT721_SDCA_RATE_8000HZ 0x01 +#define RT721_SDCA_RATE_11025HZ 0x02 +#define RT721_SDCA_RATE_12000HZ 0x03 +#define RT721_SDCA_RATE_16000HZ 0x04 +#define RT721_SDCA_RATE_22050HZ 0x05 +#define RT721_SDCA_RATE_24000HZ 0x06 +#define RT721_SDCA_RATE_32000HZ 0x07 +#define RT721_SDCA_RATE_44100HZ 0x08 +#define RT721_SDCA_RATE_48000HZ 0x09 +#define RT721_SDCA_RATE_88200HZ 0x0a +#define RT721_SDCA_RATE_96000HZ 0x0b +#define RT721_SDCA_RATE_176400HZ 0x0c +#define RT721_SDCA_RATE_192000HZ 0x0d +#define RT721_SDCA_RATE_384000HZ 0x0e +#define RT721_SDCA_RATE_768000HZ 0x0f + +/* RT721 HID ID */ +#define RT721_SDCA_HID_ID 0x11 + +enum { + RT721_AIF1, /* For headset mic and headphone */ + RT721_AIF2, /* For speaker */ + RT721_AIF3, /* For dmic */ + RT721_AIFS, +}; + +int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt721_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave); +#endif /* __RT721_H__ */ diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index d5c985ff5ac5..25fc13687bc8 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -177,7 +177,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave, * This also could sync with the cache value as the rt722_sdca_jack_init set. */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_0); sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); } @@ -308,12 +308,8 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave, SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); if (ret < 0) goto io_error; - } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) { - ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1, - SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6); - if (ret < 0) - goto io_error; } + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2); if (ret < 0) goto io_error; @@ -444,7 +440,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) mutex_lock(&rt722_sdca->disable_irq_lock); rt722_sdca->disable_irq = true; ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0); + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8, 0); mutex_unlock(&rt722_sdca->disable_irq_lock); @@ -471,7 +467,7 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) if (!slave->unattach_request) { mutex_lock(&rt722->disable_irq_lock); if (rt722->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); rt722->disable_irq = false; } diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index e5bd9ef812de..908846e994df 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -190,8 +190,8 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work) if (!rt722->component->card || !rt722->component->card->instantiated) return; - /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ - if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) { + /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */ + if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { ret = rt722_sdca_headset_detect(rt722); if (ret < 0) return; @@ -294,7 +294,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) if (rt722->hs_jack) { /* set SCP_SDCA_IntMask1[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_0); /* set SCP_SDCA_IntMask2[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); @@ -308,6 +308,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) regmap_write(rt722->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, RT722_SDCA_CTL_SELECTED_MODE, 0), 0); + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL1, 0x0000); /* trigger GE interrupt */ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2, 0x4000, 0x4000); @@ -607,12 +608,8 @@ static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, if (!adc_vol_flag) /* boost gain */ ctl = regvalue / boost_step; - else { /* ADC gain */ - if (adc_vol_flag) - ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); - else - ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset); - } + else /* ADC gain */ + ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); ucontrol->value.integer.value[i] = ctl; } diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index 240af0563283..390696440155 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -6,6 +6,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> +#include <linux/mux/driver.h> #include <linux/regulator/consumer.h> #include <sound/soc.h> @@ -16,6 +17,7 @@ struct simple_mux { struct gpio_desc *gpiod_mux; unsigned int mux; const char *mux_texts[MUX_TEXT_SIZE]; + unsigned int idle_state; struct soc_enum mux_enum; struct snd_kcontrol_new mux_mux; struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE]; @@ -57,6 +59,9 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, priv->mux = ucontrol->value.enumerated.item[0]; + if (priv->idle_state != MUX_IDLE_AS_IS && dapm->bias_level < SND_SOC_BIAS_PREPARE) + return 0; + gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux); return snd_soc_dapm_mux_update_power(dapm, kcontrol, @@ -75,10 +80,33 @@ static unsigned int simple_mux_read(struct snd_soc_component *component, static const struct snd_kcontrol_new simple_mux_mux = SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put); +static int simple_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + + if (priv->idle_state != MUX_IDLE_AS_IS) { + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux); + break; + case SND_SOC_DAPM_POST_PMD: + gpiod_set_value_cansleep(priv->gpiod_mux, priv->idle_state); + break; + default: + break; + } + } + + return 0; +} + static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = { SND_SOC_DAPM_INPUT("IN1"), SND_SOC_DAPM_INPUT("IN2"), - SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe() + SND_SOC_DAPM_MUX_E("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux, // see simple_mux_probe() + simple_mux_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("OUT"), }; @@ -93,6 +121,7 @@ static int simple_mux_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct simple_mux *priv; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -121,6 +150,14 @@ static int simple_mux_probe(struct platform_device *pdev) /* Overwrite text ("Input 1", "Input 2") if property exists */ of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE); + ret = of_property_read_u32(np, "idle-state", &priv->idle_state); + if (ret < 0) { + priv->idle_state = MUX_IDLE_AS_IS; + } else if (priv->idle_state != MUX_IDLE_AS_IS && priv->idle_state >= 2) { + dev_err(dev, "invalid idle-state %u\n", priv->idle_state); + return -EINVAL; + } + /* switch to use priv data instead of default */ priv->mux_enum.texts = priv->mux_texts; priv->mux_mux.private_value = (unsigned long)&priv->mux_enum; diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c new file mode 100644 index 000000000000..f2cea6186d98 --- /dev/null +++ b/sound/soc/codecs/sma1307.c @@ -0,0 +1,2049 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// sma1307.c -- sma1307 ALSA SoC Audio driver +// +// Copyright 2024 Iron Device Corporation +// +// Auther: Gyuhwa Park <gyuwha.park@irondevice.com> +// Auther: Kiseok Jo <kiseok.jo@irondevice.com> + +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> +#include "sma1307.h" + +#define CHECK_PERIOD_TIME 1 /* sec per HZ */ +#define PLL_MATCH(_input_clk_name, _output_clk_name, _input_clk,\ + _post_n, _n, _vco, _p_cp)\ +{\ + .input_clk_name = _input_clk_name,\ + .output_clk_name = _output_clk_name,\ + .input_clk = _input_clk,\ + .post_n = _post_n,\ + .n = _n,\ + .vco = _vco,\ + .p_cp = _p_cp,\ +} + +static const char *setting_file = "sma1307_setting.bin"; +#define SMA1307_SETTING_CHECKSUM 0x100000 + +/* PLL clock setting Table */ +struct sma1307_pll_match { + char *input_clk_name; + char *output_clk_name; + unsigned int input_clk; + unsigned int post_n; + unsigned int n; + unsigned int vco; + unsigned int p_cp; +}; + +struct sma1307_data { + char *name; + void (*init)(struct regmap *regmap); +}; + +struct sma1307_priv { + bool check_fault_status; + bool force_mute_status; + bool sw_ot1_prot; + char *name; + enum sma1307_mode amp_mode; + int binary_mode; + int dapm_aif_in; + int dapm_aif_out0; + int dapm_aif_out1; + int dapm_sdo_en; + int dapm_sdo_setting; + int num_of_pll_matches; + int check_fault_period; + struct delayed_work check_fault_work; + struct device *dev; + struct kobject *kobj; + struct mutex default_lock; + struct regmap *regmap; + struct sma1307_setting_file set; + const struct sma1307_pll_match *pll_matches; + const struct sma1307_data *data; + unsigned int cur_vol; + unsigned int format; + unsigned int frame_size; + unsigned int init_vol; + unsigned int last_bclk; + unsigned int otp_trm2; + unsigned int otp_trm3; + unsigned int rev_num; + unsigned int sys_clk_id; + unsigned int tdm_slot0_rx; + unsigned int tdm_slot1_rx; + unsigned int tdm_slot0_tx; + unsigned int tdm_slot1_tx; + unsigned int tsdw_cnt; +}; + +static const struct sma1307_pll_match sma1307_pll_matches[] = { + /* in_clk_name, out_clk_name, input_clk post_n, n, vco, p_cp */ + PLL_MATCH("1.411MHz", "24.554MHz", + 1411200, 0x06, 0xD1, 0x88, 0x00), + PLL_MATCH("1.536MHz", "24.576MHz", + 1536000, 0x06, 0xC0, 0x88, 0x00), + PLL_MATCH("2.822MHz", "24.554MHz", + 2822400, 0x06, 0xD1, 0x88, 0x04), + PLL_MATCH("3.072MHz", "24.576MHz", + 3072000, 0x06, 0x60, 0x88, 0x00), + PLL_MATCH("6.144MHz", "24.576MHz", + 6144000, 0x06, 0x60, 0x88, 0x04), + PLL_MATCH("12.288MHz", "24.576MHz", + 12288000, 0x06, 0x60, 0x88, 0x08), + PLL_MATCH("19.2MHz", "24.48MHz", + 19200000, 0x06, 0x7B, 0x88, 0x0C), + PLL_MATCH("24.576MHz", "24.576MHz", + 24576000, 0x06, 0x60, 0x88, 0x0C), +}; + +static struct snd_soc_component *sma1307_amp_component; + +static void sma1307_startup(struct snd_soc_component *); +static void sma1307_shutdown(struct snd_soc_component *); +static void sma1307_reset(struct snd_soc_component *); +static void sma1307_set_binary(struct snd_soc_component *); +static void sma1307_set_default(struct snd_soc_component *); + +/* Initial register value - 6.0W SPK (8ohm load) */ +static const struct reg_default sma1307_reg_def[] = { + { 0x00, 0x80 }, + { 0x01, 0x00 }, + { 0x02, 0x52 }, + { 0x03, 0x4C }, + { 0x04, 0x47 }, + { 0x05, 0x42 }, + { 0x06, 0x40 }, + { 0x07, 0x40 }, + { 0x08, 0x3C }, + { 0x09, 0x2F }, + { 0x0A, 0x32 }, + { 0x0B, 0x50 }, + { 0x0C, 0x8C }, + { 0x0D, 0x00 }, + { 0x0E, 0x3F }, + { 0x0F, 0x00 }, + { 0x10, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x09 }, + { 0x14, 0x12 }, + { 0x1C, 0x00 }, + { 0x1D, 0x85 }, + { 0x1E, 0xA1 }, + { 0x1F, 0x67 }, + { 0x22, 0x00 }, + { 0x23, 0x1F }, + { 0x24, 0x7A }, + { 0x25, 0x00 }, + { 0x26, 0xFF }, + { 0x27, 0x39 }, + { 0x28, 0x54 }, + { 0x29, 0x92 }, + { 0x2A, 0xB0 }, + { 0x2B, 0xED }, + { 0x2C, 0xED }, + { 0x2D, 0xFF }, + { 0x2E, 0xFF }, + { 0x2F, 0xFF }, + { 0x30, 0xFF }, + { 0x31, 0xFF }, + { 0x32, 0xFF }, + { 0x34, 0x01 }, + { 0x35, 0x17 }, + { 0x36, 0x92 }, + { 0x37, 0x00 }, + { 0x38, 0x01 }, + { 0x39, 0x10 }, + { 0x3E, 0x01 }, + { 0x3F, 0x08 }, + { 0x8B, 0x05 }, + { 0x8C, 0x50 }, + { 0x8D, 0x80 }, + { 0x8E, 0x10 }, + { 0x8F, 0x02 }, + { 0x90, 0x02 }, + { 0x91, 0x83 }, + { 0x92, 0xC0 }, + { 0x93, 0x00 }, + { 0x94, 0xA4 }, + { 0x95, 0x74 }, + { 0x96, 0x57 }, + { 0xA2, 0xCC }, + { 0xA3, 0x28 }, + { 0xA4, 0x40 }, + { 0xA5, 0x01 }, + { 0xA6, 0x41 }, + { 0xA7, 0x08 }, + { 0xA8, 0x04 }, + { 0xA9, 0x27 }, + { 0xAA, 0x10 }, + { 0xAB, 0x10 }, + { 0xAC, 0x10 }, + { 0xAD, 0x0F }, + { 0xAE, 0xCD }, + { 0xAF, 0x70 }, + { 0xB0, 0x03 }, + { 0xB1, 0xEF }, + { 0xB2, 0x03 }, + { 0xB3, 0xEF }, + { 0xB4, 0xF3 }, + { 0xB5, 0x3D }, +}; + +static bool sma1307_readable_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME: + case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19: + case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL: + case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2: + case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3: + case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2: + case SMA1307_F5_READY_FOR_V_SAR: + case SMA1307_F7_READY_FOR_T_SAR ... SMA1307_FF_DEVICE_INDEX: + break; + default: + return false; + } + return true; +} + +static bool sma1307_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME: + case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19: + case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL: + case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2: + case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3: + case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2: + break; + default: + return false; + } + return true; +} + +static bool sma1307_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_F8_STATUS_T1 ... SMA1307_FF_DEVICE_INDEX: + break; + default: + return false; + } + return true; +} + +/* DB scale conversion of speaker volume */ +static const DECLARE_TLV_DB_SCALE(sma1307_spk_tlv, -6000, 50, 0); + +static const char *const sma1307_aif_in_source_text[] = { + "Mono", "Left", "Right" +}; + +static const char *const sma1307_sdo_setting_text[] = { + "Data_One_48k", "Data_Two_48k", "Data_Two_24k", + "Clk_PLL", "Clk_OSC" +}; + +static const char *const sma1307_aif_out_source_text[] = { + "Disable", "After_FmtC", "After_Mixer", "After_DSP", + "Vrms2_Avg", "Battery", "Temperature", "After_Delay" +}; + +static const char *const sma1307_tdm_slot_text[] = { + "Slot0", "Slot1", "Slot2", "Slot3", + "Slot4", "Slot5", "Slot6", "Slot7" +}; + +static const char *const sma1307_binary_mode_text[] = { + "Mode0", "Mode1", "Mode2", "Mode3", "Mode4" +}; + +static const char *const sma1307_reset_text[] = { + "Reset" +}; + +static const struct soc_enum sma1307_aif_in_source_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_in_source_text), + sma1307_aif_in_source_text); +static const struct soc_enum sma1307_sdo_setting_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_sdo_setting_text), + sma1307_sdo_setting_text); +static const struct soc_enum sma1307_aif_out_source_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_out_source_text), + sma1307_aif_out_source_text); +static const struct soc_enum sma1307_tdm_slot_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_tdm_slot_text), + sma1307_tdm_slot_text); +static const struct soc_enum sma1307_binary_mode_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_binary_mode_text), + sma1307_binary_mode_text); +static const struct soc_enum sma1307_reset_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_reset_text), + sma1307_reset_text); + +static int sma1307_force_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->force_mute_status; + + return 0; +} + +static int sma1307_force_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->force_mute_status == val) { + change = false; + } else { + change = true; + sma1307->force_mute_status = val; + } + + return change; +} + +static int sma1307_tdm_slot_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int val1, val2; + + regmap_read(sma1307->regmap, SMA1307_A5_TDM1, &val1); + regmap_read(sma1307->regmap, SMA1307_A6_TDM2, &val2); + + if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) { + ucontrol->value.integer.value[0] + = (val1 & SMA1307_TDM_SLOT0_RX_POS_MASK) >> 3; + sma1307->tdm_slot0_rx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) { + ucontrol->value.integer.value[0] + = val1 & SMA1307_TDM_SLOT1_RX_POS_MASK; + sma1307->tdm_slot1_rx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) { + ucontrol->value.integer.value[0] + = (val2 & SMA1307_TDM_SLOT0_TX_POS_MASK) >> 3; + sma1307->tdm_slot0_tx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) { + ucontrol->value.integer.value[0] + = val2 & SMA1307_TDM_SLOT1_TX_POS_MASK; + sma1307->tdm_slot1_tx = ucontrol->value.integer.value[0]; + } else { + return -EINVAL; + } + + return 0; +} + +static int sma1307_tdm_slot_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int val = (int)ucontrol->value.integer.value[0]; + bool change; + + if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) { + if (sma1307->tdm_slot0_rx == val) + change = false; + else { + change = true; + sma1307->tdm_slot0_rx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1, + SMA1307_TDM_SLOT0_RX_POS_MASK, val << 3); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) { + if (sma1307->tdm_slot1_rx == val) + change = false; + else { + change = true; + sma1307->tdm_slot1_rx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1, + SMA1307_TDM_SLOT1_RX_POS_MASK, val); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) { + if (sma1307->tdm_slot0_tx == val) + change = false; + else { + change = true; + sma1307->tdm_slot0_tx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2, + SMA1307_TDM_SLOT0_TX_POS_MASK, val << 3); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) { + if (sma1307->tdm_slot1_tx == val) + change = false; + else { + change = true; + sma1307->tdm_slot1_tx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2, + SMA1307_TDM_SLOT1_TX_POS_MASK, val); + } + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return change; +} + +static int sma1307_sw_ot1_prot_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->sw_ot1_prot; + + return 0; +} + +static int sma1307_sw_ot1_prot_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->sw_ot1_prot == val) + change = false; + else { + change = true; + sma1307->sw_ot1_prot = val; + } + + return change; +} + +static int sma1307_check_fault_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->check_fault_status; + + return 0; +} + +static int sma1307_check_fault_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->check_fault_status == val) { + change = false; + } else { + change = true; + sma1307->check_fault_status = val; + } + + return change; +} + +static int sma1307_check_fault_period_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = sma1307->check_fault_period; + + return 0; +} + +static int sma1307_check_fault_period_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + bool change = false; + int val = ucontrol->value.integer.value[0]; + + if (val < mc->min || val > mc->max) + return -EINVAL; + if (sma1307->check_fault_period == val) { + change = false; + } else { + change = true; + sma1307->check_fault_period = val; + } + + return change; +} + +static int sma1307_reset_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_RESET_MASK, SMA1307_RESET_ON); + sma1307_reset(component); + + snd_ctl_notify(component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, + &kcontrol->id); + + return true; +} + +static int sma1307_binary_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_kcontrol_chip(kcontrol); + + sma1307->binary_mode = (int)ucontrol->value.enumerated.item[0]; + if (sma1307->set.status) + sma1307_set_binary(component); + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + +static void sma1307_startup(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_ON); + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_POWER_MASK, SMA1307_POWER_ON); + + if (sma1307->amp_mode == SMA1307_MONO_MODE) { + regmap_update_bits(sma1307->regmap, + SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, + SMA1307_SPK_MONO); + } else { + regmap_update_bits(sma1307->regmap, + SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, + SMA1307_SPK_STEREO); + } + + if (sma1307->check_fault_status) { + if (sma1307->check_fault_period > 0) + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + sma1307->check_fault_period * HZ); + else + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + CHECK_PERIOD_TIME * HZ); + } +} + +static void sma1307_shutdown(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + /* for SMA1307A */ + cancel_delayed_work_sync(&sma1307->check_fault_work); + + regmap_update_bits(sma1307->regmap, SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, SMA1307_SPK_MUTE); + /* Need to wait time for mute slope */ + msleep(55); + + regmap_update_bits(sma1307->regmap, SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, SMA1307_SPK_OFF); + regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_OFF); + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_POWER_MASK, SMA1307_POWER_OFF); +} + +static int sma1307_aif_in_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = sma1307->dapm_aif_in; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case SMA1307_MONO_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_ON); + break; + case SMA1307_LEFT_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_OFF); + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_LR_DATA_SW_MASK, + SMA1307_LR_DATA_SW_NORMAL); + break; + case SMA1307_RIGHT_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_OFF); + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_LR_DATA_SW_MASK, + SMA1307_LR_DATA_SW_SWAP); + break; + default: + + dev_err(sma1307->dev, "%s: Invalid value (%d)\n", + __func__, mux); + return -EINVAL; + } + sma1307->amp_mode = mux; + break; + } + return 0; +} + +static int sma1307_sdo_setting_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = sma1307->dapm_sdo_setting; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case SMA1307_OUT_DATA_ONE_48K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_ONE_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_OUTPUT3_DIS + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_DATA_TWO_48K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_TWO_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_OUTPUT3_DIS + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_DATA_TWO_24K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_TWO_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_TWO_SDO_PER_CH_24K + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_CLK_PLL: + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_CLK_PLL); + + break; + case SMA1307_OUT_CLK_OSC: + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_CLK_OSC); + + break; + default: + dev_err(sma1307->dev, "%s: Invalid value (%d)\n", + __func__, mux); + return -EINVAL; + } + break; + } + return 0; +} + +static int sma1307_aif_out_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = 0, val = 0, mask = 0; + + if (!strcmp(w->name, SMA1307_AIF_OUT0_NAME)) { + mux = sma1307->dapm_aif_out0; + val = mux; + mask = SMA1307_SDO_OUT0_SEL_MASK; + } else if (!strcmp(w->name, SMA1307_AIF_OUT1_NAME)) { + mux = sma1307->dapm_aif_out1; + val = mux << 3; + mask = SMA1307_SDO_OUT1_SEL_MASK; + } else { + dev_err(sma1307->dev, "%s: Invalid widget - %s\n", + __func__, w->name); + return -EINVAL; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(sma1307->regmap, SMA1307_09_OUTPUT_CTRL, + mask, val); + break; + } + return 0; +} + +static int sma1307_sdo_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(sma1307->regmap, + SMA1307_09_OUTPUT_CTRL, + SMA1307_PORT_CONFIG_MASK, + SMA1307_OUTPUT_PORT_ENABLE); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT_MASK, + SMA1307_LOGIC_OUTPUT); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(sma1307->regmap, + SMA1307_09_OUTPUT_CTRL, + SMA1307_PORT_CONFIG_MASK, + SMA1307_INPUT_PORT_ONLY); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT_MASK, + SMA1307_HIGH_Z_OUTPUT); + break; + } + return 0; +} + +static int sma1307_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + sma1307_startup(component); + break; + case SND_SOC_DAPM_PRE_PMD: + sma1307_shutdown(component); + break; + } + return 0; +} + +static int sma1307_dapm_aif_in_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.enumerated.item[0] = (unsigned int)sma1307->dapm_aif_in; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_aif_in_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_in_source_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_aif_in != val) { + change = true; + sma1307->dapm_aif_in = val; + } else + change = false; + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_sdo_setting_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.enumerated.item[0] = + (unsigned int)sma1307->dapm_sdo_setting; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_sdo_setting_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_sdo_setting_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_sdo_setting != val) { + change = true; + sma1307->dapm_sdo_setting = val; + } else + change = false; + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_aif_out_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + unsigned int val = 0; + + if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) { + val = (unsigned int)sma1307->dapm_aif_out0; + } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) { + val = (unsigned int)sma1307->dapm_aif_out1; + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + ucontrol->value.enumerated.item[0] = val; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_aif_out_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_out_source_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) { + if (sma1307->dapm_aif_out0 != val) { + change = true; + sma1307->dapm_aif_out0 = val; + } else + change = false; + } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) { + if (sma1307->dapm_aif_out1 != val) { + change = true; + sma1307->dapm_aif_out1 = val; + } else + change = false; + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_sdo_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.integer.value[0] = (long)sma1307->dapm_sdo_en; + snd_soc_dapm_put_volsw(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_sdo_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.integer.value[0]; + bool change; + + if ((val < 0) || (val > 1)) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_sdo_en != val) { + change = true; + sma1307->dapm_sdo_en = val; + } else + change = false; + + snd_soc_dapm_put_volsw(kcontrol, ucontrol); + + return change; +} + +static const struct snd_kcontrol_new sma1307_aif_in_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_IN_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_in_get, + .put = sma1307_dapm_aif_in_put, + .private_value = (unsigned long)&sma1307_aif_in_source_enum +}; + +static const struct snd_kcontrol_new sma1307_sdo_setting_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SDO Setting", + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_sdo_setting_get, + .put = sma1307_dapm_sdo_setting_put, + .private_value = (unsigned long)&sma1307_sdo_setting_enum +}; + +static const struct snd_kcontrol_new sma1307_aif_out0_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_OUT0_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_out_get, + .put = sma1307_dapm_aif_out_put, + .private_value = (unsigned long)&sma1307_aif_out_source_enum +}; + +static const struct snd_kcontrol_new sma1307_aif_out1_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_OUT1_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_out_get, + .put = sma1307_dapm_aif_out_put, + .private_value = (unsigned long)&sma1307_aif_out_source_enum +}; + +static const struct snd_kcontrol_new sma1307_sdo_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Switch", + .info = snd_soc_info_volsw, + .get = sma1307_dapm_sdo_enable_get, + .put = sma1307_dapm_sdo_enable_put, + .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, 0, 1, 0, 0) +}; + +static const struct snd_kcontrol_new sma1307_enable_control = + SOC_DAPM_SINGLE("Switch", SMA1307_00_SYSTEM_CTRL, 0, 1, 0); + +static const struct snd_kcontrol_new sma1307_binary_mode_control[] = { + SOC_ENUM_EXT("Binary Mode", sma1307_binary_mode_enum, + snd_soc_get_enum_double, sma1307_binary_mode_put), +}; + +static const struct snd_kcontrol_new sma1307_snd_controls[] = { + SOC_SINGLE_TLV(SMA1307_VOL_CTRL_NAME, SMA1307_0A_SPK_VOL, + 0, 167, 1, sma1307_spk_tlv), + SOC_ENUM_EXT(SMA1307_TDM_RX0_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_RX1_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_TX0_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_TX1_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_RESET_CTRL_NAME, sma1307_reset_enum, + snd_soc_get_enum_double, sma1307_reset_put), + SOC_SINGLE_BOOL_EXT(SMA1307_FORCE_MUTE_CTRL_NAME, 0, + sma1307_force_mute_get, sma1307_force_mute_put), + SOC_SINGLE_BOOL_EXT(SMA1307_OT1_SW_PROT_CTRL_NAME, 0, + sma1307_sw_ot1_prot_get, sma1307_sw_ot1_prot_put), + SOC_SINGLE_BOOL_EXT(SMA1307_CHECK_FAULT_STATUS_NAME, 0, + sma1307_check_fault_status_get, + sma1307_check_fault_status_put), + SOC_SINGLE_EXT(SMA1307_CHECK_FAULT_PERIOD_NAME, SND_SOC_NOPM, 0, 600, 0, + sma1307_check_fault_period_get, + sma1307_check_fault_period_put), +}; + +static const struct snd_soc_dapm_widget sma1307_dapm_widgets[] = { + /* platform domain */ + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("SDO"), + + /* path domain */ + SND_SOC_DAPM_MUX_E(SMA1307_AIF_IN_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_in_source_control, + sma1307_aif_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("SDO Setting", SND_SOC_NOPM, 0, 0, + &sma1307_sdo_setting_control, + sma1307_sdo_setting_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT0_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_out0_source_control, + sma1307_aif_out_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT1_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_out1_source_control, + sma1307_aif_out_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SWITCH_E("SDO Enable", SND_SOC_NOPM, 0, 0, + &sma1307_sdo_control, + sma1307_sdo_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("Entry", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV_E("AMP Power", SND_SOC_NOPM, 0, 0, NULL, 0, + sma1307_power_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0, + &sma1307_enable_control), + + /* stream domain */ + SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sma1307_audio_map[] = { + /* Playback */ + { "AIF IN Source", "Mono", "AIF IN" }, + { "AIF IN Source", "Left", "AIF IN" }, + { "AIF IN Source", "Right", "AIF IN" }, + + { "SDO Enable", "Switch", "AIF IN" }, + + { "SDO Setting", "Data_One_48k", "SDO Enable" }, + { "SDO Setting", "Data_Two_48k", "SDO Enable" }, + { "SDO Setting", "Data_Two_24k", "SDO Enable" }, + { "SDO Setting", "Clk_PLL", "SDO Enable" }, + { "SDO Setting", "Clk_OSC", "SDO Enable" }, + + { "AIF OUT0 Source", "Disable", "SDO Setting" }, + { "AIF OUT0 Source", "After_FmtC", "SDO Setting" }, + { "AIF OUT0 Source", "After_Mixer", "SDO Setting" }, + { "AIF OUT0 Source", "After_DSP", "SDO Setting" }, + { "AIF OUT0 Source", "Vrms2_Avg", "SDO Setting" }, + { "AIF OUT0 Source", "Battery", "SDO Setting" }, + { "AIF OUT0 Source", "Temperature", "SDO Setting" }, + { "AIF OUT0 Source", "After_Delay", "SDO Setting" }, + + { "AIF OUT1 Source", "Disable", "SDO Setting" }, + { "AIF OUT1 Source", "After_FmtC", "SDO Setting" }, + { "AIF OUT1 Source", "After_Mixer", "SDO Setting" }, + { "AIF OUT1 Source", "After_DSP", "SDO Setting" }, + { "AIF OUT1 Source", "Vrms2_Avg", "SDO Setting" }, + { "AIF OUT1 Source", "Battery", "SDO Setting" }, + { "AIF OUT1 Source", "Temperature", "SDO Setting" }, + { "AIF OUT1 Source", "After_Delay", "SDO Setting" }, + + { "Entry", NULL, "AIF OUT0 Source" }, + { "Entry", NULL, "AIF OUT1 Source" }, + { "Entry", NULL, "AIF IN Source" }, + + { "AMP Power", NULL, "Entry" }, + + { "AMP Enable", "Switch", "AMP Power" }, + { "SPK", NULL, "AMP Enable" }, + + /* Capture */ + { "AIF OUT", NULL, "AMP Enable" }, +}; + +static void sma1307_setup_pll(struct snd_soc_component *component, + unsigned int bclk) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + int i = 0; + + dev_dbg(component->dev, "%s: BCLK = %dHz\n", __func__, bclk); + + if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_MCLK) { + dev_warn(component->dev, "%s: MCLK is not supported\n", + __func__); + } else if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) { + for (i = 0; i < sma1307->num_of_pll_matches; i++) { + if (sma1307->pll_matches[i].input_clk == bclk) + break; + } + if (i == sma1307->num_of_pll_matches) { + dev_warn(component->dev, + "%s: No matching value between pll table and SCK\n", + __func__); + return; + } + + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_ON); + } + + regmap_write(sma1307->regmap, SMA1307_8B_PLL_POST_N, + sma1307->pll_matches[i].post_n); + regmap_write(sma1307->regmap, SMA1307_8C_PLL_N, + sma1307->pll_matches[i].n); + regmap_write(sma1307->regmap, SMA1307_8D_PLL_A_SETTING, + sma1307->pll_matches[i].vco); + regmap_write(sma1307->regmap, SMA1307_8E_PLL_P_CP, + sma1307->pll_matches[i].p_cp); +} + +static int sma1307_dai_hw_params_amp(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int bclk = 0; + + if (sma1307->format == SND_SOC_DAIFMT_DSP_A) + bclk = params_rate(params) * sma1307->frame_size; + else + bclk = params_rate(params) * params_physical_width(params) + * params_channels(params); + + dev_dbg(component->dev, + "%s: rate = %d : bit size = %d : channel = %d\n", + __func__, params_rate(params), params_width(params), + params_channels(params)); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) { + if (sma1307->last_bclk != bclk) { + sma1307_setup_pll(component, bclk); + sma1307->last_bclk = bclk; + } + } + + switch (params_rate(params)) { + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 44100: + case 48000: + break; + + case 96000: + dev_warn(component->dev, + "%s: %d rate not support SDO\n", __func__, + params_rate(params)); + break; + + default: + dev_err(component->dev, "%s: not support rate : %d\n", + __func__, params_rate(params)); + + return -EINVAL; + } + + /* substream->stream is SNDRV_PCM_STREAM_CAPTURE */ + } else { + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_32FS | + SMA1307_DATA_16BIT); + break; + + case SNDRV_PCM_FORMAT_S24_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_64FS | + SMA1307_DATA_24BIT); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_64FS | + SMA1307_DATA_24BIT); + break; + default: + dev_err(component->dev, + "%s: not support data bit : %d\n", __func__, + params_format(params)); + return -EINVAL; + } + } + + switch (sma1307->format) { + case SND_SOC_DAIFMT_I2S: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_STANDARD_I2S); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_I2S_FORMAT); + break; + case SND_SOC_DAIFMT_LEFT_J: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, SMA1307_LJ); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_LJ_FORMAT); + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_RJ_16BIT); + break; + case 24: + case 32: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_RJ_24BIT); + break; + } + break; + case SND_SOC_DAIFMT_DSP_A: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_STANDARD_I2S); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_TDM_FORMAT); + break; + } + + switch (params_width(params)) { + case 16: + case 24: + case 32: + break; + default: + dev_err(component->dev, + "%s: not support data bit : %d\n", __func__, + params_format(params)); + return -EINVAL; + } + + return 0; +} + +static int sma1307_dai_set_sysclk_amp(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (clk_id) { + case SMA1307_EXTERNAL_CLOCK_19_2: + case SMA1307_EXTERNAL_CLOCK_24_576: + case SMA1307_PLL_CLKIN_MCLK: + case SMA1307_PLL_CLKIN_BCLK: + break; + default: + dev_err(component->dev, "%s: Invalid clk id: %d\n", + __func__, clk_id); + return -EINVAL; + } + sma1307->sys_clk_id = clk_id; + + return 0; +} + +static int sma1307_dai_set_fmt_amp(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + + case SND_SOC_DAIFMT_CBC_CFC: + dev_dbg(component->dev, + "%s: %s\n", __func__, "I2S/TDM Device mode"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_CONTROLLER_DEVICE_MASK, + SMA1307_DEVICE_MODE); + break; + + case SND_SOC_DAIFMT_CBP_CFP: + dev_dbg(component->dev, + "%s: %s\n", __func__, "I2S/TDM Controller mode"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_CONTROLLER_DEVICE_MASK, + SMA1307_CONTROLLER_MODE); + break; + + default: + dev_err(component->dev, + "%s: Unsupported Controller/Device : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + sma1307->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + dev_err(component->dev, + "%s: Unsupported Audio Interface Format : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + + case SND_SOC_DAIFMT_IB_NF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Invert BCLK + Normal Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_SCK_RISING_MASK, + SMA1307_SCK_RISING_EDGE); + break; + case SND_SOC_DAIFMT_IB_IF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Invert BCLK + Invert Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_LEFTPOL_MASK + | SMA1307_SCK_RISING_MASK, + SMA1307_HIGH_FIRST_CH + | SMA1307_SCK_RISING_EDGE); + break; + case SND_SOC_DAIFMT_NB_IF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Normal BCLK + Invert Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_LEFTPOL_MASK, + SMA1307_HIGH_FIRST_CH); + break; + case SND_SOC_DAIFMT_NB_NF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Normal BCLK + Normal Frame"); + break; + default: + dev_err(component->dev, + "%s: Unsupported Bit & Frameclock : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + return 0; +} + +static int sma1307_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: slots = %d, slot_width - %d\n", + __func__, slots, slot_width); + + sma1307->frame_size = slot_width * slots; + + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, SMA1307_TDM_FORMAT); + + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_TX_MODE_MASK, + SMA1307_TDM_TX_MONO); + + switch (slot_width) { + case 16: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_DL_MASK, + SMA1307_TDM_DL_16); + break; + case 32: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_DL_MASK, + SMA1307_TDM_DL_32); + break; + default: + dev_err(component->dev, "%s: not support TDM %d slot_width\n", + __func__, slot_width); + return -EINVAL; + } + + switch (slots) { + case 4: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_N_SLOT_MASK, + SMA1307_TDM_N_SLOT_4); + break; + case 8: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_N_SLOT_MASK, + SMA1307_TDM_N_SLOT_8); + break; + default: + dev_err(component->dev, "%s: not support TDM %d slots\n", + __func__, slots); + return -EINVAL; + } + + if (sma1307->tdm_slot0_rx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_SLOT0_RX_POS_MASK, + sma1307->tdm_slot0_rx << 3); + else + dev_err(component->dev, "%s: Incorrect tdm-slot0-rx %d set\n", + __func__, sma1307->tdm_slot0_rx); + + if (sma1307->tdm_slot1_rx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_SLOT1_RX_POS_MASK, + sma1307->tdm_slot1_rx); + else + dev_err(component->dev, "%s: Incorrect tdm-slot1-rx %d set\n", + __func__, sma1307->tdm_slot1_rx); + + if (sma1307->tdm_slot0_tx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_SLOT0_TX_POS_MASK, + sma1307->tdm_slot0_tx << 3); + else + dev_err(component->dev, "%s: Incorrect tdm-slot0-tx %d set\n", + __func__, sma1307->tdm_slot0_tx); + + if (sma1307->tdm_slot1_tx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_SLOT1_TX_POS_MASK, + sma1307->tdm_slot1_tx); + else + dev_err(component->dev, "%s: Incorrect tdm-slot1-tx %d set\n", + __func__, sma1307->tdm_slot1_tx); + + return 0; +} + +static int sma1307_dai_mute_stream(struct snd_soc_dai *dai, int mute, + int stream) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + if (stream == SNDRV_PCM_STREAM_CAPTURE) + return 0; + if (mute) { + dev_dbg(component->dev, "%s: %s\n", __func__, "MUTE"); + regmap_update_bits(sma1307->regmap, + SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, + SMA1307_SPK_MUTE); + } else { + if (!sma1307->force_mute_status) { + dev_dbg(component->dev, "%s: %s\n", __func__, + "UNMUTE"); + regmap_update_bits(sma1307->regmap, + SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, + SMA1307_SPK_UNMUTE); + } else { + dev_dbg(sma1307->dev, "%s: FORCE MUTE!!!\n", __func__); + } + } + + return 0; +} + +static const struct snd_soc_dai_ops sma1307_dai_ops_amp = { + .hw_params = sma1307_dai_hw_params_amp, + .set_fmt = sma1307_dai_set_fmt_amp, + .set_sysclk = sma1307_dai_set_sysclk_amp, + .set_tdm_slot = sma1307_dai_set_tdm_slot, + .mute_stream = sma1307_dai_mute_stream, +}; + +#define SMA1307_RATES_PLAYBACK SNDRV_PCM_RATE_8000_96000 +#define SMA1307_RATES_CAPTURE SNDRV_PCM_RATE_8000_48000 +#define SMA1307_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver sma1307_dai[] = { + { + .name = "sma1307-amplifier", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SMA1307_RATES_PLAYBACK, + .formats = SMA1307_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SMA1307_RATES_CAPTURE, + .formats = SMA1307_FORMATS, + }, + .ops = &sma1307_dai_ops_amp, + }, +}; + +static void sma1307_check_fault_worker(struct work_struct *work) +{ + struct sma1307_priv *sma1307 = + container_of(work, struct sma1307_priv, check_fault_work.work); + unsigned int status1_val, status2_val; + char *envp[3] = { NULL, NULL, NULL }; + + if (sma1307->tsdw_cnt) + regmap_read(sma1307->regmap, + SMA1307_0A_SPK_VOL, &sma1307->cur_vol); + else + regmap_read(sma1307->regmap, + SMA1307_0A_SPK_VOL, &sma1307->init_vol); + + regmap_read(sma1307->regmap, SMA1307_FA_STATUS1, &status1_val); + regmap_read(sma1307->regmap, SMA1307_FB_STATUS2, &status2_val); + + if (~status1_val & SMA1307_OT1_OK_STATUS) { + dev_crit(sma1307->dev, + "%s: OT1(Over Temperature Level 1)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1"); + if (sma1307->sw_ot1_prot) { + /* Volume control (Current Volume -3dB) */ + if ((sma1307->cur_vol + 6) <= 0xFA) { + sma1307->cur_vol += 6; + regmap_write(sma1307->regmap, + SMA1307_0A_SPK_VOL, + sma1307->cur_vol); + envp[1] = kasprintf(GFP_KERNEL, + "VOLUME=0x%02X", sma1307->cur_vol); + } + } + sma1307->tsdw_cnt++; + } else if (sma1307->tsdw_cnt) { + regmap_write(sma1307->regmap, + SMA1307_0A_SPK_VOL, sma1307->init_vol); + sma1307->tsdw_cnt = 0; + sma1307->cur_vol = sma1307->init_vol; + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1_CLEAR"); + envp[1] = kasprintf(GFP_KERNEL, + "VOLUME=0x%02X", sma1307->cur_vol); + } + + if (~status1_val & SMA1307_OT2_OK_STATUS) { + dev_crit(sma1307->dev, + "%s: OT2(Over Temperature Level 2)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT2"); + } + if (status1_val & SMA1307_UVLO_STATUS) { + dev_crit(sma1307->dev, + "%s: UVLO(Under Voltage Lock Out)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=UVLO"); + } + if (status1_val & SMA1307_OVP_BST_STATUS) { + dev_crit(sma1307->dev, + "%s: OVP_BST(Over Voltage Protection)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OVP_BST"); + } + if (status2_val & SMA1307_OCP_SPK_STATUS) { + dev_crit(sma1307->dev, + "%s: OCP_SPK(Over Current Protect SPK)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_SPK"); + } + if (status2_val & SMA1307_OCP_BST_STATUS) { + dev_crit(sma1307->dev, + "%s: OCP_BST(Over Current Protect Boost)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_BST"); + } + if (status2_val & SMA1307_CLK_MON_STATUS) { + dev_crit(sma1307->dev, + "%s: CLK_FAULT(No clock input)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=CLK_FAULT"); + } + + if (envp[0] != NULL) { + if (kobject_uevent_env(sma1307->kobj, KOBJ_CHANGE, envp)) + dev_err(sma1307->dev, + "%s: Error sending uevent\n", __func__); + kfree(envp[0]); + kfree(envp[1]); + } + + if (sma1307->check_fault_status) { + if (sma1307->check_fault_period > 0) + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + sma1307->check_fault_period * HZ); + else + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + CHECK_PERIOD_TIME * HZ); + } +} + +static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file) +{ + const struct firmware *fw; + int *data, size, offset, num_mode; + int ret; + + ret = request_firmware(&fw, file, sma1307->dev); + + if (ret) { + dev_err(sma1307->dev, "%s: failed to read \"%s\": %pe\n", + __func__, setting_file, ERR_PTR(ret)); + sma1307->set.status = false; + return; + } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) { + dev_err(sma1307->dev, "%s: Invalid file\n", __func__); + release_firmware(fw); + sma1307->set.status = false; + return; + } + + data = kzalloc(fw->size, GFP_KERNEL); + size = fw->size >> 2; + memcpy(data, fw->data, fw->size); + + release_firmware(fw); + + /* HEADER */ + sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE; + sma1307->set.checksum = data[sma1307->set.header_size - 2]; + sma1307->set.num_mode = data[sma1307->set.header_size - 1]; + num_mode = sma1307->set.num_mode; + sma1307->set.header = devm_kzalloc(sma1307->dev, + sma1307->set.header_size, + GFP_KERNEL); + memcpy(sma1307->set.header, data, + sma1307->set.header_size * sizeof(int)); + + if ((sma1307->set.checksum >> 8) != SMA1307_SETTING_CHECKSUM) { + dev_err(sma1307->dev, "%s: failed by dismatch \"%s\"\n", + __func__, setting_file); + sma1307->set.status = false; + return; + } + + /* DEFAULT */ + sma1307->set.def_size = SMA1307_SETTING_DEFAULT_SIZE; + sma1307->set.def + = devm_kzalloc(sma1307->dev, + sma1307->set.def_size * sizeof(int), GFP_KERNEL); + memcpy(sma1307->set.def, + &data[sma1307->set.header_size], + sma1307->set.def_size * sizeof(int)); + + /* MODE */ + offset = sma1307->set.header_size + sma1307->set.def_size; + sma1307->set.mode_size = DIV_ROUND_CLOSEST(size - offset, num_mode + 1); + for (int i = 0; i < num_mode; i++) { + sma1307->set.mode_set[i] + = devm_kzalloc(sma1307->dev, + sma1307->set.mode_size * 2 * sizeof(int), + GFP_KERNEL); + for (int j = 0; j < sma1307->set.mode_size; j++) { + sma1307->set.mode_set[i][2 * j] + = data[offset + ((num_mode + 1) * j)]; + sma1307->set.mode_set[i][2 * j + 1] + = data[offset + ((num_mode + 1) * j + i + 1)]; + } + } + + kfree(data); + sma1307->set.status = true; + +} + +static void sma1307_reset(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int status = 0; + + regmap_read(sma1307->regmap, SMA1307_FF_DEVICE_INDEX, &status); + + sma1307->rev_num = status & SMA1307_REV_NUM_STATUS; + dev_dbg(component->dev, "%s: SMA1307 Revision %d\n", + __func__, sma1307->rev_num); + regmap_read(sma1307->regmap, SMA1307_99_OTP_TRM2, &sma1307->otp_trm2); + regmap_read(sma1307->regmap, SMA1307_9A_OTP_TRM3, &sma1307->otp_trm3); + + if ((sma1307->otp_trm2 & SMA1307_OTP_STAT_MASK) != SMA1307_OTP_STAT_1) + dev_warn(component->dev, "%s: SMA1307 OTP Status Fail\n", + __func__); + + /* Register Initial Value Setting */ + sma1307_setting_loaded(sma1307, setting_file); + if (sma1307->set.status) + sma1307_set_binary(component); + else + sma1307_set_default(component); + + regmap_update_bits(sma1307->regmap, + SMA1307_93_INT_CTRL, + SMA1307_DIS_INT_MASK, SMA1307_HIGH_Z_INT); + regmap_write(sma1307->regmap, SMA1307_0A_SPK_VOL, sma1307->init_vol); +} + +static void sma1307_set_binary(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int i = 0, mode = 0; + + for (i = 0; i < (sma1307->set.def_size); i++) { + if (sma1307_writeable_register(sma1307->dev, i) + && ((i < SMA1307_97_OTP_TRM0) + || (i > SMA1307_9A_OTP_TRM3))) { + regmap_write(sma1307->regmap, i, sma1307->set.def[i]); + + } + } + for (i = 0; i < (sma1307->set.mode_size); i++) { + if (sma1307_writeable_register(sma1307->dev, i) + && ((i < SMA1307_97_OTP_TRM0) + || (i > SMA1307_9A_OTP_TRM3))) { + mode = sma1307->binary_mode; + regmap_write(sma1307->regmap, + sma1307->set.mode_set[mode][2 * i], + sma1307->set.mode_set[mode][2 * i + + 1]); + } + } +} + +static void sma1307_set_default(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int i = 0; + + for (i = 0; i < (unsigned int)ARRAY_SIZE(sma1307_reg_def); i++) + regmap_write(sma1307->regmap, + sma1307_reg_def[i].reg, + sma1307_reg_def[i].def); + + if (!strcmp(sma1307->name, DEVICE_NAME_SMA1307AQ)) + sma1307->data->init(sma1307->regmap); +} + +static int sma1307_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + snd_soc_dapm_sync(dapm); + + sma1307_amp_component = component; + + snd_soc_add_component_controls(component, sma1307_binary_mode_control, + ARRAY_SIZE(sma1307_binary_mode_control)); + sma1307_reset(component); + + return 0; +} + +static const struct snd_soc_component_driver sma1307_component = { + .probe = sma1307_probe, + .controls = sma1307_snd_controls, + .num_controls = ARRAY_SIZE(sma1307_snd_controls), + .dapm_widgets = sma1307_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sma1307_dapm_widgets), + .dapm_routes = sma1307_audio_map, + .num_dapm_routes = ARRAY_SIZE(sma1307_audio_map), +}; + +static const struct regmap_config sma_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SMA1307_FF_DEVICE_INDEX, + .readable_reg = sma1307_readable_register, + .writeable_reg = sma1307_writeable_register, + .volatile_reg = sma1307_volatile_register, + + .reg_defaults = sma1307_reg_def, + .num_reg_defaults = ARRAY_SIZE(sma1307_reg_def), +}; + +static void sma1307aq_init(struct regmap *regmap) +{ + /* Guidelines for driving 4ohm load */ + /* Brown Out Protection */ + regmap_write(regmap, SMA1307_02_BROWN_OUT_PROT1, 0x62); + regmap_write(regmap, SMA1307_03_BROWN_OUT_PROT2, 0x5D); + regmap_write(regmap, SMA1307_04_BROWN_OUT_PROT3, 0x57); + regmap_write(regmap, SMA1307_05_BROWN_OUT_PROT8, 0x54); + regmap_write(regmap, SMA1307_06_BROWN_OUT_PROT9, 0x51); + regmap_write(regmap, + SMA1307_07_BROWN_OUT_PROT10, 0x4D); + regmap_write(regmap, + SMA1307_08_BROWN_OUT_PROT11, 0x4B); + regmap_write(regmap, SMA1307_27_BROWN_OUT_PROT4, 0x3C); + regmap_write(regmap, SMA1307_28_BROWN_OUT_PROT5, 0x5B); + regmap_write(regmap, + SMA1307_29_BROWN_OUT_PROT12, 0x78); + regmap_write(regmap, + SMA1307_2A_BROWN_OUT_PROT13, 0x96); + regmap_write(regmap, + SMA1307_2B_BROWN_OUT_PROT14, 0xB4); + regmap_write(regmap, + SMA1307_2C_BROWN_OUT_PROT15, 0xD3); + /* FDPEC Gain */ + regmap_write(regmap, SMA1307_35_FDPEC_CTRL0, 0x16); + /* FLT Vdd */ + regmap_write(regmap, SMA1307_92_FDPEC_CTRL1, 0xA0); + /* Boost Max */ + regmap_write(regmap, SMA1307_AB_BOOST_CTRL4, 0x0F); +} + +static const struct sma1307_data sma1307aq_data = { + .name = DEVICE_NAME_SMA1307AQ, + .init = sma1307aq_init, +}; + +static int sma1307_i2c_probe(struct i2c_client *client) +{ + struct sma1307_priv *sma1307; + const struct sma1307_data *data; + int ret = 0; + unsigned int device_info; + + sma1307 = devm_kzalloc(&client->dev, + sizeof(*sma1307), GFP_KERNEL); + if (!sma1307) + return -ENOMEM; + + sma1307->regmap = devm_regmap_init_i2c(client, &sma_i2c_regmap); + if (IS_ERR(sma1307->regmap)) { + return dev_err_probe(&client->dev, PTR_ERR(sma1307->regmap), + "%s: failed to allocate register map\n", __func__); + } + + data = device_get_match_data(&client->dev); + if (!data) + return -ENODEV; + + sma1307->data = data; + + /* set initial value as normal AMP IC status */ + sma1307->name = client->name; + sma1307->format = SND_SOC_DAIFMT_I2S; + sma1307->sys_clk_id = SMA1307_PLL_CLKIN_BCLK; + sma1307->num_of_pll_matches = ARRAY_SIZE(sma1307_pll_matches); + + sma1307->check_fault_period = CHECK_PERIOD_TIME; + sma1307->check_fault_status = true; + sma1307->init_vol = 0x32; + sma1307->cur_vol = sma1307->init_vol; + sma1307->sw_ot1_prot = true; + + mutex_init(&sma1307->default_lock); + + INIT_DELAYED_WORK(&sma1307->check_fault_work, + sma1307_check_fault_worker); + + sma1307->dev = &client->dev; + sma1307->kobj = &client->dev.kobj; + + i2c_set_clientdata(client, sma1307); + + sma1307->pll_matches = sma1307_pll_matches; + + regmap_read(sma1307->regmap, + SMA1307_FF_DEVICE_INDEX, &device_info); + + if ((device_info & 0xF8) != SMA1307_DEVICE_ID) { + dev_err(&client->dev, + "%s: device initialization error (0x%02X)", + __func__, device_info); + return -ENODEV; + } + dev_dbg(&client->dev, "%s: chip version 0x%02X\n", + __func__, device_info); + + i2c_set_clientdata(client, sma1307); + + ret = devm_snd_soc_register_component(&client->dev, + &sma1307_component, sma1307_dai, + 1); + + if (ret) { + dev_err(&client->dev, "%s: failed to register component\n", + __func__); + + return ret; + } + + return ret; +} + +static void sma1307_i2c_remove(struct i2c_client *client) +{ + struct sma1307_priv *sma1307 = + (struct sma1307_priv *)i2c_get_clientdata(client); + + cancel_delayed_work_sync(&sma1307->check_fault_work); +} + +static const struct i2c_device_id sma1307_i2c_id[] = { + { "sma1307a", 0 }, + { "sma1307aq", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, sma1307_i2c_id); + +static const struct of_device_id sma1307_of_match[] = { + { + .compatible = "irondevice,sma1307a", + }, + { + .compatible = "irondevice,sma1307aq", + .data = &sma1307aq_data //AEC-Q100 Qualificated + }, + { } +}; + +MODULE_DEVICE_TABLE(of, sma1307_of_match); + +static struct i2c_driver sma1307_i2c_driver = { + .driver = { + .name = "sma1307", + .of_match_table = sma1307_of_match, + }, + .probe = sma1307_i2c_probe, + .remove = sma1307_i2c_remove, + .id_table = sma1307_i2c_id, +}; + +module_i2c_driver(sma1307_i2c_driver); + +MODULE_DESCRIPTION("ALSA SoC SMA1307 driver"); +MODULE_AUTHOR("Gyuhwa Park, <gyuhwa.park@irondevice.com>"); +MODULE_AUTHOR("KS Jo, <kiseok.jo@irondevice.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sma1307.h b/sound/soc/codecs/sma1307.h new file mode 100644 index 000000000000..44aab52a32f9 --- /dev/null +++ b/sound/soc/codecs/sma1307.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * sma1307.h -- sma1307 ALSA SoC Audio driver + * + * Copyright 2024 Iron Device Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _SMA1307_H +#define _SMA1307_H + +#include <sound/soc.h> + +enum sma1307_fault { + SMA1307_FAULT_OT1, + SMA1307_FAULT_OT2, + SMA1307_FAULT_UVLO, + SMA1307_FAULT_OVP_BST, + SMA1307_FAULT_OCP_SPK, + SMA1307_FAULT_OCP_BST, + SMA1307_FAULT_CLK +}; + +enum sma1307_mode { + SMA1307_MONO_MODE, + SMA1307_LEFT_MODE, + SMA1307_RIGHT_MODE, +}; + +enum sma1307_sdo_mode { + SMA1307_OUT_DATA_ONE_48K, + SMA1307_OUT_DATA_TWO_48K, + SMA1307_OUT_DATA_TWO_24K, + SMA1307_OUT_CLK_PLL, + SMA1307_OUT_CLK_OSC +}; + +enum sma1307_sdo_source { + SMA1307_OUT_DISABLE, + SMA1307_OUT_FORMAT_C, + SMA1307_OUT_MIXER_OUT, + SMA1307_OUT_AFTER_DSP, + SMA1307_OUT_VRMS2_AVG, + SMA1307_OUT_BATTERY, + SMA1307_OUT_TEMP, + SMA1307_OUT_AFTER_DELAY +}; + +struct sma1307_setting_file { + bool status; + char *header; + int *def; + int *mode_set[5]; + int checksum; + int num_mode; + size_t header_size; + size_t def_size; + size_t mode_size; +}; + +#define SMA1307_I2C_ADDR_00 0x1e +#define SMA1307_I2C_ADDR_01 0x3e +#define SMA1307_I2C_ADDR_10 0x5e +#define SMA1307_I2C_ADDR_11 0x7e + +#define DEVICE_NAME_SMA1307A "sma1307a" +#define DEVICE_NAME_SMA1307AQ "sma1307aq" + +#define SMA1307_EXTERNAL_CLOCK_19_2 0x00 +#define SMA1307_EXTERNAL_CLOCK_24_576 0x01 +#define SMA1307_PLL_CLKIN_MCLK 0x02 +#define SMA1307_PLL_CLKIN_BCLK 0x03 + +#define SMA1307_OFFSET_DEFAULT_MODE 0x00 +#define SMA1307_OFFSET_BURNING_MODE 0x01 + +#define SMA1307_SETTING_HEADER_SIZE 0x08 +#define SMA1307_SETTING_DEFAULT_SIZE 0xC0 + +#define SMA1307_DEFAULT_SET 0x00 +#define SMA1307_BINARY_FILE_SET 0x01 + +/* Controls Name */ +#define SMA1307_REG_CTRL_NAME "Register Byte Control" +#define SMA1307_VOL_CTRL_NAME "Speaker Volume" +#define SMA1307_FORCE_MUTE_CTRL_NAME "Force Mute Switch" +#define SMA1307_TDM_RX0_POS_NAME "TDM RX Slot0 Position" +#define SMA1307_TDM_RX1_POS_NAME "TDM RX Slot1 Position" +#define SMA1307_TDM_TX0_POS_NAME "TDM TX Slot0 Position" +#define SMA1307_TDM_TX1_POS_NAME "TDM TX Slot1 Position" +#define SMA1307_OT1_SW_PROT_CTRL_NAME "OT1 SW Protection Switch" +#define SMA1307_RESET_CTRL_NAME "Reset Switch" +#define SMA1307_CHECK_FAULT_STATUS_NAME "Check Fault Status" +#define SMA1307_CHECK_FAULT_PERIOD_NAME "Check Fault Period" + +/* DAPM Name */ +#define SMA1307_AIF_IN_NAME "AIF IN Source" +#define SMA1307_AIF_OUT0_NAME "AIF OUT0 Source" +#define SMA1307_AIF_OUT1_NAME "AIF OUT1 Source" + +/* + * SMA1307 Register Definition + */ + +/* SMA1307 Register Addresses */ +#define SMA1307_00_SYSTEM_CTRL 0x00 +#define SMA1307_01_INPUT_CTRL1 0x01 +#define SMA1307_02_BROWN_OUT_PROT1 0x02 +#define SMA1307_03_BROWN_OUT_PROT2 0x03 +#define SMA1307_04_BROWN_OUT_PROT3 0x04 +#define SMA1307_05_BROWN_OUT_PROT8 0x05 +#define SMA1307_06_BROWN_OUT_PROT9 0x06 +#define SMA1307_07_BROWN_OUT_PROT10 0x07 +#define SMA1307_08_BROWN_OUT_PROT11 0x08 +#define SMA1307_09_OUTPUT_CTRL 0x09 +#define SMA1307_0A_SPK_VOL 0x0A +#define SMA1307_0B_BST_TEST 0x0B +#define SMA1307_0C_BOOST_CTRL8 0x0C +#define SMA1307_0D_SPK_TEST 0x0D +#define SMA1307_0E_MUTE_VOL_CTRL 0x0E +#define SMA1307_0F_VBAT_TEMP_SENSING 0x0F + +#define SMA1307_10_SYSTEM_CTRL1 0x10 +#define SMA1307_11_SYSTEM_CTRL2 0x11 +#define SMA1307_12_SYSTEM_CTRL3 0x12 +#define SMA1307_13_DELAY 0x13 +#define SMA1307_14_MODULATOR 0x14 +#define SMA1307_15_BASS_SPK1 0x15 +#define SMA1307_16_BASS_SPK2 0x16 +#define SMA1307_17_BASS_SPK3 0x17 +#define SMA1307_18_BASS_SPK4 0x18 +#define SMA1307_19_BASS_SPK5 0x19 +#define SMA1307_1A_BASS_SPK6 0x1A +#define SMA1307_1B_BASS_SPK7 0x1B +#define SMA1307_1C_BROWN_OUT_PROT20 0x1C +#define SMA1307_1D_BROWN_OUT_PROT0 0x1D +#define SMA1307_1E_TONE_GENERATOR 0x1E +#define SMA1307_1F_TONE_FINE_VOLUME 0x1F + +#define SMA1307_22_COMP_HYS_SEL 0x22 +#define SMA1307_23_COMPLIM1 0x23 +#define SMA1307_24_COMPLIM2 0x24 +#define SMA1307_25_COMPLIM3 0x25 +#define SMA1307_26_COMPLIM4 0x26 +#define SMA1307_27_BROWN_OUT_PROT4 0x27 +#define SMA1307_28_BROWN_OUT_PROT5 0x28 +#define SMA1307_29_BROWN_OUT_PROT12 0x29 +#define SMA1307_2A_BROWN_OUT_PROT13 0x2A +#define SMA1307_2B_BROWN_OUT_PROT14 0x2B +#define SMA1307_2C_BROWN_OUT_PROT15 0x2C +#define SMA1307_2D_BROWN_OUT_PROT6 0x2D +#define SMA1307_2E_BROWN_OUT_PROT7 0x2E +#define SMA1307_2F_BROWN_OUT_PROT16 0x2F + +#define SMA1307_30_BROWN_OUT_PROT17 0x30 +#define SMA1307_31_BROWN_OUT_PROT18 0x31 +#define SMA1307_32_BROWN_OUT_PROT19 0x32 +#define SMA1307_34_OCP_SPK 0x34 +#define SMA1307_35_FDPEC_CTRL0 0x35 +#define SMA1307_36_PROTECTION 0x36 +#define SMA1307_37_SLOPECTRL 0x37 +#define SMA1307_38_POWER_METER 0x38 +#define SMA1307_39_PMT_NZ_VAL 0x39 +#define SMA1307_3B_TEST1 0x3B +#define SMA1307_3C_TEST2 0x3C +#define SMA1307_3D_TEST3 0x3D +#define SMA1307_3E_IDLE_MODE_CTRL 0x3E +#define SMA1307_3F_ATEST2 0x3F +#define SMA1307_8B_PLL_POST_N 0x8B +#define SMA1307_8C_PLL_N 0x8C +#define SMA1307_8D_PLL_A_SETTING 0x8D +#define SMA1307_8E_PLL_P_CP 0x8E +#define SMA1307_8F_ANALOG_TEST 0x8F + +#define SMA1307_90_CRESTLIM1 0x90 +#define SMA1307_91_CRESTLIM2 0x91 +#define SMA1307_92_FDPEC_CTRL1 0x92 +#define SMA1307_93_INT_CTRL 0x93 +#define SMA1307_94_BOOST_CTRL9 0x94 +#define SMA1307_95_BOOST_CTRL10 0x95 +#define SMA1307_96_BOOST_CTRL11 0x96 +#define SMA1307_97_OTP_TRM0 0x97 +#define SMA1307_98_OTP_TRM1 0x98 +#define SMA1307_99_OTP_TRM2 0x99 +#define SMA1307_9A_OTP_TRM3 0x9A + +#define SMA1307_A0_PAD_CTRL0 0xA0 +#define SMA1307_A1_PAD_CTRL1 0xA1 +#define SMA1307_A2_TOP_MAN1 0xA2 +#define SMA1307_A3_TOP_MAN2 0xA3 +#define SMA1307_A4_TOP_MAN3 0xA4 +#define SMA1307_A5_TDM1 0xA5 +#define SMA1307_A6_TDM2 0xA6 +#define SMA1307_A7_CLK_MON 0xA7 +#define SMA1307_A8_BOOST_CTRL1 0xA8 +#define SMA1307_A9_BOOST_CTRL2 0xA9 +#define SMA1307_AA_BOOST_CTRL3 0xAA +#define SMA1307_AB_BOOST_CTRL4 0xAB +#define SMA1307_AC_BOOST_CTRL5 0xAC +#define SMA1307_AD_BOOST_CTRL6 0xAD +#define SMA1307_AE_BOOST_CTRL7 0xAE +#define SMA1307_AF_LPF 0xAF + +#define SMA1307_B0_RMS_TC1 0xB0 +#define SMA1307_B1_RMS_TC2 0xB1 +#define SMA1307_B2_AVG_TC1 0xB2 +#define SMA1307_B3_AVG_TC2 0xB3 +#define SMA1307_B4_PRVALUE1 0xB4 +#define SMA1307_B5_PRVALUE2 0xB5 +#define SMA1307_B8_SPK_NG_CTRL1 0xB8 +#define SMA1307_B9_SPK_NG_CTRL2 0xB9 +#define SMA1307_BA_DGC1 0xBA +#define SMA1307_BB_DGC2 0xBB +#define SMA1307_BC_DGC3 0xBC +#define SMA1307_BD_MCBS_CTRL1 0xBD +#define SMA1307_BE_MCBS_CTRL2 0xBE + +/* Status Register Read Only */ +#define SMA1307_F5_READY_FOR_V_SAR 0xF5 +#define SMA1307_F7_READY_FOR_T_SAR 0xF7 +#define SMA1307_F8_STATUS_T1 0xF8 +#define SMA1307_F9_STATUS_T2 0xF9 +#define SMA1307_FA_STATUS1 0xFA +#define SMA1307_FB_STATUS2 0xFB +#define SMA1307_FC_STATUS3 0xFC +#define SMA1307_FD_STATUS4 0xFD +#define SMA1307_FE_STATUS5 0xFE +#define SMA1307_FF_DEVICE_INDEX 0xFF + +/* SMA1307 Registers Bit Fields */ +/* Power On/Off */ +#define SMA1307_POWER_MASK BIT(0) +#define SMA1307_POWER_OFF 0 +#define SMA1307_POWER_ON BIT(0) + +/* Reset */ +#define SMA1307_RESET_MASK BIT(1) +#define SMA1307_RESET_ON BIT(1) + +/* Left Polarity */ +#define SMA1307_LEFTPOL_MASK BIT(3) +#define SMA1307_LOW_FIRST_CH 0 +#define SMA1307_HIGH_FIRST_CH BIT(3) + +/* SCK Falling/Rising */ +#define SMA1307_SCK_RISING_MASK BIT(2) +#define SMA1307_SCK_FALLING_EDGE 0 +#define SMA1307_SCK_RISING_EDGE BIT(2) + +/* SPK Mute */ +#define SMA1307_SPK_MUTE_MASK BIT(0) +#define SMA1307_SPK_UNMUTE 0 +#define SMA1307_SPK_MUTE BIT(0) + +/* SPK Mode */ +#define SMA1307_SPK_MODE_MASK (BIT(2)|BIT(3)|BIT(4)) +#define SMA1307_SPK_OFF 0 +#define SMA1307_SPK_MONO BIT(2) +#define SMA1307_SPK_STEREO BIT(4) + +/* Mono Mix */ +#define SMA1307_MONOMIX_MASK BIT(0) +#define SMA1307_MONOMIX_OFF 0 +#define SMA1307_MONOMIX_ON BIT(0) + +/* LR Data Swap */ +#define SMA1307_LR_DATA_SW_MASK BIT(4) +#define SMA1307_LR_DATA_SW_NORMAL 0 +#define SMA1307_LR_DATA_SW_SWAP BIT(4) + +/* PLL On/Off */ +#define SMA1307_PLL_MASK BIT(6) +#define SMA1307_PLL_ON 0 +#define SMA1307_PLL_OFF BIT(6) + +/* Input Format */ +#define SMA1307_I2S_MODE_MASK (BIT(4)|BIT(5)|BIT(6)) +#define SMA1307_STANDARD_I2S 0 +#define SMA1307_LJ BIT(4) +#define SMA1307_RJ_16BIT BIT(6) +#define SMA1307_RJ_18BIT (BIT(4)|BIT(6)) +#define SMA1307_RJ_20BIT (BIT(5)|BIT(6)) +#define SMA1307_RJ_24BIT (BIT(4)|BIT(5)|BIT(6)) + +/* Controller / Device Setting */ +#define SMA1307_CONTROLLER_DEVICE_MASK BIT(7) +#define SMA1307_DEVICE_MODE 0 +#define SMA1307_CONTROLLER_MODE BIT(7) + +/* Port Config */ +#define SMA1307_PORT_CONFIG_MASK (BIT(6)|BIT(7)) +#define SMA1307_INPUT_PORT_ONLY 0 +#define SMA1307_OUTPUT_PORT_ENABLE BIT(7) + +/* SDO Output */ +#define SMA1307_SDO_OUTPUT_MASK BIT(3) +#define SMA1307_LOGIC_OUTPUT 0 +#define SMA1307_HIGH_Z_OUTPUT BIT(3) + +#define SMA1307_DATA_CLK_SEL_MASK (BIT(6)|BIT(7)) +#define SMA1307_SDO_DATA 0 +#define SMA1307_SDO_CLK_PLL BIT(6) +#define SMA1307_SDO_CLK_OSC (BIT(6)|BIT(7)) + +/* SDO Output2 */ +#define SMA1307_SDO_OUTPUT2_MASK BIT(0) +#define SMA1307_ONE_SDO_PER_CH 0 +#define SMA1307_TWO_SDO_PER_CH BIT(0) + +/* SDO Output3 */ +#define SMA1307_SDO_OUTPUT3_MASK BIT(2) +#define SMA1307_SDO_OUTPUT3_DIS 0 +#define SMA1307_TWO_SDO_PER_CH_24K BIT(2) + +/* SDO OUT1 Select*/ +#define SMA1307_SDO_OUT1_SEL_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_SDO1_DISABLE 0 +#define SMA1307_SDO1_FORMAT_C BIT(3) +#define SMA1307_SDO1_MONO_MIX BIT(4) +#define SMA1307_SDO1_AFTER_DSP (BIT(3)|BIT(4)) +#define SMA1307_SDO1_VRMS2_AVG BIT(5) +#define SMA1307_SDO1_VBAT_MON (BIT(3)|BIT(5)) +#define SMA1307_SDO1_TEMP_MON (BIT(4)|BIT(5)) +#define SMA1307_SDO1_AFTER_DELAY (BIT(3)|BIT(4)|BIT(5)) + +/* SDO OUT0 Select*/ +#define SMA1307_SDO_OUT0_SEL_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_SDO0_DISABLE 0 +#define SMA1307_SDO0_FORMAT_C BIT(0) +#define SMA1307_SDO0_MONO_MIX BIT(1) +#define SMA1307_SDO0_AFTER_DSP (BIT(0)|BIT(1)) +#define SMA1307_SDO0_VRMS2_AVG BIT(2) +#define SMA1307_SDO0_VBAT_MON (BIT(0)|BIT(2)) +#define SMA1307_SDO0_TEMP_MON (BIT(1)|BIT(2)) +#define SMA1307_SDO0_AFTER_DELAY (BIT(0)|BIT(1)|BIT(2)) + +/* INTERRUPT Operation */ +#define SMA1307_SEL_INT_MASK BIT(2) +#define SMA1307_INT_CLEAR_AUTO 0 +#define SMA1307_INT_CLEAR_MANUAL BIT(2) + +/* INTERRUPT CLEAR */ +#define SMA1307_CLR_INT_MASK BIT(1) +#define SMA1307_INT_READY 0 +#define SMA1307_INT_CLEAR BIT(1) + +/* INTERRUPT Disable */ +#define SMA1307_DIS_INT_MASK BIT(0) +#define SMA1307_NORMAL_INT 0 +#define SMA1307_HIGH_Z_INT BIT(0) + +/* Interface Control */ +#define SMA1307_INTERFACE_MASK (BIT(5)|BIT(6)|BIT(7)) +#define SMA1307_LJ_FORMAT BIT(5) +#define SMA1307_I2S_FORMAT (BIT(5)|BIT(6)) +#define SMA1307_TDM_FORMAT BIT(7) + +#define SMA1307_SCK_RATE_MASK (BIT(3)|BIT(4)) +#define SMA1307_SCK_64FS 0 +#define SMA1307_SCK_32FS BIT(4) + +#define SMA1307_DATA_WIDTH_MASK (BIT(1)|BIT(2)) +#define SMA1307_DATA_24BIT 0 +#define SMA1307_DATA_16BIT (BIT(1)|BIT(2)) + +#define SMA1307_TDM_TX_MODE_MASK BIT(6) +#define SMA1307_TDM_TX_MONO 0 +#define SMA1307_TDM_TX_STEREO BIT(6) + +#define SMA1307_TDM_SLOT0_RX_POS_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_0 0 +#define SMA1307_TDM_SLOT0_RX_POS_1 BIT(3) +#define SMA1307_TDM_SLOT0_RX_POS_2 BIT(4) +#define SMA1307_TDM_SLOT0_RX_POS_3 (BIT(3)|BIT(4)) +#define SMA1307_TDM_SLOT0_RX_POS_4 BIT(5) +#define SMA1307_TDM_SLOT0_RX_POS_5 (BIT(3)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_6 (BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_7 (BIT(3)|BIT(4)|BIT(5)) + +#define SMA1307_TDM_SLOT1_RX_POS_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_0 0 +#define SMA1307_TDM_SLOT1_RX_POS_1 BIT(0) +#define SMA1307_TDM_SLOT1_RX_POS_2 BIT(1) +#define SMA1307_TDM_SLOT1_RX_POS_3 (BIT(0)|BIT(1)) +#define SMA1307_TDM_SLOT1_RX_POS_4 BIT(2) +#define SMA1307_TDM_SLOT1_RX_POS_5 (BIT(0)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_6 (BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_7 (BIT(0)|BIT(1)|BIT(2)) + +/* TDM2 FORMAT : 0xA6 */ +#define SMA1307_TDM_DL_MASK BIT(7) +#define SMA1307_TDM_DL_16 0 +#define SMA1307_TDM_DL_32 BIT(7) + +#define SMA1307_TDM_N_SLOT_MASK BIT(6) +#define SMA1307_TDM_N_SLOT_4 0 +#define SMA1307_TDM_N_SLOT_8 BIT(6) + +#define SMA1307_TDM_SLOT0_TX_POS_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_0 0 +#define SMA1307_TDM_SLOT0_TX_POS_1 BIT(3) +#define SMA1307_TDM_SLOT0_TX_POS_2 BIT(4) +#define SMA1307_TDM_SLOT0_TX_POS_3 (BIT(3)|BIT(4)) +#define SMA1307_TDM_SLOT0_TX_POS_4 BIT(5) +#define SMA1307_TDM_SLOT0_TX_POS_5 (BIT(3)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_6 (BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_7 (BIT(3)|BIT(4)|BIT(5)) + +#define SMA1307_TDM_SLOT1_TX_POS_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_0 0 +#define SMA1307_TDM_SLOT1_TX_POS_1 BIT(0) +#define SMA1307_TDM_SLOT1_TX_POS_2 BIT(1) +#define SMA1307_TDM_SLOT1_TX_POS_3 (BIT(0)|BIT(1)) +#define SMA1307_TDM_SLOT1_TX_POS_4 BIT(2) +#define SMA1307_TDM_SLOT1_TX_POS_5 (BIT(0)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_6 (BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_7 (BIT(0)|BIT(1)|BIT(2)) + +/* OTP STATUS */ +#define SMA1307_OTP_STAT_MASK BIT(6) +#define SMA1307_OTP_STAT_0 0 +#define SMA1307_OTP_STAT_1 BIT(6) + +/* STATUS */ +#define SMA1307_OT1_OK_STATUS BIT(7) +#define SMA1307_OT2_OK_STATUS BIT(6) +#define SMA1307_UVLO_STATUS BIT(5) +#define SMA1307_OVP_BST_STATUS BIT(4) +#define SMA1307_POWER_FLAG BIT(3) + +#define SMA1307_SCAN_CHK BIT(7) +#define SMA1307_OCP_SPK_STATUS BIT(5) +#define SMA1307_OCP_BST_STATUS BIT(4) +#define SMA1307_BOP_STATE (BIT(1)|BIT(2)|BIT(3)) +#define SMA1307_CLK_MON_STATUS BIT(0) + +#define SMA1307_DEVICE_ID (BIT(3)|BIT(4)) +#define SMA1307_REV_NUM_STATUS (BIT(0)|BIT(1)) +#define SMA1307_REV_NUM_REV0 0 +#define SMA1307_REV_NUM_REV1 BIT(0) + +#endif diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 310123d2bb5f..c9766979b1d7 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dir_routes[] = { SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) -static struct snd_soc_component_driver soc_codec_spdif_dir = { +static const struct snd_soc_component_driver soc_codec_spdif_dir = { .dapm_widgets = dir_widgets, .num_dapm_widgets = ARRAY_SIZE(dir_widgets), .dapm_routes = dir_routes, diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index db51a46e689d..2409fd834f84 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { { "spdif-out", NULL, "Playback" }, }; -static struct snd_soc_component_driver soc_codec_spdif_dit = { +static const struct snd_soc_component_driver soc_codec_spdif_dit = { .dapm_widgets = dit_widgets, .num_dapm_widgets = ARRAY_SIZE(dit_widgets), .dapm_routes = dit_routes, diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 12d093437ba9..e41f81eb8d16 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -650,7 +650,6 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, (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; @@ -659,9 +658,7 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, @@ -673,7 +670,6 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, (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; @@ -681,9 +677,7 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, 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; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, @@ -696,7 +690,6 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, (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); @@ -707,9 +700,7 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, else return -1; dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, @@ -721,13 +712,10 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, (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; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, @@ -739,13 +727,10 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, (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; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_nop_get( @@ -1115,14 +1100,12 @@ static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol, 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; + int max = tas_priv->ndev - 1; dev_id = clamp(dev_id, 0, max); guard(mutex)(&tas_priv->codec_lock); - rc = tasdev_chn_switch(tas_priv, dev_id); - - return rc; + return tasdev_chn_switch(tas_priv, dev_id); } static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) @@ -1339,10 +1322,8 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) i++; } - rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, + return snd_soc_add_component_controls(priv->codec, cali_ctrls, nctrls < i ? nctrls : i); - - return rc; } static void tasdevice_fw_ready(const struct firmware *fmw, diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index 3b53eba38a0b..4c32500eef3e 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -474,7 +474,7 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) return ret; } - tas5805m = devm_kzalloc(dev, sizeof(struct tas5805m_priv), GFP_KERNEL); + tas5805m = devm_kzalloc(dev, sizeof(*tas5805m), GFP_KERNEL); if (!tas5805m) return -ENOMEM; diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index bb0500e9d3ea..9be054837f68 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -364,7 +364,7 @@ static int tas6424_set_bias_level(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver soc_codec_dev_tas6424 = { +static const struct snd_soc_component_driver soc_codec_dev_tas6424 = { .set_bias_level = tas6424_set_bias_level, .controls = tas6424_snd_controls, .num_controls = ARRAY_SIZE(tas6424_snd_controls), diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 7073b9d1cda8..868e8a91e05b 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -961,7 +961,7 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) if (offset >= ADC3XXX_GPIOS_MAX) return -EINVAL; - if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) { + if (offset < ADC3XXX_GPIO_PINS) { /* GPIO1 is offset 0, GPIO2 is offset 1 */ /* We check here that the GPIO pins are either not configured * in the DT, or that they purposely are set as outputs. diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 9c50ac356c89..e3782762139f 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -555,7 +555,7 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = * On unmute: restore the register content from the reg_cache * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R */ -#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ +#define TWL4030_OUTPUT_PGA(pin_name, reg) \ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ struct snd_kcontrol *kcontrol, int event) \ { \ @@ -575,11 +575,11 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ return 0; \ } -TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN); -TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN); -TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN); -TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN); -TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN); +TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL); +TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL); +TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL); +TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL); +TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL); static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp) { diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c new file mode 100644 index 000000000000..3d49a7869948 --- /dev/null +++ b/sound/soc/codecs/uda1342.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// uda1342.c -- UDA1342 ALSA SoC Codec driver +// Based on the WM87xx drivers by Liam Girdwood and Richard Purdie +// +// Copyright 2007 Dension Audio Systems Ltd. +// Copyright 2024 Loongson Technology Co.,Ltd. +// +// Modifications by Christian Pellegrin <chripell@evolware.org> +// Further cleanup and restructuring by: +// Binbin Zhou <zhoubinbin@loongson.cn> + +#include <linux/module.h> +#include <linux/i2c.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "uda1342.h" + +#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) + +struct uda1342_priv { + int sysclk; + int dai_fmt; + + struct snd_pcm_substream *provider_substream; + struct snd_pcm_substream *consumer_substream; + + struct regmap *regmap; + struct i2c_client *i2c; +}; + +static const struct reg_default uda1342_reg_defaults[] = { + { 0x00, 0x1042 }, + { 0x01, 0x0000 }, + { 0x10, 0x0088 }, + { 0x11, 0x0000 }, + { 0x12, 0x0000 }, + { 0x20, 0x0080 }, + { 0x21, 0x0080 }, +}; + +static int uda1342_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + unsigned int mask; + unsigned int val = 0; + + /* Master mute */ + mask = BIT(5); + if (mute) + val = mask; + + return regmap_update_bits(uda1342->regmap, 0x10, mask, val); +} + +static int uda1342_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct snd_pcm_runtime *provider_runtime; + + if (uda1342->provider_substream) { + provider_runtime = uda1342->provider_substream->runtime; + + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, provider_runtime->rate); + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + provider_runtime->sample_bits); + + uda1342->consumer_substream = substream; + } else { + uda1342->provider_substream = substream; + } + + return 0; +} + +static void uda1342_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + + if (uda1342->provider_substream == substream) + uda1342->provider_substream = uda1342->consumer_substream; + + uda1342->consumer_substream = NULL; +} + +static int uda1342_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct device *dev = &uda1342->i2c->dev; + unsigned int hw_params = 0; + + if (substream == uda1342->consumer_substream) + return 0; + + /* set SYSCLK / fs ratio */ + switch (uda1342->sysclk / params_rate(params)) { + case 512: + break; + case 384: + hw_params |= BIT(4); + break; + case 256: + hw_params |= BIT(5); + break; + default: + dev_err(dev, "unsupported frequency\n"); + return -EINVAL; + } + + /* set DAI format and word length */ + switch (uda1342->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + hw_params |= BIT(1); + break; + case 18: + hw_params |= BIT(2); + break; + case 20: + hw_params |= BIT(2) | BIT(1); + break; + default: + dev_err(dev, "unsupported format (right)\n"); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_LEFT_J: + hw_params |= BIT(3); + break; + default: + dev_err(dev, "unsupported format\n"); + return -EINVAL; + } + + return regmap_update_bits(uda1342->regmap, 0x0, + STATUS0_DAIFMT_MASK | STATUS0_SYSCLK_MASK, hw_params); +} + +static int uda1342_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct device *dev = &uda1342->i2c->dev; + + /* + * Anything between 256fs*8Khz and 512fs*48Khz should be acceptable + * because the codec is slave. Of course limitations of the clock + * master (the IIS controller) apply. + * We'll error out on set_hw_params if it's not OK + */ + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + uda1342->sysclk = freq; + return 0; + } + + dev_err(dev, "unsupported sysclk\n"); + + return -EINVAL; +} + +static int uda1342_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + + /* codec supports only full consumer mode */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) { + dev_err(&uda1342->i2c->dev, "unsupported consumer mode.\n"); + return -EINVAL; + } + + /* We can't setup DAI format here as it depends on the word bit num */ + /* so let's just store the value for later */ + uda1342->dai_fmt = fmt; + + return 0; +} + +static const struct snd_kcontrol_new uda1342_snd_controls[] = { + SOC_SINGLE("Master Playback Volume", 0x11, 0, 0x3F, 1), + SOC_SINGLE("Analog1 Volume", 0x12, 0, 0x1F, 1), +}; + +/* Common DAPM widgets */ +static const struct snd_soc_dapm_widget uda1342_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("VINL1"), + SND_SOC_DAPM_INPUT("VINR1"), + SND_SOC_DAPM_INPUT("VINL2"), + SND_SOC_DAPM_INPUT("VINR2"), + + SND_SOC_DAPM_DAC("DAC", "Playback", 0, 1, 0), + SND_SOC_DAPM_ADC("ADC", "Capture", 0, 9, 0), + + SND_SOC_DAPM_OUTPUT("VOUTL"), + SND_SOC_DAPM_OUTPUT("VOUTR"), +}; + +static const struct snd_soc_dapm_route uda1342_dapm_routes[] = { + { "ADC", NULL, "VINL1" }, + { "ADC", NULL, "VINR1" }, + { "ADC", NULL, "VINL2" }, + { "ADC", NULL, "VINR2" }, + { "VOUTL", NULL, "DAC" }, + { "VOUTR", NULL, "DAC" }, +}; + +static const struct snd_soc_dai_ops uda1342_dai_ops = { + .startup = uda1342_startup, + .shutdown = uda1342_shutdown, + .hw_params = uda1342_hw_params, + .mute_stream = uda1342_mute, + .set_sysclk = uda1342_set_dai_sysclk, + .set_fmt = uda1342_set_dai_fmt, +}; + +static struct snd_soc_dai_driver uda1342_dai = { + .name = "uda1342-hifi", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = UDA134X_FORMATS, + }, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = UDA134X_FORMATS, + }, + /* pcm operations */ + .ops = &uda1342_dai_ops, +}; + +static const struct snd_soc_component_driver soc_component_dev_uda1342 = { + .controls = uda1342_snd_controls, + .num_controls = ARRAY_SIZE(uda1342_snd_controls), + .dapm_widgets = uda1342_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda1342_dapm_widgets), + .dapm_routes = uda1342_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda1342_dapm_routes), + .suspend_bias_off = 1, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config uda1342_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x21, + .reg_defaults = uda1342_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(uda1342_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int uda1342_i2c_probe(struct i2c_client *i2c) +{ + struct uda1342_priv *uda1342; + + uda1342 = devm_kzalloc(&i2c->dev, sizeof(*uda1342), GFP_KERNEL); + if (!uda1342) + return -ENOMEM; + + uda1342->regmap = devm_regmap_init_i2c(i2c, &uda1342_regmap); + if (IS_ERR(uda1342->regmap)) + return PTR_ERR(uda1342->regmap); + + i2c_set_clientdata(i2c, uda1342); + uda1342->i2c = i2c; + + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_uda1342, + &uda1342_dai, 1); +} + +static int uda1342_suspend(struct device *dev) +{ + struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + + regcache_cache_only(uda1342->regmap, true); + + return 0; +} + +static int uda1342_resume(struct device *dev) +{ + struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + + regcache_mark_dirty(uda1342->regmap); + regcache_sync(uda1342->regmap); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(uda1342_pm_ops, + uda1342_suspend, uda1342_resume, NULL); + +static const struct i2c_device_id uda1342_i2c_id[] = { + { "uda1342", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, uda1342_i2c_id); + +static const struct of_device_id uda1342_of_match[] = { + { .compatible = "nxp,uda1342" }, + { } +}; +MODULE_DEVICE_TABLE(of, uda1342_of_match); + +static struct i2c_driver uda1342_i2c_driver = { + .driver = { + .name = "uda1342", + .of_match_table = uda1342_of_match, + .pm = pm_sleep_ptr(&uda1342_pm_ops), + }, + .probe = uda1342_i2c_probe, + .id_table = uda1342_i2c_id, +}; +module_i2c_driver(uda1342_i2c_driver); + +MODULE_DESCRIPTION("UDA1342 ALSA soc codec driver"); +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); +MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda1342.h b/sound/soc/codecs/uda1342.h new file mode 100644 index 000000000000..ff6aea0a8b01 --- /dev/null +++ b/sound/soc/codecs/uda1342.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Audio support for NXP UDA1342 + * + * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> + * Copyright (c) 2024 Binbin Zhou <zhoubinbin@loongson.cn> + */ + +#ifndef _UDA1342_H +#define _UDA1342_H + +#define UDA1342_CLK 0x00 +#define UDA1342_IFACE 0x01 +#define UDA1342_PM 0x02 +#define UDA1342_AMIX 0x03 +#define UDA1342_HP 0x04 +#define UDA1342_MVOL 0x11 +#define UDA1342_MIXVOL 0x12 +#define UDA1342_MODE 0x12 +#define UDA1342_DEEMP 0x13 +#define UDA1342_MIXER 0x14 +#define UDA1342_INTSTAT 0x18 +#define UDA1342_DEC 0x20 +#define UDA1342_PGA 0x21 +#define UDA1342_ADC 0x22 +#define UDA1342_AGC 0x23 +#define UDA1342_DECSTAT 0x28 +#define UDA1342_RESET 0x7f + +/* Register flags */ +#define R00_EN_ADC 0x0800 +#define R00_EN_DEC 0x0400 +#define R00_EN_DAC 0x0200 +#define R00_EN_INT 0x0100 +#define R00_DAC_CLK 0x0010 +#define R01_SFORI_I2S 0x0000 +#define R01_SFORI_LSB16 0x0100 +#define R01_SFORI_LSB18 0x0200 +#define R01_SFORI_LSB20 0x0300 +#define R01_SFORI_MSB 0x0500 +#define R01_SFORI_MASK 0x0700 +#define R01_SFORO_I2S 0x0000 +#define R01_SFORO_LSB16 0x0001 +#define R01_SFORO_LSB18 0x0002 +#define R01_SFORO_LSB20 0x0003 +#define R01_SFORO_LSB24 0x0004 +#define R01_SFORO_MSB 0x0005 +#define R01_SFORO_MASK 0x0007 +#define R01_SEL_SOURCE 0x0040 +#define R01_SIM 0x0010 +#define R02_PON_PLL 0x8000 +#define R02_PON_HP 0x2000 +#define R02_PON_DAC 0x0400 +#define R02_PON_BIAS 0x0100 +#define R02_EN_AVC 0x0080 +#define R02_PON_AVC 0x0040 +#define R02_PON_LNA 0x0010 +#define R02_PON_PGAL 0x0008 +#define R02_PON_ADCL 0x0004 +#define R02_PON_PGAR 0x0002 +#define R02_PON_ADCR 0x0001 +#define R13_MTM 0x4000 +#define R14_SILENCE 0x0080 +#define R14_SDET_ON 0x0040 +#define R21_MT_ADC 0x8000 +#define R22_SEL_LNA 0x0008 +#define R22_SEL_MIC 0x0004 +#define R22_SKIP_DCFIL 0x0002 +#define R23_AGC_EN 0x0001 + +#define UDA1342_DAI_DUPLEX 0 /* playback and capture on single DAI */ +#define UDA1342_DAI_PLAYBACK 1 /* playback DAI */ +#define UDA1342_DAI_CAPTURE 2 /* capture DAI */ + +#define STATUS0_DAIFMT_MASK (~(7 << 1)) +#define STATUS0_SYSCLK_MASK (~(3 << 4)) + +#endif /* _UDA1342_H */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 373a31ddccb2..a2521e16c099 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5177,4 +5177,3 @@ static struct slim_driver wcd9335_slim_driver = { module_slim_driver(wcd9335_slim_driver); MODULE_DESCRIPTION("WCD9335 slim driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("slim:217:1a0:*"); diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 08fb13a334a4..c9d5e67bf66e 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -7,7 +7,6 @@ #include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..8e88830e8e57 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -30,6 +30,7 @@ config SND_SOC_FSL_MQS tristate "Medium Quality Sound (MQS) module support" depends on SND_SOC_FSL_SAI select REGMAP_MMIO + select IMX_SCMI_MISC_DRV if IMX_SCMI_MISC_EXT !=n help Say Y if you want to add Medium Quality Sound (MQS) support for the Freescale CPUs. diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index f6c3aeff0d8e..02e1594e8223 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -317,8 +317,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { { .name = "HiFi-ASRC-FE", .stream_name = "HiFi-ASRC-FE", - .dpcm_playback = 1, - .dpcm_capture = 1, .dynamic = 1, }, { @@ -326,8 +324,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { .stream_name = "HiFi-ASRC-BE", .be_hw_params_fixup = be_hw_params_fixup, .ops = &fsl_asoc_card_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .no_pcm = 1, }, }; @@ -504,13 +500,13 @@ static int fsl_asoc_card_spdif_init(struct device_node *codec_np[], } if (priv->dai_link[0].playback_only) { - priv->dai_link[1].dpcm_capture = false; - priv->dai_link[2].dpcm_capture = false; + priv->dai_link[1].playback_only = true; + priv->dai_link[2].playback_only = true; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (priv->dai_link[0].capture_only) { - priv->dai_link[1].dpcm_playback = false; - priv->dai_link[2].dpcm_playback = false; + priv->dai_link[1].capture_only = true; + priv->dai_link[2].capture_only = true; priv->card.dapm_routes = audio_map_rx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); } @@ -764,8 +760,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { codec_dai_name[0] = "tlv320dac31xx-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; priv->card.dapm_routes = audio_map_tx; @@ -791,15 +787,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_NB_NF; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) { codec_dai_name[0] = "wm8524-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->cpu_priv.slot_width = 32; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); @@ -1033,14 +1029,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* - * Properties "hp-det-gpio" and "mic-det-gpio" are optional, and + * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and * simple_util_init_jack() uses these properties for creating * Headphone Jack and Microphone Jack. * * The notifier is initialized in snd_soc_card_jack_new(), then * snd_soc_jack_notifier_register can be called. */ - if (of_property_read_bool(np, "hp-det-gpio")) { + if (of_property_read_bool(np, "hp-det-gpios") || + of_property_read_bool(np, "hp-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->hp_jack, 1, NULL, "Headphone Jack"); if (ret) @@ -1049,7 +1046,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb); } - if (of_property_read_bool(np, "mic-det-gpio")) { + if (of_property_read_bool(np, "mic-det-gpios") || + of_property_read_bool(np, "mic-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->mic_jack, 0, NULL, "Mic Jack"); if (ret) diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 021d73e409aa..bde642318835 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -169,7 +169,7 @@ static const struct regmap_config fsl_aud2htx_regmap_config = { .readable_reg = fsl_aud2htx_readable_reg, .volatile_reg = fsl_aud2htx_volatile_reg, .writeable_reg = fsl_aud2htx_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct of_device_id fsl_aud2htx_dt_ids[] = { diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 82359edd6a8b..d22f0621c465 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1748,7 +1748,7 @@ static const struct regmap_config fsl_easrc_regmap_config = { .rd_table = &fsl_easrc_readable_table, .wr_table = &fsl_easrc_writeable_table, .volatile_table = &fsl_easrc_volatileable_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #ifdef DEBUG diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 0c71a73476df..8c15389c9a04 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -68,6 +68,7 @@ struct fsl_micfil { int vad_detected; struct fsl_micfil_verid verid; struct fsl_micfil_param param; + bool mclk_flag; /* mclk enable flag */ }; struct fsl_micfil_soc_data { @@ -708,7 +709,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Enable the module */ ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -724,7 +725,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Disable the module */ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -751,7 +752,6 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s clk = micfil->mclk; /* Disable clock first, for it was enabled by pm_runtime */ - clk_disable_unprepare(clk); fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, micfil->pll11k_clk, ratio); ret = clk_prepare_enable(clk); @@ -788,6 +788,8 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + micfil->mclk_flag = true; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); if (ret) return ret; @@ -822,6 +824,17 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_micfil_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(micfil->mclk); + micfil->mclk_flag = false; + + return 0; +} + static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -878,6 +891,7 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { .startup = fsl_micfil_startup, .trigger = fsl_micfil_trigger, .hw_params = fsl_micfil_hw_params, + .hw_free = fsl_micfil_hw_free, }; static struct snd_soc_dai_driver fsl_micfil_dai = { @@ -999,6 +1013,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_STAT: case REG_MICFIL_DATACH0: case REG_MICFIL_DATACH1: case REG_MICFIL_DATACH2: @@ -1007,6 +1022,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_OUT_STAT: case REG_MICFIL_VERID: case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: @@ -1028,7 +1044,7 @@ static const struct regmap_config fsl_micfil_regmap_config = { .readable_reg = fsl_micfil_readable_reg, .volatile_reg = fsl_micfil_volatile_reg, .writeable_reg = fsl_micfil_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* END OF REGMAP */ @@ -1061,7 +1077,7 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, MICFIL_STAT_CHXF(i), - 1); + MICFIL_STAT_CHXF(i)); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { @@ -1083,6 +1099,8 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) { struct fsl_micfil *micfil = (struct fsl_micfil *)devid; struct platform_device *pdev = micfil->pdev; + u32 fifo_stat_reg; + u32 out_stat_reg; u32 stat_reg; regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); @@ -1096,9 +1114,17 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF, 1); + MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_FIFO_STAT, + fifo_stat_reg, fifo_stat_reg); + + regmap_read(micfil->regmap, REG_MICFIL_OUT_STAT, &out_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_OUT_STAT, + out_stat_reg, out_stat_reg); + return IRQ_HANDLED; } @@ -1358,7 +1384,8 @@ static int fsl_micfil_runtime_suspend(struct device *dev) regcache_cache_only(micfil->regmap, true); - clk_disable_unprepare(micfil->mclk); + if (micfil->mclk_flag) + clk_disable_unprepare(micfil->mclk); clk_disable_unprepare(micfil->busclk); return 0; @@ -1373,10 +1400,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) if (ret < 0) return ret; - ret = clk_prepare_enable(micfil->mclk); - if (ret < 0) { - clk_disable_unprepare(micfil->busclk); - return ret; + if (micfil->mclk_flag) { + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) { + clk_disable_unprepare(micfil->busclk); + return ret; + } } regcache_cache_only(micfil->regmap, false); diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 145f9ca15e43..0513e9e8402e 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -6,6 +6,7 @@ // Copyright 2019 NXP #include <linux/clk.h> +#include <linux/firmware/imx/sm.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/mfd/syscon.h> @@ -74,6 +75,29 @@ struct fsl_mqs { #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) #define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE +static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val) +{ + struct fsl_mqs *mqs_priv = context; + int num = 1; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, &num, val); + + return -EINVAL; +}; + +static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val) +{ + struct fsl_mqs *mqs_priv = context; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, val); + + return -EINVAL; +}; + static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -188,6 +212,13 @@ static const struct regmap_config fsl_mqs_regmap_config = { .cache_type = REGCACHE_NONE, }; +static const struct regmap_config fsl_mqs_sm_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_read = fsl_mqs_sm_read, + .reg_write = fsl_mqs_sm_write, +}; + static int fsl_mqs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -219,6 +250,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get gpr regmap\n"); return PTR_ERR(mqs_priv->regmap); } + } else if (mqs_priv->soc->type == TYPE_REG_SM) { + mqs_priv->regmap = devm_regmap_init(&pdev->dev, + NULL, + mqs_priv, + &fsl_mqs_sm_regmap); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(mqs_priv->regmap)); + return PTR_ERR(mqs_priv->regmap); + } } else { regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 8668abd35208..e257b8adafe0 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -838,8 +838,6 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_dai->id, i, ret); return ret; } - dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n", - qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts); if (info.mode != QMC_TRANSPARENT) { dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n", diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index beede7344efd..1e0bfd59d511 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -53,6 +53,8 @@ struct fsl_xcvr { struct snd_aes_iec958 rx_iec958; struct snd_aes_iec958 tx_iec958; u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; + struct work_struct work_rst; + spinlock_t lock; /* Protect hw_reset and trigger */ }; static const struct fsl_xcvr_pll_conf { @@ -663,7 +665,10 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - int ret; + unsigned long lock_flags; + int ret = 0; + + spin_lock_irqsave(&xcvr->lock, lock_flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -675,7 +680,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -687,7 +692,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "err updating isr %d\n", ret); - return ret; + goto release_lock; } fallthrough; case FSL_XCVR_MODE_SPDIF: @@ -696,7 +701,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); - return ret; + goto release_lock; } break; } @@ -707,14 +712,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) { dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) { dev_err(dai->dev, "Error while setting IER0: %d\n", ret); - return ret; + goto release_lock; } /* clear DPATH RESET */ @@ -723,7 +728,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } break; @@ -736,14 +741,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -754,7 +759,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); - return ret; + goto release_lock; } if (xcvr->soc_data->spdif_only) break; @@ -768,17 +773,20 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) { dev_err(dai->dev, "Err updating ISR %d\n", ret); - return ret; + goto release_lock; } break; } } break; default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; +release_lock: + spin_unlock_irqrestore(&xcvr->lock, lock_flags); + return ret; } static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) @@ -1198,6 +1206,34 @@ static const struct regmap_config fsl_xcvr_regmap_cfg = { .cache_type = REGCACHE_FLAT, }; +static void reset_rx_work(struct work_struct *work) +{ + struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst); + struct device *dev = &xcvr->pdev->dev; + unsigned long lock_flags; + u32 ext_ctrl; + + dev_dbg(dev, "reset rx path\n"); + spin_lock_irqsave(&xcvr->lock, lock_flags); + regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl); + + if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) { + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS, + 0); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, + 0); + } + spin_unlock_irqrestore(&xcvr->lock, lock_flags); +} + static irqreturn_t irq0_isr(int irq, void *devid) { struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid; @@ -1265,6 +1301,33 @@ static irqreturn_t irq0_isr(int irq, void *devid) dev_dbg(dev, "DMA write request\n"); isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ; } + if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) { + dev_dbg(dev, "CMDC status update\n"); + isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD; + } + if (isr & FSL_XCVR_IRQ_PREAMBLE_MISMATCH) { + dev_dbg(dev, "Preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_PREAMBLE_MISMATCH; + } + if (isr & FSL_XCVR_IRQ_UNEXP_PRE_REC) { + dev_dbg(dev, "Unexpected preamble received\n"); + isr_clr |= FSL_XCVR_IRQ_UNEXP_PRE_REC; + } + if (isr & FSL_XCVR_IRQ_M_W_PRE_MISMATCH) { + dev_dbg(dev, "M/W preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_M_W_PRE_MISMATCH; + } + if (isr & FSL_XCVR_IRQ_B_PRE_MISMATCH) { + dev_dbg(dev, "B preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_B_PRE_MISMATCH; + } + + if (isr & (FSL_XCVR_IRQ_PREAMBLE_MISMATCH | + FSL_XCVR_IRQ_UNEXP_PRE_REC | + FSL_XCVR_IRQ_M_W_PRE_MISMATCH | + FSL_XCVR_IRQ_B_PRE_MISMATCH)) { + schedule_work(&xcvr->work_rst); + } if (isr_clr) { regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr); @@ -1411,11 +1474,16 @@ static int fsl_xcvr_probe(struct platform_device *pdev) fsl_xcvr_comp.name); } + INIT_WORK(&xcvr->work_rst, reset_rx_work); + spin_lock_init(&xcvr->lock); return ret; } static void fsl_xcvr_remove(struct platform_device *pdev) { + struct fsl_xcvr *xcvr = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&xcvr->work_rst); pm_runtime_disable(&pdev->dev); } diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 882428592e1a..c72cb05184df 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -165,6 +165,11 @@ FSL_XCVR_IRQ_MUTE | \ FSL_XCVR_IRQ_FIFO_UOFL_ERR | \ FSL_XCVR_IRQ_HOST_WAKEUP | \ + FSL_XCVR_IRQ_CMDC_STATUS_UPD |\ + FSL_XCVR_IRQ_B_PRE_MISMATCH |\ + FSL_XCVR_IRQ_M_W_PRE_MISMATCH |\ + FSL_XCVR_IRQ_PREAMBLE_MISMATCH |\ + FSL_XCVR_IRQ_UNEXP_PRE_REC |\ FSL_XCVR_IRQ_ARC_MODE) #define FSL_XCVR_ISR_CMDC_TX_EN BIT(3) diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 6fbcf33fd0de..dcf770b55c4b 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -264,11 +264,10 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[i].cpus->dai_name = name[1][i]; priv->dai[i].dynamic = 1; - priv->dai[i].dpcm_playback = 1; - if (i == num_dai - 1) { - priv->dai[i].dpcm_capture = 1; - priv->dai[i].dpcm_playback = 0; - } + if (i == num_dai - 1) + priv->dai[i].capture_only = 1; + else + priv->dai[i].playback_only = 1; priv->dai[i].ignore_pmdown_time = 1; priv->dai[i].ops = &imx_audmix_fe_ops; @@ -285,11 +284,10 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[num_dai + i].cpus->of_node = audmix_np; priv->dai[num_dai + i].cpus->dai_name = be_name; priv->dai[num_dai + i].no_pcm = 1; - priv->dai[num_dai + i].dpcm_playback = 1; - if (i == num_dai - 1) { - priv->dai[num_dai + i].dpcm_capture = 1; - priv->dai[num_dai + i].dpcm_playback = 0; - } + if (i == num_dai - 1) + priv->dai[num_dai + i].capture_only = 1; + else + priv->dai[num_dai + i].playback_only = 1; priv->dai[num_dai + i].ignore_pmdown_time = 1; priv->dai[num_dai + i].ops = &imx_audmix_be_ops; diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index a7215bad6484..95a57fda0250 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -25,6 +25,7 @@ enum codec_type { CODEC_AK4458, CODEC_AK4497, CODEC_AK5552, + CODEC_CS42888, }; /* @@ -185,6 +186,16 @@ static struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = { { .min = 512, .max = 512, .mul = 1024 }, }; +static struct imx_akcodec_fs_mul cs42888_fs_mul[] = { + { .rmin = 8000, .rmax = 48000, .wmin = 256, .wmax = 1024, }, + { .rmin = 64000, .rmax = 96000, .wmin = 128, .wmax = 512, }, + { .rmin = 176400, .rmax = 192000, .wmin = 64, .wmax = 256, }, +}; + +static struct imx_akcodec_tdm_fs_mul cs42888_tdm_fs_mul[] = { + { .min = 256, .max = 256, .mul = 256 }, +}; + static const u32 akcodec_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000, @@ -210,6 +221,14 @@ static const u32 ak5558_tdm_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8, }; +static const u32 cs42888_channels[] = { + 1, 2, 4, 6, 8, +}; + +static const u32 cs42888_tdm_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, +}; + static bool format_is_dsd(struct snd_pcm_hw_params *params) { snd_pcm_format_t format = params_format(params); @@ -241,6 +260,7 @@ static bool codec_is_akcodec(unsigned int type) case CODEC_AK4497: case CODEC_AK5558: case CODEC_AK5552: + case CODEC_CS42888: return true; default: break; @@ -255,7 +275,7 @@ static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); const struct imx_card_plat_data *plat_data = data->plat_data; - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; unsigned int width = slots * slot_width; unsigned int rate = params_rate(params); int i; @@ -293,7 +313,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_card *card = rtd->card; struct imx_card_data *data = snd_soc_card_get_drvdata(card); - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; struct imx_card_plat_data *plat_data = data->plat_data; struct device *dev = card->dev; struct snd_soc_dai *codec_dai; @@ -340,13 +360,15 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_tdm_slot(codec_dai, - BIT(slots) - 1, - BIT(slots) - 1, - slots, slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); - return ret; + if (format_is_tdm(link_data)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + BIT(slots) - 1, + BIT(slots) - 1, + slots, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); + return ret; + } } } @@ -370,6 +392,11 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); return ret; } + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret); + return ret; + } return 0; } @@ -408,7 +435,7 @@ static int imx_aif_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct imx_card_data *data = snd_soc_card_get_drvdata(card); - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; static struct snd_pcm_hw_constraint_list constraint_rates; static struct snd_pcm_hw_constraint_list constraint_channels; int ret = 0; @@ -604,6 +631,8 @@ static int imx_card_parse_of(struct imx_card_data *data) plat_data->type = CODEC_AK5558; else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) plat_data->type = CODEC_AK5552; + else if (!strcmp(link->codecs->dai_name, "cs42888")) + plat_data->type = CODEC_CS42888; } else { link->codecs = &snd_soc_dummy_dlc; @@ -761,6 +790,12 @@ static int imx_card_probe(struct platform_device *pdev) data->dapm_routes[i].sink = "ASRC-Capture"; data->dapm_routes[i].source = "CPU-Capture"; break; + case CODEC_CS42888: + data->dapm_routes[0].sink = "Playback"; + data->dapm_routes[0].source = "CPU-Playback"; + data->dapm_routes[1].sink = "CPU-Capture"; + data->dapm_routes[1].source = "Capture"; + break; default: break; } @@ -800,6 +835,16 @@ static int imx_card_probe(struct platform_device *pdev) plat_data->support_tdm_channels = ak5558_tdm_channels; plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); break; + case CODEC_CS42888: + plat_data->fs_mul = cs42888_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul); + plat_data->tdm_fs_mul = cs42888_tdm_fs_mul; + plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul); + plat_data->support_channels = cs42888_channels; + plat_data->num_channels = ARRAY_SIZE(cs42888_channels); + plat_data->support_tdm_channels = cs42888_tdm_channels; + plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels); + break; default: break; } @@ -815,8 +860,8 @@ static int imx_card_probe(struct platform_device *pdev) } for_each_card_prelinks(&data->card, i, link) { if (link->dynamic == 1 && link_be) { - link->dpcm_playback = link_be->dpcm_playback; - link->dpcm_capture = link_be->dpcm_capture; + link->playback_only = link_be->playback_only; + link->capture_only = link_be->capture_only; } } } diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index a9a178188515..5280c1b20d85 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -50,7 +50,7 @@ snd_soc_runtime_get_dai_fmt() sample driver - linux/sound/soc/sh/rcar/core.c + linux/sound/soc/renesas/rcar/core.c linux/sound/soc/codecs/ak4613.c linux/sound/soc/codecs/pcm3168a.c linux/sound/soc/soc-utils.c diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fedae7f6f70c..24b371f32066 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -296,7 +296,7 @@ int simple_util_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; unsigned int fixed_sysclk = 0; int i1, i2, i; @@ -357,7 +357,7 @@ void simple_util_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; int i; @@ -448,7 +448,7 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, struct simple_util_dai *pdai; struct snd_soc_dai *sdai; struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); unsigned int mclk, mclk_fs = 0; int i, ret; @@ -517,7 +517,7 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->id); struct simple_util_data *data = &dai_props->adata; struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); @@ -628,7 +628,7 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) { struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; int i, ret; @@ -858,6 +858,10 @@ int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) } EXPORT_SYMBOL_GPL(simple_util_init_aux_jacks); +static struct simple_util_dai dummy_util_dais = { + .name = "dummy_util_dais", +}; + int simple_util_init_priv(struct simple_util_priv *priv, struct link_info *li) { @@ -929,6 +933,7 @@ int simple_util_init_priv(struct simple_util_priv *priv, dai_link[i].cpus = &snd_soc_dummy_dlc; dai_props[i].num.cpus = dai_link[i].num_cpus = 1; + dai_props[i].cpu_dai = &dummy_util_dais; } if (li->num[i].codecs) { @@ -951,6 +956,7 @@ int simple_util_init_priv(struct simple_util_priv *priv, dai_link[i].codecs = &snd_soc_dummy_dlc; dai_props[i].num.codecs = dai_link[i].num_codecs = 1; + dai_props[i].codec_dai = &dummy_util_dais; } if (li->num[i].platforms) { diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 85ce3ebeec05..5430d25deaef 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -224,7 +224,7 @@ static const struct snd_soc_dai_ops test_verbose_ops = { .num_auto_selectable_formats = 1, }; -#define STUB_RATES SNDRV_PCM_RATE_8000_384000 +#define STUB_RATES SNDRV_PCM_RATE_CONTINUOUS #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a32fb0a8d7d7..2db494b0e3cf 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -15,9 +15,6 @@ config SND_SOC_INTEL_SST_TOPLEVEL if SND_SOC_INTEL_SST_TOPLEVEL -config SND_SOC_INTEL_SST - tristate - config SND_SOC_INTEL_CATPT tristate "Haswell and Broadwell" depends on ACPI || COMPILE_TEST @@ -74,9 +71,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI + select SND_SOC_ACPI_INTEL_SDCA_QUIRKS # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. +config SND_SOC_ACPI_INTEL_SDCA_QUIRKS + tristate + select SND_SOC_SDCA if ACPI + endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_INTEL_KEEMBAY diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 80c0a1a95654..93eba4fd2771 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -203,8 +203,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->exit = avs_da7219_codec_exit; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index a31aa471a1c2..4dd9591ee98b 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -22,7 +22,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC", .id = 0, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), @@ -30,7 +30,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC WoV", .id = 1, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, .ignore_suspend = 1, diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index c8522e2430f8..426ce37105ae 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -233,8 +233,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_es8336_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 430c070a1a0e..cb6d54db7189 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -39,8 +39,6 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int dl[i].id = i; dl[i].nonatomic = 1; dl[i].no_pcm = 1; - dl[i].dpcm_playback = 1; - dl[i].dpcm_capture = 1; dl[i].platforms = platform; dl[i].num_platforms = 1; dl[i].ignore_pmdown_time = 1; @@ -160,8 +158,6 @@ static const struct snd_soc_dai_link probing_link = { .id = -1, .nonatomic = 1, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .cpus = &snd_soc_dummy_dlc, .num_cpus = 1, .init = avs_probing_link_init, diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 7e6c8d9c900b..4556f105c793 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -46,8 +46,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->id = 0; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 8d550e82b46a..6570209c1a63 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -82,7 +82,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98357a_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_playback = 1; + dl->playback_only = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index fdef5a008daf..6f25e66344b7 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -134,8 +134,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98373_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98373_ops; diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index 082f311d8b84..ad18c4e9a670 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -131,8 +131,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98927_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98927_ops; diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 6ea9058fdb2a..bf902540744c 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -210,8 +210,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_nau8825_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 9fcce86c6eb4..4b6c02a40204 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -184,8 +184,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt274_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index f157f2d19efb..e40563ca99fd 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -153,8 +153,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt286_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 1e85242c8dd2..94fce07c83f9 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -173,8 +173,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt298_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index cfa146b6cf08..30588d9e9ba3 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -121,7 +121,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt5514_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; + dl->capture_only = 1; dl->ops = &avs_rt5514_ops; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 44f857e90969..b456b9d14665 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -171,8 +171,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt5663_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ops = &avs_rt5663_ops; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 0dcc6392a0cc..335960cfd7ba 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -242,8 +242,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt5682_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 63bbfc30f35e..cfef00462f66 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -121,8 +121,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_ssm4567_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 4af811580356..945f9c0a6a54 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -509,7 +509,7 @@ static int avs_pcm_hw_constraints_init(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS, SNDRV_PCM_HW_PARAM_RATE, -1); - return ret; + return 0; } static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cc10ae58b0c7..9b80b19bb8d0 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -519,6 +519,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT712_SDCA_DMIC_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT721_SDCA_SDW select SND_SOC_RT722_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index 3c7cee03a02e..d25a7188f603 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -239,8 +239,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -256,8 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5650_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5650_init, SND_SOC_DAILINK_REG(ssp0_port, be, platform), }, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 304af3d06d01..9484f3410787 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -329,8 +329,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_capture = 1, - .dpcm_playback = 1, .ops = &bdw_rt5677_fe_ops, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -356,8 +354,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5677_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5677_init, .exit = bdw_rt5677_exit, SND_SOC_DAILINK_REG(ssp0_port, be, platform), diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index 58db09d9b6e1..523ade9f31ab 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -133,8 +133,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -143,7 +141,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -152,7 +150,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -161,7 +159,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -177,8 +175,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 8c2b4ab764bb..68a3d345dc25 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -175,8 +175,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -185,7 +183,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -198,8 +196,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), }, }; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 9178bbe8d995..31141d4b6b25 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -174,8 +174,6 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -184,7 +182,7 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -197,8 +195,6 @@ static struct snd_soc_dai_link dailink[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index d3327bc237b5..62594e7966ab 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -315,8 +315,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -326,7 +324,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -339,8 +337,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_cht_es8316_init, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 4a957d1cece3..fec23bda9e64 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -119,8 +119,6 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -130,7 +128,7 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -144,8 +142,6 @@ static struct snd_soc_dai_link dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2_port, dummy, platform), }, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 54f77f57ec8e..9caa4407c1ca 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1564,8 +1564,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -1574,7 +1572,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -1586,8 +1584,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5640_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5640_init, .exit = byt_rt5640_exit, .ops = &byt_rt5640_be_ssp2_ops, diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8e4b821efe92..67c62844ca2a 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -770,8 +770,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -780,7 +778,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -793,8 +791,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5651_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5651_init, .ops = &byt_rt5651_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 0b10d89cb189..a6dfbcfdf74e 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -462,8 +462,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), @@ -473,7 +471,7 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -490,8 +488,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_wm5102_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_wm5102_init, SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d7c114858833..36984de8a067 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -351,8 +351,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -361,7 +359,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -374,8 +372,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 7651b83632fa..4afb292d4f13 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -193,8 +193,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -217,8 +215,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index ac23a8b7cafc..b977a2db73a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -448,8 +448,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -458,7 +456,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -470,8 +468,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index c6c469d51243..aaef212cf44e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -358,8 +358,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -368,7 +366,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -381,8 +379,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 90d93e667bd9..ebc417c04a50 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -178,8 +178,6 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "SSP0-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &rt5660_ops, SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform), }, @@ -187,7 +185,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic48k", .id = 1, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), }, @@ -195,7 +193,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic16k", .id = 2, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp1", .id = 5, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, @@ -211,7 +209,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp2", .id = 6, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, @@ -219,7 +217,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp3", .id = 7, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, @@ -227,7 +225,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp4", .id = 8, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), }, diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c index 1826a4dfd0f3..9bb2822ba63e 100644 --- a/sound/soc/intel/boards/hsw_rt5640.c +++ b/sound/soc/intel/boards/hsw_rt5640.c @@ -85,8 +85,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -95,7 +93,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -104,7 +102,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -113,7 +111,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -127,8 +125,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 24f716e42d6a..50e846d67c19 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -217,8 +217,6 @@ static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } @@ -268,7 +266,7 @@ static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, link->init = dmic_init; link->ignore_suspend = 1; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; return 0; } @@ -326,7 +324,7 @@ static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link link->id = be_id; link->init = (hdmi_id == 1) ? hdmi_init : NULL; link->no_pcm = 1; - link->dpcm_playback = 1; + link->playback_only = 1; return 0; } @@ -361,13 +359,12 @@ static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, /* codecs - caller to handle */ /* platforms */ + /* feedback stream or firmware-generated echo reference */ link->platforms = platform_component; link->num_platforms = ARRAY_SIZE(platform_component); link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ - link->dpcm_playback = 1; return 0; } @@ -407,8 +404,6 @@ static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } @@ -448,7 +443,7 @@ static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; return 0; } @@ -496,8 +491,6 @@ static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link, if (be_type == SOF_HDA_ANALOG) link->init = hda_init; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index fc998fe4b196..a92707876851 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -455,8 +455,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].exit = sof_es8316_exit; links[id].ops = &sof_es8336_ops; links[id].nonatomic = true; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -496,7 +494,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; @@ -539,7 +537,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; @@ -569,7 +567,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; links[id].num_cpus = 1; id++; diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 8d237f67bd06..68380b738d88 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -246,12 +246,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_pcm512x_codec_init; links[id].ops = &sof_pcm512x_ops; - links[id].dpcm_playback = 1; /* * capture only supported with specific versions of the Hifiberry DAC+ */ - if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE) - links[id].dpcm_capture = 1; + if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)) + links[id].playback_only = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -294,7 +293,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; } @@ -341,7 +340,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; } diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index bc581fea0e3a..5ceb376d4924 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -871,12 +871,27 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_PRESENT), }, { + .name = "mtl_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)), + }, + { .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)), }, + { + .name = "ptl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, { } }; 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 4a0ab50d1e50..ea5249df8ac3 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -484,10 +484,26 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") + }, + .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, "0CF9") }, .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, "0CFA") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, /* MeteorLake devices */ { .callback = sof_sdw_quirk_cb, @@ -576,10 +592,59 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") + }, + .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), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3838") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3832") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "380E") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "233C") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "233B") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, /* ArrowLake devices */ { @@ -606,6 +671,46 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .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, "0CF0") + }, + .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, "0CF3") + }, + .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, "0CF4") + }, + .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, "0CF5") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + /* Pantherlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, {} }; @@ -741,7 +846,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, 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); + 1, asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -818,7 +923,7 @@ static int create_ssp_dailinks(struct snd_soc_card *card, playback, capture, cpu_dai_name, platform_component->name, ARRAY_SIZE(platform_component), codec_name, - ssp_info->dais[0].dai_name, NULL, + ssp_info->dais[0].dai_name, 1, NULL, ssp_info->ops); if (ret) return ret; @@ -843,7 +948,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "DMIC01 Pin", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", 1, asoc_sdw_dmic_init, NULL); if (ret) return ret; @@ -854,7 +959,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "DMIC16k Pin", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", 1, /* don't call asoc_sdw_dmic_init() twice */ NULL, NULL); if (ret) @@ -898,7 +1003,7 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, 1, 0, // HDMI only supports playback cpu_dai_name, platform_component->name, ARRAY_SIZE(platform_component), - codec_name, codec_dai_name, + codec_name, codec_dai_name, 1, i == 0 ? sof_sdw_hdmi_init : NULL, NULL); if (ret) return ret; @@ -926,7 +1031,7 @@ static int create_bt_dailinks(struct snd_soc_card *card, 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); + 1, NULL, NULL); if (ret) return ret; diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index facc6c32cbfe..51922347409f 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -167,8 +167,6 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &sof_wm8804_ops, SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 91e146e2487d..0afd114be9e5 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-dsp-y := sst-dsp.o -snd-soc-sst-ipc-y := sst-ipc.o snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \ soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ @@ -18,5 +16,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o -obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o +snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o + obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o +obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o 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 072b8486d072..24d850df77ca 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -44,6 +44,31 @@ static const struct snd_soc_acpi_endpoint spk_3_endpoint = { .group_id = 1, }; +/* + * 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 cs35l56_2_lr_adr[] = { { .adr = 0x00023001FA355601ull, @@ -185,6 +210,24 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +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 rt1320_2_single_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = { { .mask = BIT(0), @@ -287,6 +330,20 @@ static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_single_adr), + .adr_d = rt1320_2_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_codecs arl_essx_83x6 = { .num_codecs = 3, .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, @@ -385,6 +442,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711-l0.tplg", }, + { + .link_mask = BIT(0) | BIT(2), + .links = arl_rt722_l0_rt1320_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines); 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 094ed4b27cb0..98a9c36d7a4c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -8,6 +8,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = { @@ -90,6 +91,30 @@ static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -198,6 +223,15 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { + { + .adr = 0x000230025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { { .adr = 0x000030025d072201ull, @@ -252,6 +286,15 @@ static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_adr_device rt713_0_adr[] = { { .adr = 0x000031025D071301ull, @@ -410,6 +453,21 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr), + .adr_d = rt712_vb_2_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group1_adr), + .adr_d = rt1320_1_group1_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { /* mockup tests need to be first */ @@ -485,6 +543,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg" }, + { + .link_mask = BIT(1) | BIT(2), + .links = lnl_sdw_rt712_vb_l2_rt1320_l1, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index d4435a34a3a3..0b37465b6c53 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -6,9 +6,12 @@ * */ +#include <linux/soundwire/sdw_intel.h> +#include <sound/sdca.h> #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-ssp-common.h> +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { @@ -42,6 +45,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .comp_ids = &mtl_rt5682_rt5682s_hp, + .drv_name = "mtl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mtl_lt6911_hdmi, + .sof_tplg_filename = "sof-mtl-rt5682-ssp1-hdmi-ssp02.tplg", + }, /* place boards for each headphone codec: sof driver will complete the * tplg name and machine driver will detect the amp type */ @@ -126,6 +136,27 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint rt712_vb_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, + }, +}; + /* * RT722 is a multi-function codec, three endpoints are created for * its headset, amp and dmic functions. @@ -183,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = { + { + .adr = 0x000030025D071201ull, + .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints), + .endpoints = rt712_vb_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { { .adr = 0x000330025D171201ull, @@ -356,6 +396,15 @@ static const struct snd_soc_acpi_link_adr mtl_712_l0[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr), + .adr_d = rt712_vb_0_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -769,6 +818,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { }, { .link_mask = BIT(0), + .links = mtl_712_vb_l0, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg", + }, + { + .link_mask = BIT(0), .links = mtl_712_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0.tplg", @@ -836,3 +892,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); + +MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_SDCA_QUIRKS); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index 90f97a44b607..f1c0d7a02cda 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -9,8 +9,21 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include "soc-acpi-intel-sdw-mockup-match.h" +#include <sound/soc-acpi-intel-ssp-common.h> + +static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = { + .num_codecs = 2, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, +}; struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { + { + .comp_ids = &ptl_rt5682_rt5682s_hp, + .drv_name = "ptl_rt5682_def", + .sof_tplg_filename = "sof-ptl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); @@ -23,10 +36,10 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { }; /* - * RT722 is a multi-function codec, three endpoints are created for - * its headset, amp and dmic functions. + * Multi-function codecs with three endpoints created for + * headset, amp and dmic functions. */ -static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { +static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = { { .num = 0, .aggregated = 0, @@ -56,11 +69,38 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { + { + .adr = 0x000330025d072101ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt721" + } +}; + +static const struct snd_soc_acpi_link_adr ptl_rt721_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt721_3_single_adr), + .adr_d = rt721_3_single_adr, + }, + {}, +}; + static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { { .adr = 0x000030025d072201ull, - .num_endpoints = ARRAY_SIZE(rt722_endpoints), - .endpoints = rt722_endpoints, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_1_single_adr[] = { + { + .adr = 0x000130025d072201ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, .name_prefix = "rt722" } }; @@ -68,8 +108,8 @@ static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = { { .adr = 0x000330025d072201ull, - .num_endpoints = ARRAY_SIZE(rt722_endpoints), - .endpoints = rt722_endpoints, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, .name_prefix = "rt722" } }; @@ -83,6 +123,15 @@ static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_rt722_l1[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt722_1_single_adr), + .adr_d = rt722_1_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = { { .mask = BIT(3), @@ -129,12 +178,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .sof_tplg_filename = "sof-ptl-rt711.tplg", }, { + .link_mask = BIT(3), + .links = ptl_rt721_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt721.tplg", + }, + { .link_mask = BIT(0), .links = ptl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt722.tplg", }, { + .link_mask = BIT(1), + .links = ptl_rt722_l1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + }, + { .link_mask = BIT(3), .links = ptl_rt722_l3, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c new file mode 100644 index 000000000000..0b7076606d66 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#include <linux/soundwire/sdw_intel.h> +#include <sound/sdca.h> +#include <sound/soc-acpi.h> +#include "soc-acpi-intel-sdca-quirks.h" + +/* + * Pretend machine quirk. The argument type is not the traditional + * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx + * which contains the peripheral information required for the + * SoundWire/SDCA filter on the SMART_MIC setup and interface + * revision. When the return value is false, the entry in the + * 'snd_soc_acpi_mach' table needs to be skipped. + */ +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg) +{ + struct sdw_intel_ctx *ctx = arg; + int i; + + if (!ctx) + return false; + + for (i = 0; i < ctx->peripherals->num_peripherals; i++) { + if (sdca_device_quirk_match(ctx->peripherals->array[i], + SDCA_QUIRKS_RT712_VB)) + return true; + } + + return false; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, SND_SOC_ACPI_INTEL_SDCA_QUIRKS); + +MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_SDCA); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h new file mode 100644 index 000000000000..bead5ec6243f --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS +#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS + +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); + +#endif diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h deleted file mode 100644 index de32bb9afccb..000000000000 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology - * - * Copyright (C) 2013, Intel Corporation - */ - -#ifndef __SOUND_SOC_SST_DSP_PRIV_H -#define __SOUND_SOC_SST_DSP_PRIV_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/firmware.h> - -#include "../skylake/skl-sst-dsp.h" - -/* - * DSP Operations exported by platform Audio DSP driver. - */ -struct sst_ops { - /* Shim IO */ - void (*write)(void __iomem *addr, u32 offset, u32 value); - u32 (*read)(void __iomem *addr, u32 offset); - - /* IRQ handlers */ - irqreturn_t (*irq_handler)(int irq, void *context); - - /* SST init and free */ - int (*init)(struct sst_dsp *sst); - void (*free)(struct sst_dsp *sst); -}; - -/* - * Audio DSP memory offsets and addresses. - */ -struct sst_addr { - u32 sram0_base; - u32 sram1_base; - u32 w0_stat_sz; - u32 w0_up_sz; - void __iomem *lpe; - void __iomem *shim; -}; - -/* - * Audio DSP Mailbox configuration. - */ -struct sst_mailbox { - void __iomem *in_base; - void __iomem *out_base; - size_t in_size; - size_t out_size; -}; - -/* - * Generic SST Shim Interface. - */ -struct sst_dsp { - - /* Shared for all platforms */ - - /* runtime */ - struct sst_dsp_device *sst_dev; - spinlock_t spinlock; /* IPC locking */ - struct mutex mutex; /* DSP FW lock */ - struct device *dev; - void *thread_context; - int irq; - u32 id; - - /* operations */ - struct sst_ops *ops; - - /* debug FS */ - struct dentry *debugfs_root; - - /* base addresses */ - struct sst_addr addr; - - /* mailbox */ - struct sst_mailbox mailbox; - - /* SST FW files loaded and their modules */ - struct list_head module_list; - - /* SKL data */ - - const char *fw_name; - - /* To allocate CL dma buffers */ - struct skl_dsp_loader_ops dsp_ops; - struct skl_dsp_fw_ops fw_ops; - int sst_state; - struct skl_cl_dev cl_dev; - u32 intr_status; - const struct firmware *fw; - struct snd_dma_buffer dmab; -}; - -#endif diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c deleted file mode 100644 index cdd2f7cf50ae..000000000000 --- a/sound/soc/intel/common/sst-dsp.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Smart Sound Technology (SST) DSP Core Driver - * - * Copyright (C) 2013, Intel Corporation - */ - -#include <linux/slab.h> -#include <linux/export.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io-64-nonatomic-lo-hi.h> -#include <linux/delay.h> - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" - -#define CREATE_TRACE_POINTS -#include <trace/events/intel-sst.h> - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) -{ - writel(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write); - -u32 sst_shim32_read(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read); - -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) -{ - writeq(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write64); - -u64 sst_shim32_read64(void __iomem *addr, u32 offset) -{ - return readq(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read64); - -/* Public API */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst->ops->write(sst->addr.shim, offset, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write); - -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) -{ - unsigned long flags; - u32 val; - - spin_lock_irqsave(&sst->spinlock, flags); - val = sst->ops->read(sst->addr.shim, offset); - spin_unlock_irqrestore(&sst->spinlock, flags); - - return val; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read); - -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) -{ - sst->ops->write(sst->addr.shim, offset, value); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); - -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) -{ - return sst->ops->read(sst->addr.shim, offset); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); - -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - bool change; - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - change = (old != new); - if (change) - sst_dsp_shim_write_unlocked(sst, offset, new); - - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - sst_dsp_shim_write_unlocked(sst, offset, new); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); - -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - bool change; - - spin_lock_irqsave(&sst->spinlock, flags); - change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); - -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation) -{ - u32 reg; - unsigned long timeout; - int k = 0, s = 500; - - /* - * split the loop into sleeps of varying resolution. more accurately, - * the range of wakeups are: - * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. - * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms - * (usleep_range (500, 1000) and usleep_range(5000, 10000) are - * both possible in this phase depending on whether k > 10 or not). - * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. - */ - - timeout = jiffies + msecs_to_jiffies(time); - while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target) - && time_before(jiffies, timeout)) { - k++; - if (k > 10) - s = 5000; - - usleep_range(s, 2*s); - } - - if ((reg & mask) == target) { - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", - reg, operation); - - return 0; - } - - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", - reg, operation); - return -ETIME; -} -EXPORT_SYMBOL_GPL(sst_dsp_register_poll); - -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, - u32 outbox_offset, size_t outbox_size) -{ - sst->mailbox.in_base = sst->addr.lpe + inbox_offset; - sst->mailbox.out_base = sst->addr.lpe + outbox_offset; - sst->mailbox.in_size = inbox_size; - sst->mailbox.out_size = outbox_size; - return 0; -} -EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); - -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_write(bytes); - - memcpy_toio(sst->mailbox.out_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); - -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.out_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); - -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_write(bytes); - - memcpy_toio(sst->mailbox.in_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); - -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.in_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); - -/* Module information */ -MODULE_AUTHOR("Liam Girdwood"); -MODULE_DESCRIPTION("Intel SST Core"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h deleted file mode 100644 index 998b1a052281..000000000000 --- a/sound/soc/intel/common/sst-dsp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology (SST) Core - * - * Copyright (C) 2013, Intel Corporation - */ - -#ifndef __SOUND_SOC_SST_DSP_H -#define __SOUND_SOC_SST_DSP_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> - -struct sst_dsp; - -/* - * SST Device. - * - * This structure is populated by the SST core driver. - */ -struct sst_dsp_device { - /* Mandatory fields */ - struct sst_ops *ops; - irqreturn_t (*thread)(int irq, void *context); - void *thread_context; -}; - -/* SHIM Read / Write */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* SHIM Read / Write Unlocked for callers already holding sst lock */ -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); -u32 sst_shim32_read(void __iomem *addr, u32 offset); -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value); -u64 sst_shim32_read64(void __iomem *addr, u32 offset); - -/* Mailbox management */ -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, - size_t inbox_size, u32 outbox_offset, size_t outbox_size); -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes); -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation); - -#endif diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c deleted file mode 100644 index 6b2c83f9f010..000000000000 --- a/sound/soc/intel/common/sst-ipc.c +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/wait.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <sound/asound.h> - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" -#include "sst-ipc.h" - -/* IPC message timeout (msecs) */ -#define IPC_TIMEOUT_MSECS 300 - -#define IPC_EMPTY_LIST_SIZE 8 - -/* locks held by caller */ -static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) -{ - struct ipc_message *msg = NULL; - - if (!list_empty(&ipc->empty_list)) { - msg = list_first_entry(&ipc->empty_list, struct ipc_message, - list); - list_del(&msg->list); - } - - return msg; -} - -static int tx_wait_done(struct sst_generic_ipc *ipc, - struct ipc_message *msg, struct sst_ipc_message *reply) -{ - unsigned long flags; - int ret; - - /* wait for DSP completion (in all cases atm inc pending) */ - ret = wait_event_timeout(msg->waitq, msg->complete, - msecs_to_jiffies(IPC_TIMEOUT_MSECS)); - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - if (ret == 0) { - if (ipc->ops.shim_dbg != NULL) - ipc->ops.shim_dbg(ipc, "message timeout"); - - list_del(&msg->list); - ret = -ETIMEDOUT; - } else { - - /* copy the data returned from DSP */ - if (reply) { - reply->header = msg->rx.header; - if (reply->data) - memcpy(reply->data, msg->rx.data, msg->rx.size); - } - ret = msg->errno; - } - - list_add_tail(&msg->list, &ipc->empty_list); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return ret; -} - -static int ipc_tx_message(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, - struct sst_ipc_message *reply, int wait) -{ - struct ipc_message *msg; - unsigned long flags; - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - - msg = msg_get_empty(ipc); - if (msg == NULL) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return -EBUSY; - } - - msg->tx.header = request.header; - msg->tx.size = request.size; - msg->rx.header = 0; - msg->rx.size = reply ? reply->size : 0; - msg->wait = wait; - msg->errno = 0; - msg->pending = false; - msg->complete = false; - - if ((request.size) && (ipc->ops.tx_data_copy != NULL)) - ipc->ops.tx_data_copy(msg, request.data, request.size); - - list_add_tail(&msg->list, &ipc->tx_list); - schedule_work(&ipc->kwork); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - - if (wait) - return tx_wait_done(ipc, msg, reply); - else - return 0; -} - -static int msg_empty_list_init(struct sst_generic_ipc *ipc) -{ - int i; - - ipc->msg = kcalloc(IPC_EMPTY_LIST_SIZE, sizeof(struct ipc_message), - GFP_KERNEL); - if (ipc->msg == NULL) - return -ENOMEM; - - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].tx.data == NULL) - goto free_mem; - - ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].rx.data == NULL) { - kfree(ipc->msg[i].tx.data); - goto free_mem; - } - - init_waitqueue_head(&ipc->msg[i].waitq); - list_add(&ipc->msg[i].list, &ipc->empty_list); - } - - return 0; - -free_mem: - while (i > 0) { - kfree(ipc->msg[i-1].tx.data); - kfree(ipc->msg[i-1].rx.data); - --i; - } - kfree(ipc->msg); - - return -ENOMEM; -} - -static void ipc_tx_msgs(struct work_struct *work) -{ - struct sst_generic_ipc *ipc = - container_of(work, struct sst_generic_ipc, kwork); - struct ipc_message *msg; - - spin_lock_irq(&ipc->dsp->spinlock); - - while (!list_empty(&ipc->tx_list) && !ipc->pending) { - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of processing - * completion irq - */ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - break; - } - - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); - - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); - } - - spin_unlock_irq(&ipc->dsp->spinlock); -} - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - int ret; - - /* - * DSP maybe in lower power active state, so - * check if the DSP supports DSP lp On method - * if so invoke that before sending IPC - */ - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) - return -EIO; - - ret = ipc_tx_message(ipc, request, reply, 1); - - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) - return -EIO; - - return ret; -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request) -{ - return ipc_tx_message(ipc, request, NULL, 0); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - return ipc_tx_message(ipc, request, reply, 1); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header) -{ - struct ipc_message *msg; - u64 mask; - - if (ipc->ops.reply_msg_match != NULL) - header = ipc->ops.reply_msg_match(header, &mask); - else - mask = (u64)-1; - - if (list_empty(&ipc->rx_list)) { - dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", - header); - return NULL; - } - - list_for_each_entry(msg, &ipc->rx_list, list) { - if ((msg->tx.header & mask) == header) - return msg; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg); - -/* locks held by caller */ -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg) -{ - msg->complete = true; - - if (!msg->wait) - list_add_tail(&msg->list, &ipc->empty_list); - else - wake_up(&msg->waitq); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete); - -int sst_ipc_init(struct sst_generic_ipc *ipc) -{ - int ret; - - INIT_LIST_HEAD(&ipc->tx_list); - INIT_LIST_HEAD(&ipc->rx_list); - INIT_LIST_HEAD(&ipc->empty_list); - init_waitqueue_head(&ipc->wait_txq); - - ret = msg_empty_list_init(ipc); - if (ret < 0) - return -ENOMEM; - - INIT_WORK(&ipc->kwork, ipc_tx_msgs); - return 0; -} -EXPORT_SYMBOL_GPL(sst_ipc_init); - -void sst_ipc_fini(struct sst_generic_ipc *ipc) -{ - int i; - - cancel_work_sync(&ipc->kwork); - - if (ipc->msg) { - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - kfree(ipc->msg[i].tx.data); - kfree(ipc->msg[i].rx.data); - } - kfree(ipc->msg); - } -} -EXPORT_SYMBOL_GPL(sst_ipc_fini); - -/* Module information */ -MODULE_AUTHOR("Jin Yao"); -MODULE_DESCRIPTION("Intel SST IPC generic"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h deleted file mode 100644 index 86d44ceadc92..000000000000 --- a/sound/soc/intel/common/sst-ipc.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation - */ - -#ifndef __SST_GENERIC_IPC_H -#define __SST_GENERIC_IPC_H - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/list.h> -#include <linux/workqueue.h> -#include <linux/sched.h> - -struct sst_ipc_message { - u64 header; - void *data; - size_t size; -}; - -struct ipc_message { - struct list_head list; - struct sst_ipc_message tx; - struct sst_ipc_message rx; - - wait_queue_head_t waitq; - bool pending; - bool complete; - bool wait; - int errno; -}; - -struct sst_generic_ipc; -struct sst_dsp; - -struct sst_plat_ipc_ops { - void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); - void (*shim_dbg)(struct sst_generic_ipc *, const char *); - void (*tx_data_copy)(struct ipc_message *, char *, size_t); - u64 (*reply_msg_match)(u64 header, u64 *mask); - bool (*is_dsp_busy)(struct sst_dsp *dsp); - int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); -}; - -/* SST generic IPC data */ -struct sst_generic_ipc { - struct device *dev; - struct sst_dsp *dsp; - - /* IPC messaging */ - struct list_head tx_list; - struct list_head rx_list; - struct list_head empty_list; - wait_queue_head_t wait_txq; - struct task_struct *tx_thread; - struct work_struct kwork; - bool pending; - struct ipc_message *msg; - int tx_data_max_size; - int rx_data_max_size; - - struct sst_plat_ipc_ops ops; -}; - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header); - -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg); - -int sst_ipc_init(struct sst_generic_ipc *ipc); -void sst_ipc_fini(struct sst_generic_ipc *ipc); - -#endif diff --git a/sound/soc/loongson/Kconfig b/sound/soc/loongson/Kconfig index b8d7e2bade24..2d8291c1443c 100644 --- a/sound/soc/loongson/Kconfig +++ b/sound/soc/loongson/Kconfig @@ -1,11 +1,23 @@ # SPDX-License-Identifier: GPL-2.0 menu "SoC Audio for Loongson CPUs" + +config SND_SOC_LOONGSON_CARD + tristate "Loongson Sound Card Driver" depends on LOONGARCH || COMPILE_TEST + select SND_SOC_LOONGSON_I2S_PCI if PCI + select SND_SOC_LOONGSON_I2S_PLATFORM if OF + help + Say Y or M if you want to add support for SoC audio using + loongson I2S controller. + + The driver add support for ALSA SoC Audio support using + loongson I2S controller. config SND_SOC_LOONGSON_I2S_PCI tristate "Loongson I2S-PCI Device Driver" - select REGMAP_MMIO + depends on LOONGARCH || COMPILE_TEST depends on PCI + select REGMAP_MMIO help Say Y or M if you want to add support for I2S driver for Loongson I2S controller. @@ -13,15 +25,15 @@ config SND_SOC_LOONGSON_I2S_PCI The controller is found in loongson bridge chips or SoCs, and work as a PCI device. -config SND_SOC_LOONGSON_CARD - tristate "Loongson Sound Card Driver" - select SND_SOC_LOONGSON_I2S_PCI - depends on PCI +config SND_SOC_LOONGSON_I2S_PLATFORM + tristate "Loongson I2S-PLAT Device Driver" + depends on LOONGARCH || COMPILE_TEST + select REGMAP_MMIO + select SND_SOC_GENERIC_DMAENGINE_PCM help - Say Y or M if you want to add support for SoC audio using - loongson I2S controller. - - The driver add support for ALSA SoC Audio support using - loongson I2S controller. + Say Y or M if you want to add support for I2S driver for + Loongson I2S controller. + The controller work as a platform device, we can found it in + Loongson-2K1000 SoCs. endmenu diff --git a/sound/soc/loongson/Makefile b/sound/soc/loongson/Makefile index 578030ad6563..c0cb1acb36e3 100644 --- a/sound/soc/loongson/Makefile +++ b/sound/soc/loongson/Makefile @@ -1,7 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 #Platform Support -snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_i2s.o loongson_dma.o -obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o +snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o +obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o + +snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o +obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o + +snd-soc-loongson-i2s-y := loongson_i2s.o #Machine Support snd-soc-loongson-card-y := loongson_card.o diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index 40bbf3205391..e8852a30f213 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -246,6 +246,7 @@ struct snd_soc_dai_driver loongson_i2s_dai = { .ops = &loongson_i2s_dai_ops, .symmetric_rate = 1, }; +EXPORT_SYMBOL_GPL(loongson_i2s_dai); static int i2s_suspend(struct device *dev) { @@ -268,3 +269,7 @@ static int i2s_resume(struct device *dev) const struct dev_pm_ops loongson_i2s_pm = { SYSTEM_SLEEP_PM_OPS(i2s_suspend, i2s_resume) }; +EXPORT_SYMBOL_GPL(loongson_i2s_pm); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Common functions for loongson I2S controller driver"); diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c new file mode 100644 index 000000000000..fa2e450ff618 --- /dev/null +++ b/sound/soc/loongson/loongson_i2s_plat.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Loongson I2S controller master mode dirver(platform device) +// +// Copyright (C) 2023-2024 Loongson Technology Corporation Limited +// +// Author: Yingkun Meng <mengyingkun@loongson.cn> +// Binbin Zhou <zhoubinbin@loongson.cn> + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/of_dma.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "loongson_i2s.h" + +#define LOONGSON_I2S_RX_DMA_OFFSET 21 +#define LOONGSON_I2S_TX_DMA_OFFSET 18 + +#define LOONGSON_DMA0_CONF 0x0 +#define LOONGSON_DMA1_CONF 0x1 +#define LOONGSON_DMA2_CONF 0x2 +#define LOONGSON_DMA3_CONF 0x3 +#define LOONGSON_DMA4_CONF 0x4 + +/* periods_max = PAGE_SIZE / sizeof(struct ls_dma_chan_reg) */ +static const struct snd_pcm_hardware loongson_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + .period_bytes_min = 128, + .period_bytes_max = 128 * 1024, + .periods_min = 1, + .periods_max = 64, + .buffer_bytes_max = 1024 * 1024, +}; + +static const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = { + .pcm_hardware = &loongson_pcm_hardware, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .prealloc_buffer_size = 128 * 1024, +}; + +static int loongson_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + if (substream->pcm->device & 1) { + runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; + runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; + } + + if (substream->pcm->device & 2) + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID); + /* + * For mysterious reasons (and despite what the manual says) + * playback samples are lost if the DMA count is not a multiple + * of the DMA burst size. Let's add a rule to enforce that. + */ + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + return 0; +} + +static const struct snd_soc_component_driver loongson_i2s_component_driver = { + .name = LS_I2S_DRVNAME, + .open = loongson_pcm_open, +}; + +static const struct regmap_config loongson_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14, + .cache_type = REGCACHE_FLAT, +}; + +static int loongson_i2s_apbdma_config(struct platform_device *pdev) +{ + int val; + void __iomem *regs; + + regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + val = readl(regs); + val |= LOONGSON_DMA2_CONF << LOONGSON_I2S_TX_DMA_OFFSET; + val |= LOONGSON_DMA3_CONF << LOONGSON_I2S_RX_DMA_OFFSET; + writel(val, regs); + + return 0; +} + +static int loongson_i2s_plat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct loongson_i2s *i2s; + struct resource *res; + struct clk *i2s_clk; + int ret; + + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + ret = loongson_i2s_apbdma_config(pdev); + if (ret) + return ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2s->reg_base)) + return dev_err_probe(dev, PTR_ERR(i2s->reg_base), + "devm_ioremap_resource failed\n"); + + i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base, + &loongson_i2s_regmap_config); + if (IS_ERR(i2s->regmap)) + return dev_err_probe(dev, PTR_ERR(i2s->regmap), + "devm_regmap_init_mmio failed\n"); + + i2s->playback_dma_data.addr = res->start + LS_I2S_TX_DATA; + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->playback_dma_data.maxburst = 4; + + i2s->capture_dma_data.addr = res->start + LS_I2S_RX_DATA; + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->capture_dma_data.maxburst = 4; + + i2s_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(i2s_clk)) + return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n"); + i2s->clk_rate = clk_get_rate(i2s_clk); + + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + dev_set_name(dev, LS_I2S_DRVNAME); + dev_set_drvdata(dev, i2s); + + ret = devm_snd_soc_register_component(dev, &loongson_i2s_component_driver, + &loongson_i2s_dai, 1); + if (ret) + return dev_err_probe(dev, ret, "failed to register DAI\n"); + + return devm_snd_dmaengine_pcm_register(dev, &loongson_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_COMPAT); +} + +static const struct of_device_id loongson_i2s_ids[] = { + { .compatible = "loongson,ls2k1000-i2s" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, loongson_i2s_ids); + +static struct platform_driver loongson_i2s_driver = { + .probe = loongson_i2s_plat_probe, + .driver = { + .name = "loongson-i2s-plat", + .pm = pm_sleep_ptr(&loongson_i2s_pm), + .of_match_table = loongson_i2s_ids, + }, +}; +module_platform_driver(loongson_i2s_driver); + +MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 4974b0536b7b..00a79867235d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -221,7 +221,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(fe_multi_ch_out), }, [DAI_LINK_FE_PCM0_IN] = { @@ -231,7 +231,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_pcm0_in), }, [DAI_LINK_FE_PCM1_IN] = { @@ -241,7 +241,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_pcm1_in), }, [DAI_LINK_FE_BT_OUT] = { @@ -250,7 +250,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(fe_bt_out), }, [DAI_LINK_FE_BT_IN] = { @@ -259,7 +259,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_bt_in), }, /* BE */ @@ -269,8 +269,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s0), }, [DAI_LINK_BE_I2S1] = { @@ -279,8 +277,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s1), }, [DAI_LINK_BE_I2S2] = { @@ -289,8 +285,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s2), }, [DAI_LINK_BE_I2S3] = { @@ -299,15 +293,11 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s3), }, [DAI_LINK_BE_MRG_BT] = { .name = "mt2701-cs42448-MRG-BT", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_mrg_bt), }, }; diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 8a6643bfe830..2814f0570928 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -67,7 +67,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -76,7 +76,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* BE */ @@ -86,8 +86,6 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_wm8960_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 784c201b8fd4..daad9544a8d4 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -78,7 +78,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_1), }, { @@ -87,7 +87,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_2), }, { @@ -96,7 +96,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_3), }, { @@ -105,7 +105,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_1), }, { @@ -114,7 +114,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_2), }, { @@ -123,7 +123,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_3), }, { @@ -132,7 +132,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono_1), }, { @@ -141,8 +141,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_lpbk), }, @@ -152,8 +150,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_speech), }, @@ -161,24 +157,18 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c index 6982e833421d..c3d1e2eeb0e5 100644 --- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -45,7 +45,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -54,7 +54,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* BE */ @@ -65,8 +65,6 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 0557a287c641..0724564cee6a 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -104,7 +104,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .stream_name = "MAX98090 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -112,7 +112,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .stream_name = "MAX98090 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* Back End DAI links */ @@ -123,8 +123,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .ops = &mt8173_max98090_ops, .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(hifi), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 4ed06c269065..d8e4e70d834c 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -139,7 +139,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { .stream_name = "rt5650_rt5514 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -147,7 +147,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { .stream_name = "rt5650_rt5514 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* Back End DAI links */ @@ -159,8 +159,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_rt5514_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 763067c21153..488f2314dbf7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -171,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "rt5650_rt5676 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -179,7 +179,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "rt5650_rt5676 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, [DAI_LINK_HDMI] = { @@ -187,7 +187,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "HDMI PCM", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_pcm), }, @@ -200,14 +200,12 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_rt5676_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, [DAI_LINK_HDMI_I2S] = { .name = "HDMI BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_be), }, /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 466f176f8e94..59c19fdd8675 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -210,7 +210,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "rt5650 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -218,7 +218,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "rt5650 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, [DAI_LINK_HDMI] = { @@ -226,7 +226,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "HDMI PCM", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_pcm), }, /* Back End DAI links */ @@ -238,14 +238,12 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, [DAI_LINK_HDMI_I2S] = { .name = "HDMI BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .init = mt8173_rt5650_hdmi_init, SND_SOC_DAILINK_REG(hdmi_be), }, diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index f848e14b091a..1d8881e0a361 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -425,7 +425,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_da7219_max98357_ops, SND_SOC_DAILINK_REG(playback1), }, @@ -435,7 +435,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_da7219_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(playback2), }, @@ -445,7 +445,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback3), }, { @@ -454,7 +454,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_da7219_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -464,7 +464,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, { @@ -473,7 +473,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_da7219_max98357_ops, SND_SOC_DAILINK_REG(capture3), }, @@ -483,7 +483,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono), }, { @@ -492,38 +492,32 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, /* BE */ { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -532,7 +526,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -541,7 +535,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_da7219_i2s_ops, @@ -551,13 +545,13 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, }, { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -570,7 +564,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ignore = 1, diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c index 65e46ebe7be6..5cf5592336d3 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -1036,7 +1036,6 @@ static int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) int mt8183_dai_i2s_register(struct mtk_base_afe *afe) { struct mtk_base_afe_dai *dai; - int ret; dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); if (!dai) @@ -1055,9 +1054,5 @@ int mt8183_dai_i2s_register(struct mtk_base_afe *afe) dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); /* set all dai i2s private data */ - ret = mt8183_dai_i2s_set_priv(afe); - if (ret) - return ret; - - return 0; + return mt8183_dai_i2s_set_priv(afe); } diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index bb6df056a878..6267c8554c15 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -430,7 +430,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_mt6358_ops, SND_SOC_DAILINK_REG(playback1), }, @@ -440,7 +440,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(playback2), }, @@ -450,7 +450,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback3), }, { @@ -459,7 +459,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -469,7 +469,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, { @@ -478,7 +478,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_mt6358_ops, SND_SOC_DAILINK_REG(capture3), }, @@ -488,7 +488,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono), }, { @@ -497,7 +497,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, { @@ -513,31 +513,25 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .ops = &mt8183_mt6358_i2s_ops, SND_SOC_DAILINK_REG(i2s0), @@ -545,7 +539,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -554,7 +548,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -564,13 +558,13 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, }, { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .ops = &mt8183_mt6358_i2s_ops, .init = &mt8183_bt_init, @@ -582,7 +576,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_tdm_ops, diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c index 771d53611c2a..a5ef913743d4 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c @@ -647,7 +647,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -660,7 +660,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback12), }, { @@ -669,7 +669,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -681,7 +681,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -694,7 +694,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback4), }, { @@ -703,7 +703,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback5), }, { @@ -712,7 +712,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback6), }, { @@ -721,7 +721,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, { @@ -730,7 +730,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, { @@ -739,7 +739,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture1), }, { @@ -748,7 +748,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -761,7 +761,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, { @@ -770,7 +770,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -783,7 +783,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture5), }, { @@ -792,7 +792,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -804,7 +804,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture7), }, { @@ -813,8 +813,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_lpbk), }, @@ -824,8 +822,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_fm), }, @@ -835,8 +831,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src1), }, @@ -846,8 +840,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src_bargein), }, @@ -857,7 +849,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio), }, @@ -867,8 +859,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src_aaudio), }, @@ -876,8 +866,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, .init = primary_codec_init, SND_SOC_DAILINK_REG(adda), @@ -888,7 +876,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .init = mt8186_mt6366_rt1019_rt5682s_hdmi_init, SND_SOC_DAILINK_REG(i2s3), @@ -896,7 +884,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .ops = &mt8186_rt5682s_i2s_ops, SND_SOC_DAILINK_REG(i2s0), @@ -904,7 +892,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .init = mt8186_headset_codec_init, SND_SOC_DAILINK_REG(i2s1), @@ -912,46 +900,38 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(i2s2), }, { .name = "HW Gain 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_gain1), }, { .name = "HW Gain 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_gain2), }, { .name = "HW_SRC_1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_src1), }, { .name = "HW_SRC_2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_src2), }, { .name = "CONNSYS_I2S", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(connsys_i2s), }, @@ -960,15 +940,13 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "TDM IN", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(tdm_in), }, @@ -976,35 +954,35 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "Hostless_UL1", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul1), }, { .name = "Hostless_UL2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul2), }, { .name = "Hostless_UL3", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul3), }, { .name = "Hostless_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul5), }, { .name = "Hostless_UL6", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul6), }, @@ -1012,25 +990,25 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "AFE_SOF_DL1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_DL1), }, { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, { .name = "AFE_SOF_UL1", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_UL1), }, { .name = "AFE_SOF_UL2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_UL2), }, }; diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c index 8a17d1935c48..43670316611e 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c @@ -63,7 +63,6 @@ static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe) param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0]; } - val = 0; mask = (MTKAIF_RXIF_DELAY_DATA | MTKAIF_RXIF_DELAY_CYCLE_MASK); val |= FIELD_PREP(MTKAIF_RXIF_DELAY_CYCLE_MASK, delay_cycle); val |= FIELD_PREP(MTKAIF_RXIF_DELAY_DATA, delay_data); diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c index 2a48f5fd6826..69a091dad88d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c @@ -2422,7 +2422,6 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); snd_pcm_format_t format = params_format(params); int width = snd_pcm_format_physical_width(format); - int ret; if (!is_valid_etdm_dai(dai->id)) return -EINVAL; @@ -2450,9 +2449,7 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN; } - ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); - - return ret; + return mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); } static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c index 5bc854a8f3df..8ca7cc75e21d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c @@ -128,7 +128,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, unsigned int lrck_inv; unsigned int bck_inv; unsigned int fmt; - unsigned int bit_width = dai->sample_bits; + unsigned int bit_width = dai->symmetric_sample_bits; unsigned int val = 0; unsigned int mask = 0; int fs = 0; diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index 08ae962afeb9..84abdba9ddb6 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -932,7 +932,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -946,7 +946,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -960,7 +960,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -974,7 +974,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, [DAI_LINK_DL8_FE] = { @@ -985,7 +985,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, [DAI_LINK_DL10_FE] = { @@ -996,7 +996,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback10), }, [DAI_LINK_DL11_FE] = { @@ -1007,7 +1007,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback11), }, [DAI_LINK_UL1_FE] = { @@ -1018,7 +1018,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture1), }, [DAI_LINK_UL2_FE] = { @@ -1029,7 +1029,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, [DAI_LINK_UL3_FE] = { @@ -1040,7 +1040,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, [DAI_LINK_UL4_FE] = { @@ -1051,7 +1051,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -1065,7 +1065,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -1079,7 +1079,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture6), }, [DAI_LINK_UL8_FE] = { @@ -1090,7 +1090,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture8), }, [DAI_LINK_UL9_FE] = { @@ -1101,7 +1101,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture9), }, [DAI_LINK_UL10_FE] = { @@ -1112,14 +1112,14 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture10), }, /* BE */ [DAI_LINK_DL_SRC_BE] = { .name = "DL_SRC_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(dl_src), }, [DAI_LINK_DPTX_BE] = { @@ -1127,7 +1127,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .ops = &mt8188_dptx_ops, .be_hw_params_fixup = mt8188_dptx_hw_params_fixup, .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(dptx), }, [DAI_LINK_ETDM1_IN_BE] = { @@ -1136,7 +1136,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(etdm1_in), }, @@ -1146,7 +1146,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(etdm2_in), }, [DAI_LINK_ETDM1_OUT_BE] = { @@ -1155,7 +1155,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm1_out), }, [DAI_LINK_ETDM2_OUT_BE] = { @@ -1164,7 +1164,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm2_out), }, [DAI_LINK_ETDM3_OUT_BE] = { @@ -1173,7 +1173,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm3_out), }, [DAI_LINK_PCM1_BE] = { @@ -1182,14 +1182,12 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(pcm1), }, [DAI_LINK_UL_SRC_BE] = { .name = "UL_SRC_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(ul_src), }, @@ -1197,28 +1195,28 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { [DAI_LINK_SOF_DL2_BE] = { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, [DAI_LINK_SOF_DL3_BE] = { .name = "AFE_SOF_DL3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL3), }, [DAI_LINK_SOF_UL4_BE] = { .name = "AFE_SOF_UL4", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL4), }, [DAI_LINK_SOF_UL5_BE] = { .name = "AFE_SOF_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL5), }, diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index db00704e206d..1aba9c75594e 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -598,7 +598,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback1), }, { @@ -607,7 +607,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback12), }, { @@ -616,7 +616,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback2), }, { @@ -625,7 +625,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(playback3), }, @@ -635,7 +635,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback4), }, { @@ -644,7 +644,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback5), }, { @@ -653,7 +653,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback6), }, { @@ -662,7 +662,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, { @@ -671,7 +671,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, { @@ -680,7 +680,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback9), }, { @@ -689,7 +689,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -699,7 +699,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(capture2), }, @@ -709,7 +709,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, { @@ -718,7 +718,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture4), }, { @@ -727,7 +727,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture5), }, { @@ -736,7 +736,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture6), }, { @@ -745,7 +745,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture7), }, { @@ -754,7 +754,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture8), }, { @@ -763,7 +763,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono1), }, { @@ -772,7 +772,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono2), }, { @@ -781,7 +781,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono3), }, { @@ -790,15 +790,13 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, /* Back End DAI links */ { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, .init = mt8192_mt6359_init, SND_SOC_DAILINK_REG(primary_codec), @@ -806,29 +804,27 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "Primary Codec CH34", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec_ch34), }, { .name = "AP_DMIC", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(ap_dmic), }, { .name = "AP_DMIC_CH34", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(ap_dmic_ch34), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s0), @@ -836,7 +832,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s1), @@ -844,7 +840,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s2), @@ -852,7 +848,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s3), @@ -860,7 +856,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s5), @@ -868,7 +864,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S6", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s6), @@ -876,7 +872,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S7", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s7), @@ -884,7 +880,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S8", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .init = mt8192_rt5682_init, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, @@ -894,7 +890,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S9", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s9), @@ -903,23 +899,19 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "CONNSYS_I2S", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(connsys_i2s), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, @@ -929,7 +921,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, .ignore = 1, diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 6d6d79300d51..cdc16057d50e 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -127,7 +127,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, unsigned int lrck_inv; unsigned int bck_inv; unsigned int fmt; - unsigned int bit_width = dai->sample_bits; + unsigned int bit_width = dai->symmetric_sample_bits; unsigned int val = 0; unsigned int mask = 0; int fs = 0; diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 2832ef78eaed..56b9d2433a1e 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -913,7 +913,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL2_FE), }, @@ -925,7 +925,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL3_FE), }, @@ -937,7 +937,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL6_FE), }, @@ -949,7 +949,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(DL7_FE), }, [DAI_LINK_DL8_FE] = { @@ -960,7 +960,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL8_FE), }, @@ -972,7 +972,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_hdmitx_dptx_playback_ops, SND_SOC_DAILINK_REG(DL10_FE), }, @@ -984,7 +984,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL11_FE), }, @@ -996,7 +996,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL1_FE), }, [DAI_LINK_UL2_FE] = { @@ -1007,7 +1007,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL2_FE), }, @@ -1019,7 +1019,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL3_FE), }, @@ -1031,7 +1031,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL4_FE), }, @@ -1043,7 +1043,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL5_FE), }, @@ -1055,7 +1055,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL6_FE), }, [DAI_LINK_UL8_FE] = { @@ -1066,7 +1066,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL8_FE), }, @@ -1078,7 +1078,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL9_FE), }, @@ -1090,7 +1090,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL10_FE), }, @@ -1098,13 +1098,13 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { [DAI_LINK_DL_SRC_BE] = { .name = "DL_SRC_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(DL_SRC_BE), }, [DAI_LINK_DPTX_BE] = { .name = "DPTX_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_dptx_ops, .be_hw_params_fixup = mt8195_dptx_hw_params_fixup, SND_SOC_DAILINK_REG(DPTX_BE), @@ -1115,7 +1115,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(ETDM1_IN_BE), }, [DAI_LINK_ETDM2_IN_BE] = { @@ -1124,7 +1124,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_capture = 1, + .capture_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM2_IN_BE), }, @@ -1134,7 +1134,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM1_OUT_BE), }, @@ -1144,7 +1144,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(ETDM2_OUT_BE), }, [DAI_LINK_ETDM3_OUT_BE] = { @@ -1153,7 +1153,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(ETDM3_OUT_BE), }, [DAI_LINK_PCM1_BE] = { @@ -1162,48 +1162,46 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .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(PCM1_BE), }, [DAI_LINK_UL_SRC1_BE] = { .name = "UL_SRC1_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL_SRC1_BE), }, [DAI_LINK_UL_SRC2_BE] = { .name = "UL_SRC2_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL_SRC2_BE), }, /* SOF BE */ [DAI_LINK_SOF_DL2_BE] = { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, [DAI_LINK_SOF_DL3_BE] = { .name = "AFE_SOF_DL3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL3), }, [DAI_LINK_SOF_UL4_BE] = { .name = "AFE_SOF_UL4", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL4), }, [DAI_LINK_SOF_UL5_BE] = { .name = "AFE_SOF_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL5), }, diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c index f9945c2a2cd1..0bac143b48bf 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c @@ -118,13 +118,13 @@ static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe, 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); + unsigned int rate = dai->symmetric_rate; + int reg = get_chan_reg(dai->symmetric_channels); if (reg < 0) return -EINVAL; - dmic_data->dmic_channel = dai->channels; + dmic_data->dmic_channel = dai->symmetric_channels; val |= DMIC_TOP_CON_SDM3_LEVEL_MODE; diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c index f85ec07249c3..3373b88da28e 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c @@ -44,7 +44,7 @@ static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream, 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 bit_width = dai->symmetric_sample_bits; unsigned int val = 0; if (!slave_mode) { diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 42cbdfdfadb5..d398e83ea052 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -168,7 +168,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(playback1), }, @@ -181,7 +181,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(playback2), }, @@ -194,7 +194,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(awb_capture), }, @@ -207,7 +207,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(vul), }, @@ -219,23 +219,19 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { .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, + .capture_only = 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), }, diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 5ebf287fe700..a2dfccb7990f 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -43,7 +43,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } @@ -56,7 +56,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; struct snd_soc_dai *codec_dai; int ret, i; @@ -86,7 +86,7 @@ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; int ret; /* The loopback rx_mask is the pad tx_mask */ diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 62057c71f742..09103eef2a97 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -442,14 +442,18 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Playback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_PAD, @@ -461,7 +465,9 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Loopback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_LOOPBACK, diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h index 1a17f546ce6e..acfcd48f8a00 100644 --- a/sound/soc/meson/axg-tdm.h +++ b/sound/soc/meson/axg-tdm.h @@ -15,8 +15,6 @@ #define AXG_TDM_NUM_LANES 4 #define AXG_TDM_CHANNEL_MAX 128 -#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_768000) #define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c index 455f6bfc9f8f..b408cc2bbc91 100644 --- a/sound/soc/meson/gx-card.c +++ b/sound/soc/meson/gx-card.c @@ -32,7 +32,7 @@ static int gx_card_i2s_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct gx_dai_link_i2s_data *be = - (struct gx_dai_link_i2s_data *)priv->link_data[rtd->num]; + (struct gx_dai_link_i2s_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 922ecada1cd8..311377317176 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -190,6 +190,7 @@ static const struct of_device_id snd_sc8280xp_dt_match[] = { {.compatible = "qcom,sm8450-sndcard", "sm8450"}, {.compatible = "qcom,sm8550-sndcard", "sm8550"}, {.compatible = "qcom,sm8650-sndcard", "sm8650"}, + {.compatible = "qcom,sm8750-sndcard", "sm8750"}, {} }; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 19adadedc88a..45e0c33fc3f3 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -63,6 +63,14 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case SECONDARY_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_SEC_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, @@ -78,7 +86,7 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) return qcom_snd_sdw_startup(substream); } -static void sm2450_snd_shutdown(struct snd_pcm_substream *substream) +static void sm8250_snd_shutdown(struct snd_pcm_substream *substream) { 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); @@ -123,7 +131,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sm8250_be_ops = { .startup = sm8250_snd_startup, - .shutdown = sm2450_snd_shutdown, + .shutdown = sm8250_snd_shutdown, .hw_params = sm8250_snd_hw_params, .hw_free = sm8250_snd_hw_free, .prepare = sm8250_snd_prepare, diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 898b5c26bf1e..8eb57fc12f0d 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -95,23 +95,53 @@ static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream, return qcom_snd_sdw_hw_params(substream, params, &data->sruntime[cpu_dai->id]); } +static int x1e80100_snd_hw_map_channels(unsigned int *ch_map, int num) +{ + switch (num) { + case 1: + ch_map[0] = PCM_CHANNEL_FC; + break; + case 2: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + break; + case 3: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + ch_map[2] = PCM_CHANNEL_FC; + break; + case 4: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_LB; + ch_map[2] = PCM_CHANNEL_FR; + ch_map[3] = PCM_CHANNEL_RB; + break; + default: + return -EINVAL; + } + + return 0; +} + static int x1e80100_snd_prepare(struct snd_pcm_substream *substream) { 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 x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - const unsigned int rx_slot[4] = { PCM_CHANNEL_FL, - PCM_CHANNEL_LB, - PCM_CHANNEL_FR, - PCM_CHANNEL_RB }; + unsigned int channels = substream->runtime->channels; + unsigned int rx_slot[4]; int ret; switch (cpu_dai->id) { case WSA_CODEC_DMA_RX_0: case WSA_CODEC_DMA_RX_1: + ret = x1e80100_snd_hw_map_channels(rx_slot, channels); + if (ret) + return ret; + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, - ARRAY_SIZE(rx_slot), rx_slot); + channels, rx_slot); if (ret) return ret; break; diff --git a/sound/soc/sh/Kconfig b/sound/soc/renesas/Kconfig index 426632996a0a..426632996a0a 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/renesas/Kconfig diff --git a/sound/soc/sh/Makefile b/sound/soc/renesas/Makefile index f0e19cbd1581..f0e19cbd1581 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/renesas/Makefile diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/renesas/dma-sh7760.c index c53539482c20..c53539482c20 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/renesas/dma-sh7760.c diff --git a/sound/soc/sh/fsi.c b/sound/soc/renesas/fsi.c index 221ce91f1950..221ce91f1950 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/renesas/fsi.c diff --git a/sound/soc/sh/hac.c b/sound/soc/renesas/hac.c index db618c09d1e0..db618c09d1e0 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/renesas/hac.c diff --git a/sound/soc/sh/migor.c b/sound/soc/renesas/migor.c index 5a0bc6edac0a..5a0bc6edac0a 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/renesas/migor.c diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/renesas/rcar/Makefile index 45eb875a912a..45eb875a912a 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/renesas/rcar/Makefile diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/renesas/rcar/adg.c index 0f190abf00e7..0f190abf00e7 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/renesas/rcar/adg.c diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/renesas/rcar/cmd.c index 8d9a1e345a22..8d9a1e345a22 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/renesas/rcar/cmd.c diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/renesas/rcar/core.c index eca5ce096e54..e2234928c9e8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -1233,6 +1233,19 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name return i; } +static struct device_node* + rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports, + struct device_node *e_port) +{ + if (of_node_name_eq(e_ports, "ports")) + return e_ports; + + if (of_node_name_eq(e_ports, "port")) + return e_port; + + return NULL; +} + static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); @@ -1278,12 +1291,10 @@ audio_graph: * Audio-Graph-Card */ for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) + node = rsnd_pick_endpoint_node_for_ports(ports, np); + if (!node) continue; - priv->component_dais[i] = - of_graph_get_endpoint_count(of_node_name_eq(ports, "ports") ? - ports : np); + priv->component_dais[i] = of_graph_get_endpoint_count(node); nr += priv->component_dais[i]; i++; if (i >= RSND_MAX_COMPONENT) { @@ -1488,15 +1499,16 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) */ dai_i = 0; if (is_graph) { + struct device_node *dai_np_port; struct device_node *ports; struct device_node *dai_np; for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) + dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np); + if (!dai_np_port) continue; - for_each_endpoint_of_node(of_node_name_eq(ports, "ports") ? - ports : np, dai_np) { + + for_each_endpoint_of_node(dai_np_port, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { rdai = rsnd_rdai_get(priv, dai_i); @@ -1831,7 +1843,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = name, .info = rsnd_kctrl_info, - .index = rtd->num, + .index = rtd->id, .get = rsnd_kctrl_get, .put = rsnd_kctrl_put, }; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c index a26ec7b780cd..a26ec7b780cd 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/renesas/rcar/ctu.c diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/renesas/rcar/debugfs.c index 26d3b310b9db..26d3b310b9db 100644 --- a/sound/soc/sh/rcar/debugfs.c +++ b/sound/soc/renesas/rcar/debugfs.c diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/renesas/rcar/dma.c index 2342bbb6fe92..2342bbb6fe92 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/renesas/rcar/dma.c diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c index da91dd301aab..da91dd301aab 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/renesas/rcar/dvc.c diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/renesas/rcar/gen.c index d1f20cde66be..d1f20cde66be 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/renesas/rcar/gen.c diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/renesas/rcar/mix.c index 024d91cc8748..024d91cc8748 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/renesas/rcar/mix.c diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h index 3c164d8e3b16..3c164d8e3b16 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/renesas/rcar/rsnd.h diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/renesas/rcar/src.c index e7f86db0d94c..e7f86db0d94c 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/renesas/rcar/src.c diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c index b3d4e8ae07ef..b3d4e8ae07ef 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/renesas/rcar/ssi.c diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c index 665e8b2db579..665e8b2db579 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/renesas/rcar/ssiu.c diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/renesas/rz-ssi.c index 040ce0431fd2..6efd017aaa7f 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/renesas/rz-ssi.c @@ -311,8 +311,7 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, ssicr |= SSICR_CKDV(clk_ckdv); ssicr |= SSICR_DWL(1) | SSICR_SWL(3); rz_ssi_reg_writel(ssi, SSICR, ssicr); - rz_ssi_reg_writel(ssi, SSIFCR, - (SSIFCR_AUCKE | SSIFCR_TFRST | SSIFCR_RFRST)); + rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST); return 0; } @@ -343,8 +342,7 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) dev_info(ssi->dev, "timeout waiting for SSI idle\n"); /* Hold FIFOs in reset */ - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, - SSIFCR_TFRST | SSIFCR_RFRST); + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST); } static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/renesas/sh7760-ac97.c index d267243a159b..d267243a159b 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/renesas/sh7760-ac97.c diff --git a/sound/soc/sh/siu.h b/sound/soc/renesas/siu.h index a675c36fc9d9..a675c36fc9d9 100644 --- a/sound/soc/sh/siu.h +++ b/sound/soc/renesas/siu.h diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/renesas/siu_dai.c index 7e771a164a80..7e771a164a80 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/renesas/siu_dai.c diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/renesas/siu_pcm.c index f15ff36e7934..f15ff36e7934 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/renesas/siu_pcm.c diff --git a/sound/soc/sh/ssi.c b/sound/soc/renesas/ssi.c index 96cf523c2273..96cf523c2273 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/renesas/ssi.c diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index ed865cc07e2e..40ac12c07145 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -171,25 +171,24 @@ static struct snd_soc_dai_link odroid_card_dais[] = { .name = "Primary", .stream_name = "Primary", .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(primary), }, { /* BE <-> CODECs link */ .name = "I2S Mixer", .ops = &odroid_card_be_ops, .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAILINK_REG(mixer), }, { /* Secondary FE <-> BE link */ - .playback_only = 1, .ops = &odroid_card_fe_ops, .name = "Secondary", .stream_name = "Secondary", .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(secondary), } }; @@ -278,8 +277,8 @@ static int odroid_audio_probe(struct platform_device *pdev) /* Set capture capability only for boards with the MAX98090 CODEC */ if (codec_link->num_codecs > 1) { - card->dai_link[0].dpcm_capture = 1; - card->dai_link[1].dpcm_capture = 1; + card->dai_link[0].playback_only = 0; + card->dai_link[1].playback_only = 0; } priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig new file mode 100644 index 000000000000..ee20b9914aa1 --- /dev/null +++ b/sound/soc/sdca/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_SOC_SDCA + tristate + depends on ACPI + help + This option enables support for the MIPI SoundWire Device + Class for Audio (SDCA). + +config SND_SOC_SDCA_OPTIONAL + def_tristate SND_SOC_SDCA || !SND_SOC_SDCA diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile new file mode 100644 index 000000000000..c296bd5a0a7c --- /dev/null +++ b/sound/soc/sdca/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +snd-soc-sdca-objs := sdca_functions.o sdca_device.o + +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c new file mode 100644 index 000000000000..c44dc21cb634 --- /dev/null +++ b/sound/soc/sdca/sdca_device.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2024 Intel Corporation + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include <linux/acpi.h> +#include <linux/soundwire/sdw.h> +#include <sound/sdca.h> +#include <sound/sdca_function.h> + +void sdca_lookup_interface_revision(struct sdw_slave *slave) +{ + struct fwnode_handle *fwnode = slave->dev.fwnode; + + /* + * if this property is not present, then the sdca_interface_revision will + * remain zero, which will be considered as 'not defined' or 'invalid'. + */ + fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision", + &slave->sdca_data.interface_revision); +} +EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, SND_SOC_SDCA); + +static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) +{ + struct sdw_slave_id *id = &slave->id; + int i; + + /* + * The RT712_VA relies on the v06r04 draft, and the + * RT712_VB on a more recent v08r01 draft. + */ + if (slave->sdca_data.interface_revision < 0x0801) + return false; + + if (id->mfg_id != 0x025d) + return false; + + if (id->part_id != 0x712 && + id->part_id != 0x713 && + id->part_id != 0x716 && + id->part_id != 0x717) + return false; + + for (i = 0; i < slave->sdca_data.num_functions; i++) { + if (slave->sdca_data.sdca_func[i].type == + SDCA_FUNCTION_TYPE_SMART_MIC) + return true; + } + + return false; +} + +bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) +{ + switch (quirk) { + case SDCA_QUIRKS_RT712_VB: + return sdca_device_quirk_rt712_vb(slave); + default: + break; + } + return false; +} +EXPORT_SYMBOL_NS(sdca_device_quirk_match, SND_SOC_SDCA); diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c new file mode 100644 index 000000000000..e6e5629c7054 --- /dev/null +++ b/sound/soc/sdca/sdca_functions.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2024 Intel Corporation + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include <linux/acpi.h> +#include <linux/soundwire/sdw.h> +#include <sound/sdca.h> +#include <sound/sdca_function.h> + +static int patch_sdca_function_type(struct device *dev, + u32 interface_revision, + u32 *function_type, + const char **function_name) +{ + unsigned long function_type_patch = 0; + + /* + * Unfortunately early SDCA specifications used different indices for Functions, + * for backwards compatibility we have to reorder the values found + */ + if (interface_revision >= 0x0801) + goto skip_early_draft_order; + + switch (*function_type) { + case 1: + function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP; + break; + case 2: + function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC; + break; + case 3: + function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC; + break; + case 4: + function_type_patch = SDCA_FUNCTION_TYPE_UAJ; + break; + case 5: + function_type_patch = SDCA_FUNCTION_TYPE_RJ; + break; + case 6: + function_type_patch = SDCA_FUNCTION_TYPE_HID; + break; + default: + dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n", + __func__, interface_revision, *function_type); + return -EINVAL; + } + +skip_early_draft_order: + if (function_type_patch) + *function_type = function_type_patch; + + /* now double-check the values */ + switch (*function_type) { + case SDCA_FUNCTION_TYPE_SMART_AMP: + *function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME; + break; + case SDCA_FUNCTION_TYPE_SMART_MIC: + *function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME; + break; + case SDCA_FUNCTION_TYPE_UAJ: + *function_name = SDCA_FUNCTION_TYPE_UAJ_NAME; + break; + case SDCA_FUNCTION_TYPE_HID: + *function_name = SDCA_FUNCTION_TYPE_HID_NAME; + break; + case SDCA_FUNCTION_TYPE_SIMPLE_AMP: + case SDCA_FUNCTION_TYPE_SIMPLE_MIC: + case SDCA_FUNCTION_TYPE_SPEAKER_MIC: + case SDCA_FUNCTION_TYPE_RJ: + case SDCA_FUNCTION_TYPE_IMP_DEF: + dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n", + __func__, *function_type); + return -EINVAL; + default: + dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n", + __func__, *function_type); + return -EINVAL; + } + + dev_info(dev, "%s: found SDCA function %s (type %d)\n", + __func__, *function_name, *function_type); + + return 0; +} + +static int find_sdca_function(struct acpi_device *adev, void *data) +{ + struct fwnode_handle *function_node = acpi_fwnode_handle(adev); + struct sdca_device_data *sdca_data = data; + struct device *dev = &adev->dev; + struct fwnode_handle *control5; /* used to identify function type */ + const char *function_name; + u32 function_type; + int func_index; + u64 addr; + int ret; + + if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) { + dev_err(dev, "%s: maximum number of functions exceeded\n", __func__); + return -EINVAL; + } + + /* + * The number of functions cannot exceed 8, we could use + * acpi_get_local_address() but the value is stored as u64 so + * we might as well avoid casts and intermediate levels + */ + ret = acpi_get_local_u64_address(adev->handle, &addr); + if (ret < 0) + return ret; + + if (!addr) { + dev_err(dev, "%s: no addr\n", __func__); + return -ENODEV; + } + + /* + * Extracting the topology type for an SDCA function is a + * convoluted process. + * The Function type is only visible as a result of a read + * from a control. In theory this would mean reading from the hardware, + * but the SDCA/DisCo specs defined the notion of "DC value" - a constant + * represented with a DSD subproperty. + * Drivers have to query the properties for the control + * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05) + */ + control5 = fwnode_get_named_child_node(function_node, + "mipi-sdca-control-0x5-subproperties"); + if (!control5) + return -ENODEV; + + ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value", + &function_type); + + fwnode_handle_put(control5); + + if (ret < 0) { + dev_err(dev, "%s: the function type can only be determined from ACPI information\n", + __func__); + return ret; + } + + ret = patch_sdca_function_type(dev, sdca_data->interface_revision, + &function_type, &function_name); + if (ret < 0) + return ret; + + /* store results */ + func_index = sdca_data->num_functions; + sdca_data->sdca_func[func_index].adr = addr; + sdca_data->sdca_func[func_index].type = function_type; + sdca_data->sdca_func[func_index].name = function_name; + sdca_data->num_functions++; + + return 0; +} + +void sdca_lookup_functions(struct sdw_slave *slave) +{ + struct device *dev = &slave->dev; + struct acpi_device *adev = to_acpi_device_node(dev->fwnode); + + if (!adev) { + dev_info(dev, "No matching ACPI device found, ignoring peripheral\n"); + return; + } + acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data); +} +EXPORT_SYMBOL_NS(sdca_lookup_functions, SND_SOC_SDCA); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SDCA library"); diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile index 28229ed96ffb..daf019113553 100644 --- a/sound/soc/sdw_utils/Makefile +++ b/sound/soc/sdw_utils/Makefile @@ -1,9 +1,8 @@ # 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_rt_amp.o soc_sdw_rt_mf_sdca.o \ soc_sdw_bridge_cs35l56.o \ soc_sdw_cs42l42.o soc_sdw_cs42l43.o \ soc_sdw_cs_amp.o \ diff --git a/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c deleted file mode 100644 index 5127210b9a03..000000000000 --- a/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -/* - * soc_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/soc_sdw_utils.h> - -/* - * dapm routes for rt712 spk will be registered dynamically according - * to the number of rt712 spk used. The first two entries will be registered - * for one codec case, and the last two entries are also registered - * if two rt712s are used. - */ -static const struct snd_soc_dapm_route rt712_spk_map[] = { - { "Speaker", NULL, "rt712 SPOL" }, - { "Speaker", NULL, "rt712 SPOR" }, -}; - -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; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt712", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt712_spk_map, ARRAY_SIZE(rt712_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add SPK map: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS(asoc_sdw_rt712_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c deleted file mode 100644 index 6a402172289f..000000000000 --- a/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -/* - * soc_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/soc_sdw_utils.h> - -static const struct snd_soc_dapm_route rt722_spk_map[] = { - { "Speaker", NULL, "rt722 SPK" }, -}; - -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; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt722", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt722_spk_map, ARRAY_SIZE(rt722_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add rt722 spk map: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS(asoc_sdw_rt722_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c new file mode 100644 index 000000000000..81e43319876e --- /dev/null +++ b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2024 Intel Corporation. + +/* + * soc_sdw_rt_mf_sdca + * - Helpers to handle RT Multifunction Codec from generic machine driver + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <sound/control.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <sound/soc-dapm.h> +#include <sound/soc_sdw_utils.h> + +#define CODEC_NAME_SIZE 6 + +/* dapm routes for RT-SPK will be registered dynamically */ +static const struct snd_soc_dapm_route rt712_spk_map[] = { + { "Speaker", NULL, "rt712 SPOL" }, + { "Speaker", NULL, "rt712 SPOR" }, +}; + +static const struct snd_soc_dapm_route rt721_spk_map[] = { + { "Speaker", NULL, "rt721 SPK" }, +}; + +static const struct snd_soc_dapm_route rt722_spk_map[] = { + { "Speaker", NULL, "rt722 SPK" }, +}; + +/* Structure to map codec names to respective route arrays and sizes */ +struct codec_route_map { + const char *codec_name; + const struct snd_soc_dapm_route *route_map; + size_t route_size; +}; + +/* Codec route maps array */ +static const struct codec_route_map codec_routes[] = { + { "rt712", rt712_spk_map, ARRAY_SIZE(rt712_spk_map) }, + { "rt721", rt721_spk_map, ARRAY_SIZE(rt721_spk_map) }, + { "rt722", rt722_spk_map, ARRAY_SIZE(rt722_spk_map) }, +}; + +static const struct codec_route_map *get_codec_route_map(const char *codec_name) +{ + for (size_t i = 0; i < ARRAY_SIZE(codec_routes); i++) { + if (strcmp(codec_routes[i].codec_name, codec_name) == 0) + return &codec_routes[i]; + } + return NULL; +} + +int asoc_sdw_rt_mf_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct snd_soc_card *card = rtd->card; + char codec_name[CODEC_NAME_SIZE]; + int ret; + + /* acquire codec name */ + snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai->name); + + /* acquire corresponding route map and size */ + const struct codec_route_map *route_map = get_codec_route_map(codec_name); + + if (!route_map) { + dev_err(rtd->dev, "failed to get codec name and route map\n"); + return -EINVAL; + } + + /* Update card components */ + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:%s", + card->components, codec_name); + if (!card->components) + return -ENOMEM; + + /* Add routes */ + ret = snd_soc_dapm_add_routes(&card->dapm, route_map->route_map, route_map->route_size); + if (ret) + dev_err(rtd->dev, "failed to add rt sdca spk map: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_rt_mf_sdca_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c index 3e6211dc1599..af43efbb8f79 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c @@ -60,6 +60,11 @@ static const struct snd_soc_dapm_route rt713_sdca_map[] = { { "rt713 MIC2", NULL, "Headset Mic" }, }; +static const struct snd_soc_dapm_route rt721_sdca_map[] = { + { "Headphone", NULL, "rt721 HP" }, + { "rt721 MIC2", NULL, "Headset Mic" }, +}; + static const struct snd_soc_dapm_route rt722_sdca_map[] = { { "Headphone", NULL, "rt722 HP" }, { "rt722 MIC2", NULL, "Headset Mic" }, @@ -121,6 +126,9 @@ int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s } else if (strstr(component->name_prefix, "rt713")) { ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map, ARRAY_SIZE(rt713_sdca_map)); + } else if (strstr(component->name_prefix, "rt721")) { + ret = snd_soc_dapm_add_routes(&card->dapm, rt721_sdca_map, + ARRAY_SIZE(rt721_sdca_map)); } else if (strstr(component->name_prefix, "rt722")) { ret = snd_soc_dapm_add_routes(&card->dapm, rt722_sdca_map, ARRAY_SIZE(rt722_sdca_map)); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index a6070f822eb9..19bd02e2cd6d 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -138,14 +138,21 @@ struct asoc_sdw_codec_info codec_info_list[] = { .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, + .rtd_init = asoc_sdw_rt_mf_sdca_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 = "rt712-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 = 2, + .dai_num = 3, }, { .part_id = 0x1712, @@ -178,8 +185,15 @@ struct asoc_sdw_codec_info codec_info_list[] = { .widgets = generic_jack_widgets, .num_widgets = ARRAY_SIZE(generic_jack_widgets), }, + { + .direction = {false, true}, + .dai_name = "rt712-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 = 1, + .dai_num = 2, }, { .part_id = 0x1713, @@ -334,6 +348,47 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dai_num = 1, }, { + .part_id = 0x721, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt721-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 = "rt721-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + /* No feedback capability is provided by rt721-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_rt_mf_sdca_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 = "rt721-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 = 0x722, .version_id = 3, .dais = { @@ -358,11 +413,13 @@ struct asoc_sdw_codec_info codec_info_list[] = { .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, + .rtd_init = asoc_sdw_rt_mf_sdca_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, + .quirk_exclude = true, }, { .direction = {false, true}, @@ -487,6 +544,8 @@ struct asoc_sdw_codec_info codec_info_list[] = { .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, .widgets = generic_dmic_widgets, .num_widgets = ARRAY_SIZE(generic_dmic_widgets), + .quirk = SOC_SDW_CODEC_MIC, + .quirk_exclude = true, }, { .direction = {false, true}, @@ -956,15 +1015,17 @@ void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_lin 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), + int codecs_num, int no_pcm, + 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->stream_name = name; dai_links->platforms = platform_component; dai_links->num_platforms = num_platforms; - dai_links->no_pcm = 1; + dai_links->no_pcm = no_pcm; dai_links->cpus = cpus; dai_links->num_cpus = cpus_num; dai_links->codecs = codecs; @@ -980,7 +1041,7 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d 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, + const char *codec_dai_name, int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops) { @@ -999,7 +1060,7 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d 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); + &dlc[2], 1, no_pcm, init, ops); return 0; } @@ -1112,7 +1173,8 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, 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)) + if (dai_info->quirk && + !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) continue; dev_dbg(dev, diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 6d693b2ad5a3..270f9777942f 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -131,8 +131,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); /* Check if all Slaves defined on the link can be found */ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, const struct snd_soc_acpi_link_adr *link, - struct sdw_extended_slave_id *ids, - int num_slaves) + struct sdw_peripherals *peripherals) { unsigned int part_id, link_id, unique_id, mfg_id, version; int i, j, k; @@ -146,22 +145,25 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, link_id = SDW_DISCO_LINK_ID(adr); version = SDW_VERSION(adr); - for (j = 0; j < num_slaves; j++) { + for (j = 0; j < peripherals->num_peripherals; j++) { + struct sdw_slave *peripheral = peripherals->array[j]; + /* find out how many identical parts were reported on that link */ - if (ids[j].link_id == link_id && - ids[j].id.part_id == part_id && - ids[j].id.mfg_id == mfg_id && - ids[j].id.sdw_version == version) + if (peripheral->bus->link_id == link_id && + peripheral->id.part_id == part_id && + peripheral->id.mfg_id == mfg_id && + peripheral->id.sdw_version == version) reported_part_count++; } - for (j = 0; j < num_slaves; j++) { + for (j = 0; j < peripherals->num_peripherals; j++) { + struct sdw_slave *peripheral = peripherals->array[j]; int expected_part_count = 0; - if (ids[j].link_id != link_id || - ids[j].id.part_id != part_id || - ids[j].id.mfg_id != mfg_id || - ids[j].id.sdw_version != version) + if (peripheral->bus->link_id != link_id || + peripheral->id.part_id != part_id || + peripheral->id.mfg_id != mfg_id || + peripheral->id.sdw_version != version) continue; /* find out how many identical parts are expected */ @@ -180,7 +182,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, */ unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || - ids[j].id.unique_id == unique_id) { + peripheral->id.unique_id == unique_id) { dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); break; } @@ -189,7 +191,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, part_id, reported_part_count, expected_part_count, link_id); } } - if (j == num_slaves) { + if (j == peripherals->num_peripherals) { dev_dbg(dev, "Slave part_id %#x not found\n", part_id); return false; } diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b3d7bb91e294..b67ef78f405c 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -58,7 +58,7 @@ static inline int soc_component_field_shift(struct snd_soc_component *component, * In such case, we can update these macros. */ #define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream) -#define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL) +#define soc_component_mark_pop(component, tgt) ((component)->mark_##tgt = NULL) #define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream) void snd_soc_component_set_aux(struct snd_soc_component *component, @@ -339,7 +339,7 @@ void snd_soc_component_module_put(struct snd_soc_component *component, module_put(component->dev->driver->owner); /* remove the mark from module */ - soc_component_mark_pop(component, mark, module); + soc_component_mark_pop(component, module); } int snd_soc_component_open(struct snd_soc_component *component, @@ -370,7 +370,7 @@ int snd_soc_component_close(struct snd_soc_component *component, ret = component->driver->close(component, substream); /* remove marked substream */ - soc_component_mark_pop(component, substream, open); + soc_component_mark_pop(component, open); return soc_component_ret(component, ret); } @@ -515,7 +515,7 @@ void snd_soc_component_compr_free(struct snd_soc_component *component, component->driver->compress_ops->free(component, cstream); /* remove marked substream */ - soc_component_mark_pop(component, cstream, compr_open); + soc_component_mark_pop(component, compr_open); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); @@ -1210,7 +1210,7 @@ void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, } /* remove marked substream */ - soc_component_mark_pop(component, substream, hw_params); + soc_component_mark_pop(component, hw_params); } } @@ -1254,7 +1254,7 @@ int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, r = soc_component_trigger(component, substream, cmd); if (r < 0) ret = r; /* use last ret */ - soc_component_mark_pop(component, substream, trigger); + soc_component_mark_pop(component, trigger); } } @@ -1294,7 +1294,7 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, pm_runtime_put_autosuspend(component->dev); /* remove marked stream */ - soc_component_mark_pop(component, stream, pm); + soc_component_mark_pop(component, pm); } } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index e692aa3b8b22..563dc0767c17 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) snd_soc_dai_digital_mute(codec_dai, 1, stream); if (!snd_soc_dai_active(cpu_dai)) - cpu_dai->rate = 0; + cpu_dai->symmetric_rate = 0; if (!snd_soc_dai_active(codec_dai)) - codec_dai->rate = 0; + codec_dai->symmetric_rate = 0; snd_soc_link_compr_shutdown(cstream, rollback); @@ -537,11 +537,10 @@ static struct snd_compr_ops soc_compr_dyn_ops = { * snd_soc_new_compress - create a new compress. * * @rtd: The runtime for which we will create compress - * @num: the device index number (zero based - shared with normal PCMs) * * Return: 0 for success, else error. */ -int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) +int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component; struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); @@ -606,12 +605,19 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) return -ENOMEM; if (rtd->dai_link->dynamic) { + int playback = 1; + int capture = 1; + + if (rtd->dai_link->capture_only) + playback = 0; + if (rtd->dai_link->playback_only) + capture = 0; + snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, - rtd->dai_link->dpcm_playback, - rtd->dai_link->dpcm_capture, &be_pcm); + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, + playback, capture, &be_pcm); if (ret < 0) { dev_err(rtd->card->dev, "Compress ASoC: can't create compressed for %s: %d\n", @@ -624,14 +630,14 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = be_pcm; rtd->fe_compr = 1; - if (rtd->dai_link->dpcm_playback) + if (playback) be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; - if (rtd->dai_link->dpcm_capture) + if (capture) be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); } else { snprintf(new_name, sizeof(new_name), "%s %s-%d", - rtd->dai_link->stream_name, codec_dai->name, num); + rtd->dai_link->stream_name, codec_dai->name, rtd->id); memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); } @@ -645,7 +651,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) break; } - ret = snd_compress_new(rtd->card->snd_card, num, direction, + ret = snd_compress_new(rtd->card->snd_card, rtd->id, direction, new_name, compr); if (ret < 0) { component = snd_soc_rtd_to_codec(rtd, 0)->component; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 20248a29d167..a1dace4bb616 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -558,7 +558,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( */ rtd->card = card; rtd->dai_link = dai_link; - rtd->num = card->num_rtd++; + rtd->id = card->num_rtd++; rtd->pmdown_time = pmdown_time; /* default power off timeout */ /* see for_each_card_rtds */ @@ -1166,7 +1166,7 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codec, *platform, *cpu; struct snd_soc_component *component; - int i, ret; + int i, id, ret; lockdep_assert_held(&client_mutex); @@ -1225,6 +1225,28 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, } } + /* + * Most drivers will register their PCMs using DAI link ordering but + * topology based drivers can use the DAI link id field to set PCM + * device number and then use rtd + a base offset of the BEs. + * + * FIXME + * + * This should be implemented by using "dai_link" feature instead of + * "component" feature. + */ + id = rtd->id; + for_each_rtd_components(rtd, i, component) { + if (!component->driver->use_dai_pcm_id) + continue; + + if (rtd->dai_link->no_pcm) + id += component->driver->be_pcm_base; + else + id = rtd->dai_link->id; + } + rtd->id = id; + return 0; _err_defer: @@ -1457,8 +1479,7 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct snd_soc_component *component; - int ret, num, i; + int ret; /* do machine specific initialization */ ret = snd_soc_link_init(rtd); @@ -1473,30 +1494,13 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, /* add DPCM sysfs entries */ soc_dpcm_debugfs_add(rtd); - num = rtd->num; - - /* - * most drivers will register their PCMs using DAI link ordering but - * topology based drivers can use the DAI link id field to set PCM - * device number and then use rtd + a base offset of the BEs. - */ - for_each_rtd_components(rtd, i, component) { - if (!component->driver->use_dai_pcm_id) - continue; - - if (rtd->dai_link->no_pcm) - num += component->driver->be_pcm_base; - else - num = rtd->dai_link->id; - } - /* create compress_device if possible */ - ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); + ret = snd_soc_dai_compress_new(cpu_dai, rtd); if (ret != -ENOTSUPP) goto err; /* create the pcm */ - ret = soc_new_pcm(rtd, num); + ret = soc_new_pcm(rtd); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); @@ -1999,25 +2003,7 @@ match: dai_link->platforms->name = component->name; /* convert non BE into BE */ - if (!dai_link->no_pcm) { - dai_link->no_pcm = 1; - - if (dai_link->dpcm_playback) - dev_warn(card->dev, - "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_playback=1\n", - dai_link->name); - if (dai_link->dpcm_capture) - dev_warn(card->dev, - "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_capture=1\n", - dai_link->name); - - /* convert normal link into DPCM one */ - if (!(dai_link->dpcm_playback || - dai_link->dpcm_capture)) { - dai_link->dpcm_playback = !dai_link->capture_only; - dai_link->dpcm_capture = !dai_link->playback_only; - } - } + dai_link->no_pcm = 1; /* * override any BE fixups diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 4e08892d24c6..34ba1a93a4c9 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -37,7 +37,7 @@ static inline int _soc_dai_ret(const struct snd_soc_dai *dai, * In such case, we can update these macros. */ #define soc_dai_mark_push(dai, substream, tgt) ((dai)->mark_##tgt = substream) -#define soc_dai_mark_pop(dai, substream, tgt) ((dai)->mark_##tgt = NULL) +#define soc_dai_mark_pop(dai, tgt) ((dai)->mark_##tgt = NULL) #define soc_dai_mark_match(dai, substream, tgt) ((dai)->mark_##tgt == substream) /** @@ -416,7 +416,7 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, dai->driver->ops->hw_free(substream, dai); /* remove marked substream */ - soc_dai_mark_pop(dai, substream, hw_params); + soc_dai_mark_pop(dai, hw_params); } int snd_soc_dai_startup(struct snd_soc_dai *dai, @@ -453,16 +453,16 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, dai->driver->ops->shutdown(substream, dai); /* remove marked substream */ - soc_dai_mark_pop(dai, substream, startup); + soc_dai_mark_pop(dai, startup); } int snd_soc_dai_compress_new(struct snd_soc_dai *dai, - struct snd_soc_pcm_runtime *rtd, int num) + struct snd_soc_pcm_runtime *rtd) { int ret = -ENOTSUPP; if (dai->driver->ops && dai->driver->ops->compress_new) - ret = dai->driver->ops->compress_new(rtd, num); + ret = dai->driver->ops->compress_new(rtd); return soc_dai_ret(dai, ret); } @@ -640,7 +640,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, r = soc_dai_trigger(dai, substream, cmd); if (r < 0) ret = r; /* use last ret */ - soc_dai_mark_pop(dai, substream, trigger); + soc_dai_mark_pop(dai, trigger); } } @@ -704,7 +704,7 @@ void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai, dai->driver->cops->shutdown(cstream, dai); /* remove marked cstream */ - soc_dai_mark_pop(dai, cstream, compr_startup); + soc_dai_mark_pop(dai, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 4534a1c03e8e..c6364caabc0e 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -9,43 +9,6 @@ #include <sound/soc.h> #include <sound/dmaengine_pcm.h> -static void devm_dai_release(struct device *dev, void *res) -{ - snd_soc_unregister_dai(*(struct snd_soc_dai **)res); -} - -/** - * devm_snd_soc_register_dai - resource-managed dai registration - * @dev: Device used to manage component - * @component: The component the DAIs are registered for - * @dai_drv: DAI driver to use for the DAI - * @legacy_dai_naming: if %true, use legacy single-name format; - * if %false, use multiple-name format; - */ -struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev, - struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) -{ - struct snd_soc_dai **ptr; - struct snd_soc_dai *dai; - - ptr = devres_alloc(devm_dai_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - dai = snd_soc_register_dai(component, dai_drv, legacy_dai_naming); - if (dai) { - *ptr = dai; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return dai; -} -EXPORT_SYMBOL_GPL(devm_snd_soc_register_dai); - static void devm_component_release(struct device *dev, void *res) { const struct snd_soc_component_driver **cmpnt_drv = res; diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index fee4022708bc..7f1f1bc717e2 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -35,7 +35,7 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, * In such case, we can update these macros. */ #define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream) -#define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL) +#define soc_link_mark_pop(rtd, tgt) ((rtd)->mark_##tgt = NULL) #define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream) int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd) @@ -94,7 +94,7 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream, rtd->dai_link->ops->shutdown(substream); /* remove marked substream */ - soc_link_mark_pop(rtd, substream, startup); + soc_link_mark_pop(rtd, startup); } int snd_soc_link_prepare(struct snd_pcm_substream *substream) @@ -138,7 +138,7 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) rtd->dai_link->ops->hw_free(substream); /* remove marked substream */ - soc_link_mark_pop(rtd, substream, hw_params); + soc_link_mark_pop(rtd, hw_params); } static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) @@ -175,7 +175,7 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, break; ret = soc_link_trigger(substream, cmd); - soc_link_mark_pop(rtd, substream, startup); + soc_link_mark_pop(rtd, startup); } return ret; @@ -209,7 +209,7 @@ void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, rtd->dai_link->compr_ops->shutdown) rtd->dai_link->compr_ops->shutdown(cstream); - soc_link_mark_pop(rtd, cstream, compr_startup); + soc_link_mark_pop(rtd, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7a59121fc323..1150455619aa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -416,22 +416,6 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) return true; } -/** - * snd_soc_set_runtime_hwparams - set the runtime hardware parameters - * @substream: the pcm substream - * @hw: the hardware parameters - * - * Sets the substream runtime hardware parameters. - */ -int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, - const struct snd_pcm_hardware *hw) -{ - substream->runtime->hw = *hw; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); - /* DPCM stream event, send event to FE and all active BEs. */ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) @@ -463,13 +447,13 @@ static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) { if (params) { - dai->rate = params_rate(params); - dai->channels = params_channels(params); - dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + dai->symmetric_rate = params_rate(params); + dai->symmetric_channels = params_channels(params); + dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params)); } else { - dai->rate = 0; - dai->channels = 0; - dai->sample_bits = 0; + dai->symmetric_rate = 0; + dai->symmetric_channels = 0; + dai->symmetric_sample_bits = 0; } } @@ -483,14 +467,14 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, return 0; #define __soc_pcm_apply_symmetry(name, NAME) \ - if (soc_dai->name && (soc_dai->driver->symmetric_##name || \ - rtd->dai_link->symmetric_##name)) { \ + if (soc_dai->symmetric_##name && \ + (soc_dai->driver->symmetric_##name || rtd->dai_link->symmetric_##name)) { \ dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\ - #name, soc_dai->name); \ + #name, soc_dai->symmetric_##name); \ \ ret = snd_pcm_hw_constraint_single(substream->runtime, \ SNDRV_PCM_HW_PARAM_##NAME,\ - soc_dai->name); \ + soc_dai->symmetric_##name); \ if (ret < 0) { \ dev_err(soc_dai->dev, \ "ASoC: Unable to apply %s constraint: %d\n",\ @@ -526,9 +510,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ if (!snd_soc_dai_is_dummy(cpu_dai) && \ - cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ + cpu_dai->symmetric_##xxx && \ + cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \ dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ - #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ + #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ + d.name, d.symmetric_##xxx); \ return -EINVAL; \ } @@ -799,8 +785,7 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, /* Make sure DAI parameters cleared if the DAI becomes inactive */ for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_active(dai) == 0 && - (dai->rate || dai->channels || dai->sample_bits)) + if (snd_soc_dai_active(dai) == 0) soc_pcm_set_dai_params(dai, NULL); } } @@ -2838,7 +2823,11 @@ 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 *codec_dai; struct snd_soc_dai_link_ch_map *ch_maps; + struct snd_soc_dai *dummy_dai = snd_soc_find_dai(&snd_soc_dummy_dlc); + int cpu_capture; + int cpu_playback; int has_playback = 0; int has_capture = 0; int i; @@ -2848,73 +2837,38 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, return -EINVAL; } - if (dai_link->dynamic || dai_link->no_pcm) { - - for_each_rtd_ch_maps(rtd, i, ch_maps) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + /* Adapt stream for codec2codec links */ + cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); + cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - 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; - } + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); /* - * REMOVE ME + * FIXME + * + * DPCM Codec has been no checked before. + * It should be checked, but it breaks compatibility. * - * dpcm_xxx flag will be removed soon, Indicates warning if dpcm_xxx flag was used - * as availability limitation + * For example there is a case that CPU have loopback capabilities which is used + * for tests on boards where the Codec has no capture capabilities. In this case, + * Codec capture validation check will be fail, but system should allow capture + * capabilities. We have no solution for it today. */ - 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 (!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 *codec_dai; + if (dai_link->dynamic || dai_link->no_pcm) + codec_dai = dummy_dai; - /* Adapt stream for codec2codec links */ - int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); - int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - - /* - * see - * soc.h :: [dai_link->ch_maps Image sample] - */ - for_each_rtd_ch_maps(rtd, i, ch_maps) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); - codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); - - if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && - snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) - has_playback = 1; - if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && - snd_soc_dai_stream_valid(cpu_dai, cpu_capture)) - has_capture = 1; - } + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) + has_playback = 1; + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, cpu_capture)) + has_capture = 1; } if (dai_link->playback_only) @@ -2938,7 +2892,7 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, static int soc_create_pcm(struct snd_pcm **pcm, struct snd_soc_pcm_runtime *rtd, - int playback, int capture, int num) + int playback, int capture) { char new_name[64]; int ret; @@ -2948,13 +2902,13 @@ static int soc_create_pcm(struct snd_pcm **pcm, snprintf(new_name, sizeof(new_name), "codec2codec(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } else if (rtd->dai_link->no_pcm) { snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } else { if (rtd->dai_link->dynamic) @@ -2963,9 +2917,9 @@ static int soc_create_pcm(struct snd_pcm **pcm, else snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, - soc_codec_dai_name(rtd), num); + soc_codec_dai_name(rtd), rtd->id); - ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, + ret = snd_pcm_new(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } if (ret < 0) { @@ -2973,13 +2927,13 @@ static int soc_create_pcm(struct snd_pcm **pcm, new_name, rtd->dai_link->name, ret); return ret; } - dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n", rtd->id, new_name); return 0; } /* create a new pcm */ -int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) +int soc_new_pcm(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component; struct snd_pcm *pcm; @@ -2990,7 +2944,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ret < 0) return ret; - ret = soc_create_pcm(&pcm, rtd, playback, capture, num); + ret = soc_create_pcm(&pcm, rtd, playback, capture); if (ret < 0) return ret; diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c index a2b08568f4e8..c8f2ec29e970 100644 --- a/sound/soc/soc-topology-test.c +++ b/sound/soc/soc-topology-test.c @@ -88,8 +88,6 @@ static struct snd_soc_dai_link kunit_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(dummy, dummy, platform), }, }; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 97517423d1f0..43003d2d3666 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1544,8 +1544,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, /* enable DPCM */ link->dynamic = 1; link->ignore_pmdown_time = 1; - link->dpcm_playback = le32_to_cpu(pcm->playback); - link->dpcm_capture = le32_to_cpu(pcm->capture); + link->playback_only = le32_to_cpu(pcm->playback) && !le32_to_cpu(pcm->capture); + link->capture_only = !le32_to_cpu(pcm->playback) && le32_to_cpu(pcm->capture); if (pcm->flag_mask) set_link_flags(link, le32_to_cpu(pcm->flag_mask), diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 303823dc45d7..aa93e77ac937 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -103,8 +103,8 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER, .buffer_bytes_max = 128*1024, - .period_bytes_min = PAGE_SIZE, - .period_bytes_max = PAGE_SIZE*2, + .period_bytes_min = 4096, + .period_bytes_max = 4096*2, .periods_min = 2, .periods_max = 128, }; diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index dbcaac84cb73..fc792956bb97 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -145,8 +145,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * link = mach->links; for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, - acp_data->sdw->ids, - acp_data->sdw->num_slaves)) + acp_data->sdw->peripherals)) break; } if (i == acp_data->info.count || !link->num_adr) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 83fe0401baf8..24e779e8d650 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -19,11 +19,47 @@ #define CREATE_TRACE_POINTS #include <trace/events/sof.h> +/* Module parameters for firmware, topology and IPC type override */ +static char *override_fw_path; +module_param_named(fw_path, override_fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *override_fw_filename; +module_param_named(fw_filename, override_fw_filename, charp, 0444); +MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware."); + +static char *override_lib_path; +module_param_named(lib_path, override_lib_path, charp, 0444); +MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries."); + +static char *override_tplg_path; +module_param_named(tplg_path, override_tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + +static char *override_tplg_filename; +module_param_named(tplg_filename, override_tplg_filename, charp, 0444); +MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology."); + +static int override_ipc_type = -1; +module_param_named(ipc_type, override_ipc_type, int, 0444); +MODULE_PARM_DESC(ipc_type, "Force SOF IPC type. 0 - IPC3, 1 - IPC4"); + /* see SOF_DBG_ flags */ static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +static unsigned int sof_ipc_timeout_ms; +static unsigned int sof_boot_timeout_ms; +module_param_named(ipc_timeout, sof_ipc_timeout_ms, uint, 0444); +MODULE_PARM_DESC(ipc_timeout, + "Set the IPC timeout value in ms (0 to use the platform default)"); +module_param_named(boot_timeout, sof_boot_timeout_ms, uint, 0444); +MODULE_PARM_DESC(boot_timeout, + "Set the DSP boot timeout value in ms (0 to use the platform default)"); +#endif + /* SOF defaults if not provided by the platform in ms */ #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 @@ -570,6 +606,23 @@ static void sof_probe_work(struct work_struct *work) } } +static void +sof_apply_profile_override(struct sof_loadable_file_profile *path_override) +{ + if (override_ipc_type >= 0 && override_ipc_type < SOF_IPC_TYPE_COUNT) + path_override->ipc_type = override_ipc_type; + if (override_fw_path) + path_override->fw_path = override_fw_path; + if (override_fw_filename) + path_override->fw_name = override_fw_filename; + if (override_lib_path) + path_override->fw_lib_path = override_lib_path; + if (override_tplg_path) + path_override->tplg_path = override_tplg_path; + if (override_tplg_filename) + path_override->tplg_name = override_tplg_filename; +} + int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) { struct snd_sof_dev *sdev; @@ -601,6 +654,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } } + sof_apply_profile_override(&plat_data->ipc_file_profile_base); + /* Initialize sof_ops based on the initial selected IPC version */ ret = sof_init_sof_ops(sdev); if (ret) @@ -632,6 +687,15 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) else sdev->boot_timeout = plat_data->desc->boot_timeout; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) + /* Override the timeout values with module parameter, if set */ + if (sof_ipc_timeout_ms) + sdev->ipc_timeout = sof_ipc_timeout_ms; + + if (sof_boot_timeout_ms) + sdev->boot_timeout = sof_boot_timeout_ms; +#endif + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); /* diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ac505c7ad342..ee274d445515 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -646,6 +646,10 @@ static int hda_dai_suspend(struct hdac_bus *bus) sdai = swidget->private; ops = sdai->platform_private; + if (rtd->dpcm[hext_stream->link_substream->stream].state != + SND_SOC_DPCM_STATE_PAUSED) + continue; + /* for consistency with TRIGGER_SUSPEND */ if (ops->post_trigger) { ret = ops->post_trigger(sdev, cpu_dai, diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4c88522d4048..6028a80418bb 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -858,7 +858,6 @@ skip_dsp: static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { - const struct sof_intel_dsp_desc *chip; int ret; /* display codec must be powered before link reset */ @@ -891,10 +890,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) hda_dsp_ctrl_ppcap_int_enable(sdev, true); } - chip = get_chip_info(sdev->pdata); - if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) - hda_sdw_int_enable(sdev, true); - cleanup: /* display codec can powered off after controller init */ hda_codec_i915_display_power(sdev, false); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 9d8ebb7c6a10..76a03b6b2728 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -26,6 +26,11 @@ #include "../sof-priv.h" #include "hda.h" +static bool persistent_cl_buffer = true; +module_param(persistent_cl_buffer, bool, 0444); +MODULE_PARM_DESC(persistent_cl_buffer, "Persistent Code Loader DMA buffer " + "(default = Y, use N to force buffer re-allocation)"); + static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -43,9 +48,10 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev) } } -struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab, - int direction, bool is_iccmax) +struct hdac_ext_stream* +hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size, + struct snd_dma_buffer *dmab, bool persistent_buffer, int direction, + bool is_iccmax) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct hdac_ext_stream *hext_stream; @@ -61,11 +67,19 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, hstream = &hext_stream->hstream; hstream->substream = NULL; - /* allocate DMA buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); - if (ret < 0) { - dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret); - goto out_put; + /* + * Allocate DMA buffer if it is temporary or if the buffer is intended + * to be persistent but not yet allocated. + * We cannot rely solely on !dmab->area as caller might use a struct on + * stack (when it is temporary) without clearing it to 0. + */ + if (!persistent_buffer || !dmab->area) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); + if (ret < 0) { + dev_err(sdev->dev, "%s: memory alloc failed: %d\n", + __func__, ret); + goto out_put; + } } hstream->period_bytes = 0;/* initialize period_bytes */ @@ -91,6 +105,10 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, out_free: snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; out_put: hda_dsp_stream_put(sdev, direction, hstream->stream_tag); return ERR_PTR(ret); @@ -255,7 +273,7 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - struct hdac_ext_stream *hext_stream) + bool persistent_buffer, struct hdac_ext_stream *hext_stream) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct hdac_stream *hstream = &hext_stream->hstream; @@ -279,10 +297,14 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); - snd_dma_free_pages(dmab); - dmab->area = NULL; - hstream->bufsize = 0; - hstream->format_val = 0; + + if (!persistent_buffer) { + snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; + } return ret; } @@ -340,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_ext_stream *iccmax_stream; - struct snd_dma_buffer dmab_bdl; int ret, ret1; u8 original_gb; @@ -354,7 +376,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) * the data, so use a buffer of PAGE_SIZE for receiving. */ iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE, - &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE, true); + &hda->iccmax_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_CAPTURE, true); if (IS_ERR(iccmax_stream)) { dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); return PTR_ERR(iccmax_stream); @@ -366,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) * Perform iccmax stream cleanup. This should be done even if firmware loading fails. * If the cleanup also fails, we return the initial error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab_bdl, iccmax_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab, + persistent_cl_buffer, iccmax_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); @@ -408,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) const struct sof_intel_dsp_desc *chip_info; struct hdac_ext_stream *hext_stream; struct firmware stripped_firmware; - struct snd_dma_buffer dmab; int ret, ret1, i; if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) { @@ -432,23 +455,31 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) return -EINVAL; } - stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset; - stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset; - /* init for booting wait */ init_waitqueue_head(&sdev->boot_wait); /* prepare DMA for code loader stream */ + stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset; hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, - &dmab, SNDRV_PCM_STREAM_PLAYBACK, false); + &hda->cl_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_PLAYBACK, false); if (IS_ERR(hext_stream)) { dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); return PTR_ERR(hext_stream); } - memcpy(dmab.area, stripped_firmware.data, - stripped_firmware.size); + /* + * Copy the payload to the DMA buffer if it is temporary or if the + * buffer is persistent but it does not have the basefw payload either + * because this is the first boot and the buffer needs to be initialized, + * or a library got loaded and it replaced the basefw. + */ + if (!persistent_cl_buffer || !hda->cl_dmab_contains_basefw) { + stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset; + memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size); + hda->cl_dmab_contains_basefw = true; + } /* try ROM init a few times before giving up */ for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { @@ -514,7 +545,8 @@ cleanup: * This should be done even if firmware loading fails. * If the cleanup also fails, we return the initial error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, + persistent_cl_buffer, hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); @@ -545,7 +577,6 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream; struct firmware stripped_firmware; struct sof_ipc4_msg msg = {}; - struct snd_dma_buffer dmab; int ret, ret1; /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */ @@ -556,16 +587,28 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset; stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset; + /* + * force re-allocation of the cl_dmab if the preserved DMA buffer is + * smaller than what is needed for the library + */ + if (persistent_cl_buffer && stripped_firmware.size > hda->cl_dmab.bytes) { + snd_dma_free_pages(&hda->cl_dmab); + hda->cl_dmab.area = NULL; + hda->cl_dmab.bytes = 0; + } + /* prepare DMA for code loader stream */ hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, - &dmab, SNDRV_PCM_STREAM_PLAYBACK, false); + &hda->cl_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_PLAYBACK, false); if (IS_ERR(hext_stream)) { dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__); return PTR_ERR(hext_stream); } - memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size); + memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size); + hda->cl_dmab_contains_basefw = false; /* * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE @@ -628,7 +671,8 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, cleanup: /* clean up even in case of error and return the first error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer, + hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 9a3559c78b62..46f89d6d06f8 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -481,6 +481,24 @@ int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid) } EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, SND_SOC_SOF_HDA_MLINK); +void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable) +{ + struct hdac_ext2_link *h2link; + struct hdac_ext_link *hlink; + + h2link = find_ext2_link(bus, alt, elid); + if (!h2link) + return; + + if (!h2link->intc) + return; + + hlink = &h2link->hext_link; + + hdaml_link_enable_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL, enable); +} +EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt_unlocked, SND_SOC_SOF_HDA_MLINK); + void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable) { struct hdac_ext2_link *h2link; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3ac63ce67ab1..519bafd3b947 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -119,13 +119,39 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, int remain, ioc; period_bytes = hstream->period_bytes; - dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); - if (!period_bytes) + dev_dbg(sdev->dev, "period_bytes: %#x, bufsize: %#x\n", period_bytes, + hstream->bufsize); + + if (!period_bytes) { + unsigned int chunk_size; + + chunk_size = snd_sgbuf_get_chunk_size(dmab, 0, hstream->bufsize); + period_bytes = hstream->bufsize; + /* + * HDA spec demands that the LVI value must be at least one + * before the DMA operation can begin. This means that there + * must be at least two BDLE present for the transfer. + * + * If the buffer is not a single continuous area then the + * hda_setup_bdle() will create multiple BDLEs for each segment. + * If the memory is a single continuous area, force it to be + * split into two 'periods', otherwise the transfer will be + * split to multiple BDLE for each chunk in hda_setup_bdle() + * + * Note: period_bytes == 0 can only happen for firmware or + * library loading. The data size is 4K aligned, which ensures + * that the second chunk's start address will be 128-byte + * aligned. + */ + if (chunk_size == hstream->bufsize) + period_bytes /= 2; + } + periods = hstream->bufsize / period_bytes; - dev_dbg(sdev->dev, "periods:%d\n", periods); + dev_dbg(sdev->dev, "periods: %d\n", periods); remain = hstream->bufsize % period_bytes; if (remain) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 70fc08c8fc99..01b135068b1f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -866,8 +866,6 @@ skip_dsp_setup: dev_err(sdev->dev, "could not startup SoundWire links\n"); goto disable_pp_cap; } - - hda_sdw_int_enable(sdev, true); } init_waitqueue_head(&hdev->waitq); @@ -938,6 +936,12 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) /* disable DSP */ hda_dsp_ctrl_ppcap_enable(sdev, false); + /* Free the persistent DMA buffers used for base firmware download */ + if (hda->cl_dmab.area) + snd_dma_free_pages(&hda->cl_dmab); + if (hda->iccmax_dmab.area) + snd_dma_free_pages(&hda->iccmax_dmab); + skip_disable_dsp: free_irq(sdev->ipc_irq, sdev); if (sdev->msi_enabled) @@ -1066,7 +1070,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev { struct snd_sof_pdata *pdata = sdev->pdata; const struct snd_soc_acpi_link_adr *link; - struct sdw_extended_slave_id *ids; + struct sdw_peripherals *peripherals; struct snd_soc_acpi_mach *mach; struct sof_intel_hda_dev *hdev; u32 link_mask; @@ -1085,7 +1089,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev return NULL; } - if (!hdev->sdw->num_slaves) { + if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) { dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n"); return NULL; } @@ -1121,13 +1125,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * are not found on this link. */ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, - hdev->sdw->ids, - hdev->sdw->num_slaves)) + hdev->sdw->peripherals)) break; } /* Found if all Slaves are checked */ if (i == hdev->info.count || !link->num_adr) - break; + if (!mach->machine_check || mach->machine_check(hdev->sdw)) + break; } if (mach && mach->link_mask) { mach->mach_params.links = mach->links; @@ -1138,10 +1142,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev } dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n"); - ids = hdev->sdw->ids; - for (i = 0; i < hdev->sdw->num_slaves; i++) + peripherals = hdev->sdw->peripherals; + for (i = 0; i < peripherals->num_peripherals; i++) dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n", - ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version); + peripherals->array[i]->bus->link_id, + peripherals->array[i]->id.mfg_id, + peripherals->array[i]->id.part_id, + peripherals->array[i]->id.sdw_version); return NULL; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b74a472435b5..22bd9c3c8216 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -495,6 +495,15 @@ struct sof_intel_hda_dev { int boot_iteration; + /* + * DMA buffers for base firmware download. By default the buffers are + * allocated once and kept through the lifetime of the driver. + * See module parameter: persistent_cl_buffer + */ + struct snd_dma_buffer cl_dmab; + bool cl_dmab_contains_basefw; + struct snd_dma_buffer iccmax_dmab; + struct hda_bus hbus; /* hw config */ @@ -714,11 +723,12 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, - int direction, bool is_iccmax); + bool persistent_buffer, int direction, + bool is_iccmax); int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - struct hdac_ext_stream *hext_stream); + bool persistent_buffer, struct hdac_ext_stream *hext_stream); int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); #define HDA_CL_STREAM_FORMAT 0x40 diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 3d5a1f8b17e5..e3c4b4a0d705 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -192,16 +192,8 @@ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } -static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - - hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable); -} - static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { - lnl_enable_sdw_irq(sdev, false); mtl_disable_ipc_interrupts(sdev); return mtl_enable_interrupts(sdev, false); } @@ -237,7 +229,6 @@ const struct sof_intel_dsp_desc lnl_chip_info = { .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, .sdw_process_wakeen = hda_sdw_process_wakeen_common, @@ -262,7 +253,6 @@ const struct sof_intel_dsp_desc ptl_chip_info = { .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, diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c index 35b89c2b9d4c..7e9c76d5b2c9 100644 --- a/sound/soc/sof/ipc3-loader.c +++ b/sound/soc/sof/ipc3-loader.c @@ -193,6 +193,9 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) case SOF_EXT_MAN_ELEM_CC_VERSION: ret = ipc3_fw_ext_man_get_cc_info(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_PROBE_INFO: + dev_dbg(sdev->dev, "Probe info (not parsed)\n"); + break; case SOF_EXT_MAN_ELEM_DBG_ABI: ret = ipc3_fw_ext_man_get_dbg_abi_info(sdev, elem_hdr); break; diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 83c22d4a4830..7de5e3d285e7 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -226,7 +226,7 @@ static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) static void sof_ipc3_dump_payload(struct snd_sof_dev *sdev, void *ipc_data, size_t size) { - printk(KERN_DEBUG "Size of payload following the header: %zu\n", size); + dev_dbg(sdev->dev, "Size of payload following the header: %zu\n", size); print_hex_dump_debug("Message payload: ", DUMP_PREFIX_OFFSET, 16, 4, ipc_data, size, false); } diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 4df2be3d39eb..18fff2df76f9 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -603,6 +603,9 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, unsigned int be_rate; int i; + if (WARN_ON_ONCE(!num_input_formats)) + return -EINVAL; + /* * Copier does not change sampling rate, so we * need to only consider the input pin information. diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 240fee2166d1..b55eb977e443 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -195,7 +195,7 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo for (i = 0; i < num_formats; i++) { struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; dev_dbg(dev, - "Pin index #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", + "Pin #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg), fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg, @@ -203,6 +203,101 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo } } +static void +sof_ipc4_dbg_module_audio_format(struct device *dev, + struct snd_sof_widget *swidget, + struct sof_ipc4_available_audio_format *available_fmt, + int in_fmt_index, int out_fmt_index) +{ + struct sof_ipc4_audio_format *in_fmt, *out_fmt; + u32 out_rate, out_channels, out_valid_bits; + u32 in_rate, in_channels, in_valid_bits; + struct sof_ipc4_pin_format *pin_fmt; + + if (!available_fmt->num_input_formats && + !available_fmt->num_output_formats) + return; + + /* Only input or output is supported by the module */ + if (!available_fmt->num_input_formats) { + if (available_fmt->num_output_formats == 1) + dev_dbg(dev, "Output audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Output audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } else if (!available_fmt->num_output_formats) { + if (available_fmt->num_input_formats == 1) + dev_dbg(dev, "Input audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Input audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } + + in_fmt = &available_fmt->input_pin_fmts[in_fmt_index].audio_fmt; + out_fmt = &available_fmt->output_pin_fmts[out_fmt_index].audio_fmt; + + in_rate = in_fmt->sampling_frequency; + in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + out_rate = out_fmt->sampling_frequency; + out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); + out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + + if (!(in_valid_bits != out_valid_bits || in_rate != out_rate || + in_channels != out_channels)) { + /* There is no change in format */ + if (available_fmt->num_input_formats == 1 && + available_fmt->num_output_formats == 1) + dev_dbg(dev, "Audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Audio format (in/out format index: %d/%d) for %s:\n", + in_fmt_index, out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } + + /* The format is changed by the module */ + if (available_fmt->num_input_formats == 1) + dev_dbg(dev, "Input audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, "Input audio format (format index: %d) for %s:\n", + in_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + if (available_fmt->num_output_formats == 1) + dev_dbg(dev, "Output audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, "Output audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); +} + static const struct sof_ipc4_audio_format * sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) { @@ -660,7 +755,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) * It is fine to call kfree(ipc4_copier->copier_config) since * ipc4_copier->copier_config is null. */ - ret = 0; break; } @@ -1205,47 +1299,56 @@ static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, } static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config, struct sof_ipc4_available_audio_format *available_fmt, u32 out_ref_rate, u32 out_ref_channels, u32 out_ref_valid_bits) { - struct sof_ipc4_audio_format *out_fmt; + struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts; + u32 pin_fmts_size = available_fmt->num_output_formats; bool single_format; - int i; + int i = 0; - if (!available_fmt->num_output_formats) + if (!pin_fmts_size) { + dev_err(sdev->dev, "no output formats for %s\n", + swidget->widget->name); return -EINVAL; + } - single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts, - available_fmt->num_output_formats); + single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); /* pick the first format if there's only one available or if all formats are the same */ - if (single_format) { - base_config->obs = available_fmt->output_pin_fmts[0].buffer_size; - return 0; - } + if (single_format) + goto out_fmt; /* * if there are multiple output formats, then choose the output format that matches * the reference params */ - for (i = 0; i < available_fmt->num_output_formats; i++) { + for (i = 0; i < pin_fmts_size; i++) { + struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; + u32 _out_rate, _out_channels, _out_valid_bits; - out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; - _out_rate = out_fmt->sampling_frequency; - _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); - _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + _out_rate = fmt->sampling_frequency; + _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); if (_out_rate == out_ref_rate && _out_channels == out_ref_channels && - _out_valid_bits == out_ref_valid_bits) { - base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; - return i; - } + _out_valid_bits == out_ref_valid_bits) + goto out_fmt; } + dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", + __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels); + return -EINVAL; + +out_fmt: + base_config->obs = pin_fmts[i].buffer_size; + + return i; } static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) @@ -1278,13 +1381,12 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, int sample_valid_bits; int i = 0; - if (!available_fmt->num_input_formats) { + if (!pin_fmts_size) { dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name); return -EINVAL; } - single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); if (single_format) goto in_fmt; @@ -1306,11 +1408,8 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); if (params_rate(params) == rate && params_channels(params) == channels && - sample_valid_bits == valid_bits) { - dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n", - rate, valid_bits, channels, i); + sample_valid_bits == valid_bits) break; - } } if (i == pin_fmts_size) { @@ -1321,16 +1420,11 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, in_fmt: /* copy input format */ - if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { - memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, - sizeof(struct sof_ipc4_audio_format)); + memcpy(&base_config->audio_fmt, &pin_fmts[i].audio_fmt, + sizeof(struct sof_ipc4_audio_format)); - /* set base_cfg ibs/obs */ - base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; - - dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); - } + /* set base_cfg ibs/obs */ + base_config->ibs = pin_fmts[i].buffer_size; return i; } @@ -1706,6 +1800,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_copier_data *copier_data; + int input_fmt_index, output_fmt_index; struct snd_pcm_hw_params ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; @@ -1717,7 +1812,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, int ipc_size, ret, out_ref_valid_bits; u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; - int output_fmt_index; bool single_output_bitdepth; int i; @@ -1849,10 +1943,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* set input and output audio formats */ - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, - &ref_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &copier_data->base_config, + &ref_params, available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; /* set the reference params for output format selection */ single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, @@ -1865,7 +1960,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, { struct sof_ipc4_audio_format *in_fmt; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); @@ -1904,17 +1999,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); } - dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n", - swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits); - - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (output_fmt_index < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); + if (output_fmt_index < 0) return output_fmt_index; - } /* * Set the output format. Current topology defines pin 0 input and output formats in pairs. @@ -1926,8 +2016,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, sizeof(struct sof_ipc4_audio_format)); - dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1); switch (swidget->id) { case snd_soc_dapm_dai_in: @@ -2104,6 +2192,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, *ipc_config_size = ipc_size; + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); + /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); @@ -2139,25 +2230,31 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret; + int input_fmt_index, output_fmt_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->data.base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &gain->data.base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->data.base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return ret; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &gain->data.base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config); @@ -2176,25 +2273,31 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret; + int input_fmt_index, output_fmt_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &mixer->base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return ret; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &mixer->base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config); @@ -2214,12 +2317,14 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int output_format_index, input_format_index; + int output_fmt_index, input_fmt_index; - input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->data.base_config, - pipeline_params, available_fmt); - if (input_format_index < 0) - return input_format_index; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &src->data.base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; /* * For playback, the SRC sink rate will be configured based on the requested output @@ -2235,7 +2340,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, * SRC does not perform format conversion, so the output channels and valid bit depth must * be the same as that of the input. */ - in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt; + in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); @@ -2246,19 +2351,22 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, */ out_ref_rate = params_rate(fe_params); - output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->data.base_config, - available_fmt, out_ref_rate, - out_ref_channels, out_ref_valid_bits); - if (output_format_index < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return output_format_index; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &src->data.base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config); - out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; + out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt; src->data.sink_rate = out_audio_fmt->sampling_frequency; /* update pipeline_params for sink widgets */ @@ -2355,49 +2463,61 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_process *process = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; - struct sof_ipc4_audio_format *in_fmt; - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; void *cfg = process->ipc_config_data; - int output_fmt_index; + int output_fmt_index = 0; + int input_fmt_index = 0; int ret; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &process->base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + /* Configure output audio format only if the module supports output */ + if (available_fmt->num_output_formats) { + struct sof_ipc4_audio_format *in_fmt; + struct sof_ipc4_pin_format *pin_fmt; + u32 out_ref_rate, out_ref_channels; + int out_ref_valid_bits; - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config, - available_fmt, out_ref_rate, - out_ref_channels, out_ref_valid_bits); - if (output_fmt_index < 0 && available_fmt->num_output_formats) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return output_fmt_index; - } + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; - /* copy Pin 0 output format */ - if (available_fmt->num_output_formats && - output_fmt_index < available_fmt->num_output_formats && - !available_fmt->output_pin_fmts[output_fmt_index].pin_index) { - memcpy(&process->output_format, - &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, - sizeof(struct sof_ipc4_audio_format)); - - /* modify the pipeline params with the pin 0 output format */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, - &process->output_format, - BIT(SNDRV_PCM_HW_PARAM_FORMAT) | - BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | - BIT(SNDRV_PCM_HW_PARAM_RATE)); - if (ret) - return ret; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &process->base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + pin_fmt = &available_fmt->output_pin_fmts[output_fmt_index]; + + /* copy Pin output format for Pin 0 only */ + if (pin_fmt->pin_index == 0) { + memcpy(&process->output_format, &pin_fmt->audio_fmt, + sizeof(struct sof_ipc4_audio_format)); + + /* modify the pipeline params with the output format */ + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, + &process->output_format, + BIT(SNDRV_PCM_HW_PARAM_FORMAT) | + BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | + BIT(SNDRV_PCM_HW_PARAM_RATE)); + if (ret) + return ret; + } } + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); + /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config); diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index b12b3d865ae3..c0c906a78eba 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -55,10 +55,9 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].no_pcm = 1; links[i].cpus->dai_name = drv[i].name; links[i].platforms->name = dev_name(dev->parent); - if (drv[i].playback.channels_min) - links[i].dpcm_playback = 1; - if (drv[i].capture.channels_min) - links[i].dpcm_capture = 1; + + links[i].playback_only = drv[i].playback.channels_min && !drv[i].capture.channels_min; + links[i].capture_only = !drv[i].playback.channels_min && drv[i].capture.channels_min; links[i].be_hw_params_fixup = sof_pcm_dai_link_fixup; } diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b196b2b74c26..76ff798a4a1e 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -24,11 +24,11 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); static int sof_acpi_debug; module_param_named(sof_acpi_debug, sof_acpi_debug, int, 0444); diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 71f7153cf79c..fb8c8a14d885 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -16,11 +16,19 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); + +static char *fw_filename; +module_param(fw_filename, charp, 0444); +MODULE_PARM_DESC(fw_filename, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); + +static char *tplg_filename; +module_param(tplg_filename, charp, 0444); +MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module."); const struct dev_pm_ops sof_of_pm = { .prepare = snd_sof_prepare, @@ -68,6 +76,8 @@ int sof_of_probe(struct platform_device *pdev) sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; sof_pdata->ipc_file_profile_base.fw_path = fw_path; sof_pdata->ipc_file_profile_base.tplg_path = tplg_path; + sof_pdata->ipc_file_profile_base.fw_name = fw_filename; + sof_pdata->ipc_file_profile_base.tplg_name = tplg_filename; /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_of_probe_complete; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 38f2187da5de..fe5650616573 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -22,23 +22,23 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); static char *fw_filename; module_param(fw_filename, charp, 0444); -MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware."); +MODULE_PARM_DESC(fw_filename, "deprecated - moved to snd-sof module."); static char *lib_path; module_param(lib_path, charp, 0444); -MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries."); +MODULE_PARM_DESC(lib_path, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); static char *tplg_filename; module_param(tplg_filename, charp, 0444); -MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology."); +MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module."); static int sof_pci_debug; module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); @@ -46,7 +46,7 @@ MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); static int sof_pci_ipc_type = -1; module_param_named(ipc_type, sof_pci_ipc_type, int, 0444); -MODULE_PARM_DESC(ipc_type, "Force SOF IPC type. 0 - IPC3, 1 - IPC4"); +MODULE_PARM_DESC(ipc_type, "deprecated - moved to snd-sof module."); static const char *sof_dmi_override_tplg_name; static bool sof_dmi_use_community_key; diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 9351727dce1a..c914d1c46850 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -142,7 +142,7 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = { SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &stm32_adfsdm_dai_ops, }; @@ -309,7 +309,7 @@ static void stm32_adfsdm_cleanup(void *data) iio_channel_release_all_cb(data); } -static struct snd_soc_component_driver stm32_adfsdm_soc_platform = { +static const struct snd_soc_component_driver stm32_adfsdm_soc_platform = { .open = stm32_adfsdm_pcm_open, .close = stm32_adfsdm_pcm_close, .hw_params = stm32_adfsdm_pcm_hw_params, diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index faa00103ee7f..19dc61008a75 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -200,10 +200,13 @@ enum i2s_datlen { #define STM32_I2S_NAME_LEN 32 #define STM32_I2S_RATE_11K 11025 +#define STM32_I2S_MAX_SAMPLE_RATE_8K 192000 +#define STM32_I2S_MAX_SAMPLE_RATE_11K 176400 +#define STM32_I2S_CLK_RATE_TOLERANCE 1000 /* ppm */ /** * struct stm32_i2s_data - private data of I2S - * @regmap_conf: I2S register map configuration pointer + * @conf: I2S configuration pointer * @regmap: I2S register map pointer * @pdev: device data pointer * @dai_drv: DAI driver pointer @@ -224,11 +227,14 @@ enum i2s_datlen { * @divider: prescaler division ratio * @div: prescaler div field * @odd: prescaler odd field + * @i2s_clk_flg: flag set while exclusivity on I2S kernel clock is active * @refcount: keep count of opened streams on I2S * @ms_flg: master mode flag. + * @set_i2s_clk_rate: set I2S kernel clock rate + * @put_i2s_clk_rate: put I2S kernel clock rate */ struct stm32_i2s_data { - const struct regmap_config *regmap_conf; + const struct stm32_i2s_conf *conf; struct regmap *regmap; struct platform_device *pdev; struct snd_soc_dai_driver *dai_drv; @@ -249,8 +255,21 @@ struct stm32_i2s_data { unsigned int divider; unsigned int div; bool odd; + bool i2s_clk_flg; int refcount; int ms_flg; + int (*set_i2s_clk_rate)(struct stm32_i2s_data *i2s, unsigned int rate); + void (*put_i2s_clk_rate)(struct stm32_i2s_data *i2s); +}; + +/** + * struct stm32_i2s_conf - I2S configuration + * @regmap_conf: regmap configuration pointer + * @get_i2s_clk_parent: get parent clock of I2S kernel clock + */ +struct stm32_i2s_conf { + const struct regmap_config *regmap_conf; + int (*get_i2s_clk_parent)(struct stm32_i2s_data *i2s); }; struct stm32_i2smclk_data { @@ -261,6 +280,8 @@ struct stm32_i2smclk_data { #define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw) +static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s); + static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s, unsigned long input_rate, unsigned long output_rate) @@ -312,6 +333,33 @@ static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s) cgfr_mask, cgfr); } +static bool stm32_i2s_rate_accurate(struct stm32_i2s_data *i2s, + unsigned int max_rate, unsigned int rate) +{ + struct platform_device *pdev = i2s->pdev; + u64 delta, dividend; + int ratio; + + if (!rate) { + dev_err(&pdev->dev, "Unexpected null rate\n"); + return false; + } + + ratio = DIV_ROUND_CLOSEST(max_rate, rate); + if (!ratio) + return false; + + dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate))); + delta = div_u64(dividend, max_rate); + + if (delta <= STM32_I2S_CLK_RATE_TOLERANCE) + return true; + + dev_dbg(&pdev->dev, "Rate [%u] not accurate\n", rate); + + return false; +} + static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, unsigned int rate) { @@ -332,6 +380,87 @@ static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, return ret; } +static void stm32_i2s_put_parent_rate(struct stm32_i2s_data *i2s) +{ + if (i2s->i2s_clk_flg) { + i2s->i2s_clk_flg = false; + clk_rate_exclusive_put(i2s->i2sclk); + } +} + +static int stm32_i2s_set_parent_rate(struct stm32_i2s_data *i2s, + unsigned int rate) +{ + struct platform_device *pdev = i2s->pdev; + unsigned int i2s_clk_rate, i2s_clk_max_rate, i2s_curr_rate, i2s_new_rate; + int ret, div; + + /* + * Set maximum expected kernel clock frequency + * - mclk on: + * f_i2s_ck = MCKDIV * mclk-fs * fs + * Here typical 256 ratio is assumed for mclk-fs + * - mclk off: + * f_i2s_ck = MCKDIV * FRL * fs + * Where FRL=[16,32], MCKDIV=[1..256] + * f_i2s_ck = i2s_clk_max_rate * 32 / 256 + */ + if (!(rate % STM32_I2S_RATE_11K)) + i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_11K * 256; + else + i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_8K * 256; + + if (!i2s->i2smclk) + i2s_clk_max_rate /= 8; + + /* Request exclusivity, as the clock may be shared by I2S instances */ + clk_rate_exclusive_get(i2s->i2sclk); + i2s->i2s_clk_flg = true; + + /* + * Check current kernel clock rate. If it gives the expected accuracy + * return immediately. + */ + i2s_curr_rate = clk_get_rate(i2s->i2sclk); + if (stm32_i2s_rate_accurate(i2s, i2s_clk_max_rate, i2s_curr_rate)) + return 0; + + /* + * Otherwise try to set the maximum rate and check the new actual rate. + * If the new rate does not give the expected accuracy, try to set + * lower rates for the kernel clock. + */ + i2s_clk_rate = i2s_clk_max_rate; + div = 1; + do { + /* Check new rate accuracy. Return if ok */ + i2s_new_rate = clk_round_rate(i2s->i2sclk, i2s_clk_rate); + if (stm32_i2s_rate_accurate(i2s, i2s_clk_rate, i2s_new_rate)) { + ret = clk_set_rate(i2s->i2sclk, i2s_clk_rate); + if (ret) { + dev_err(&pdev->dev, "Error %d setting i2s_clk_rate rate. %s", + ret, ret == -EBUSY ? + "Active stream rates may be in conflict\n" : "\n"); + goto err; + } + + return 0; + } + + /* Try a lower frequency */ + div++; + i2s_clk_rate = i2s_clk_max_rate / div; + } while (i2s_clk_rate > rate); + + /* no accurate rate found */ + dev_err(&pdev->dev, "Failed to find an accurate rate"); + +err: + stm32_i2s_put_parent_rate(i2s); + + return -EINVAL; +} + static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -635,12 +764,16 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, clk_rate_exclusive_put(i2s->i2smclk); i2s->mclk_rate = 0; } + + if (i2s->put_i2s_clk_rate) + i2s->put_i2s_clk_rate(i2s); + return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0); } /* If master clock is used, set parent clock now */ - ret = stm32_i2s_set_parent_clock(i2s, freq); + ret = i2s->set_i2s_clk_rate(i2s, freq); if (ret) return ret; ret = clk_set_rate_exclusive(i2s->i2smclk, freq); @@ -667,10 +800,11 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, u32 cgfr; int ret; - if (!(rate % 11025)) - clk_set_parent(i2s->i2sclk, i2s->x11kclk); - else - clk_set_parent(i2s->i2sclk, i2s->x8kclk); + if (!i2s->mclk_rate) { + ret = i2s->set_i2s_clk_rate(i2s, rate); + if (ret) + return ret; + } i2s_clock_rate = clk_get_rate(i2s->i2sclk); /* @@ -915,6 +1049,14 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(i2s->i2sclk); + /* + * Release kernel clock if following conditions are fulfilled + * - Master clock is not used. Kernel clock won't be released trough sysclk + * - Put handler is defined. Involve that clock is managed exclusively + */ + if (!i2s->i2smclk && i2s->put_i2s_clk_rate) + i2s->put_i2s_clk_rate(i2s); + spin_lock_irqsave(&i2s->irq_lock, flags); i2s->substream = NULL; spin_unlock_irqrestore(&i2s->irq_lock, flags); @@ -1012,14 +1154,36 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, return 0; } +static const struct stm32_i2s_conf stm32_i2s_conf_h7 = { + .regmap_conf = &stm32_h7_i2s_regmap_conf, + .get_i2s_clk_parent = stm32_i2s_get_parent_clk, +}; + +static const struct stm32_i2s_conf stm32_i2s_conf_mp25 = { + .regmap_conf = &stm32_h7_i2s_regmap_conf +}; + static const struct of_device_id stm32_i2s_ids[] = { - { - .compatible = "st,stm32h7-i2s", - .data = &stm32_h7_i2s_regmap_conf - }, + { .compatible = "st,stm32h7-i2s", .data = &stm32_i2s_conf_h7 }, + { .compatible = "st,stm32mp25-i2s", .data = &stm32_i2s_conf_mp25 }, {}, }; +static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s) +{ + struct device *dev = &i2s->pdev->dev; + + i2s->x8kclk = devm_clk_get(dev, "x8k"); + if (IS_ERR(i2s->x8kclk)) + return dev_err_probe(dev, PTR_ERR(i2s->x8kclk), "Cannot get x8k parent clock\n"); + + i2s->x11kclk = devm_clk_get(dev, "x11k"); + if (IS_ERR(i2s->x11kclk)) + return dev_err_probe(dev, PTR_ERR(i2s->x11kclk), "Cannot get x11k parent clock\n"); + + return 0; +} + static int stm32_i2s_parse_dt(struct platform_device *pdev, struct stm32_i2s_data *i2s) { @@ -1031,8 +1195,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, if (!np) return -ENODEV; - i2s->regmap_conf = device_get_match_data(&pdev->dev); - if (!i2s->regmap_conf) + i2s->conf = device_get_match_data(&pdev->dev); + if (!i2s->conf) return -EINVAL; i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); @@ -1052,15 +1216,18 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, return dev_err_probe(&pdev->dev, PTR_ERR(i2s->i2sclk), "Could not get i2sclk\n"); - i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(i2s->x8kclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x8kclk), - "Could not get x8k parent clock\n"); + if (i2s->conf->get_i2s_clk_parent) { + i2s->set_i2s_clk_rate = stm32_i2s_set_parent_clock; + } else { + i2s->set_i2s_clk_rate = stm32_i2s_set_parent_rate; + i2s->put_i2s_clk_rate = stm32_i2s_put_parent_rate; + } - i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(i2s->x11kclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x11kclk), - "Could not get x11k parent clock\n"); + if (i2s->conf->get_i2s_clk_parent) { + ret = i2s->conf->get_i2s_clk_parent(i2s); + if (ret) + return ret; + } /* Register mclk provider if requested */ if (of_property_present(np, "#clock-cells")) { @@ -1126,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev) return ret; i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", - i2s->base, i2s->regmap_conf); + i2s->base, i2s->conf->regmap_conf); if (IS_ERR(i2s->regmap)) return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "Regmap init error\n"); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index b45ee7e24f22..bc8180fc8462 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -19,26 +19,42 @@ #include "stm32_sai.h" +static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai); + static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = STM_SAI_STM32F4, .fifo_size = 8, .has_spdif_pdm = false, + .get_sai_ck_parent = stm32_sai_get_parent_clk, }; /* - * Default settings for stm32 H7 socs and next. + * Default settings for STM32H7x socs and STM32MP1x. * These default settings will be overridden if the soc provides * support of hardware configuration registers. + * - STM32H7: rely on default settings + * - STM32MP1: retrieve settings from registers */ static const struct stm32_sai_conf stm32_sai_conf_h7 = { .version = STM_SAI_STM32H7, .fifo_size = 8, .has_spdif_pdm = true, + .get_sai_ck_parent = stm32_sai_get_parent_clk, +}; + +/* + * STM32MP2x: + * - do not use SAI parent clock source selection + * - do not use DMA burst mode + */ +static const struct stm32_sai_conf stm32_sai_conf_mp25 = { + .no_dma_burst = true, }; static const struct of_device_id stm32_sai_ids[] = { { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, + { .compatible = "st,stm32mp25-sai", .data = (void *)&stm32_sai_conf_mp25 }, {} }; @@ -148,6 +164,29 @@ error: return ret; } +static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) +{ + struct device *dev = &sai->pdev->dev; + + sai->clk_x8k = devm_clk_get(dev, "x8k"); + if (IS_ERR(sai->clk_x8k)) { + if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) + dev_err(dev, "missing x8k parent clock: %ld\n", + PTR_ERR(sai->clk_x8k)); + return PTR_ERR(sai->clk_x8k); + } + + sai->clk_x11k = devm_clk_get(dev, "x11k"); + if (IS_ERR(sai->clk_x11k)) { + if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) + dev_err(dev, "missing x11k parent clock: %ld\n", + PTR_ERR(sai->clk_x11k)); + return PTR_ERR(sai->clk_x11k); + } + + return 0; +} + static int stm32_sai_probe(struct platform_device *pdev) { struct stm32_sai_data *sai; @@ -160,6 +199,8 @@ static int stm32_sai_probe(struct platform_device *pdev) if (!sai) return -ENOMEM; + sai->pdev = pdev; + sai->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sai->base)) return PTR_ERR(sai->base); @@ -178,15 +219,11 @@ static int stm32_sai_probe(struct platform_device *pdev) "missing bus clock pclk\n"); } - sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(sai->clk_x8k)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k), - "missing x8k parent clock\n"); - - sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(sai->clk_x11k)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k), - "missing x11k parent clock\n"); + if (sai->conf.get_sai_ck_parent) { + ret = sai->conf.get_sai_ck_parent(sai); + if (ret) + return ret; + } /* init irqs */ sai->irq = platform_get_irq(pdev, 0); @@ -227,7 +264,6 @@ static int stm32_sai_probe(struct platform_device *pdev) } clk_disable_unprepare(sai->pclk); - sai->pdev = pdev; sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index 33e4bff8c2f5..07b71133db2a 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -264,16 +264,22 @@ enum stm32_sai_syncout { STM_SAI_SYNC_OUT_B, }; +struct stm32_sai_data; + /** * struct stm32_sai_conf - SAI configuration + * @get_sai_ck_parent: get parent clock of SAI kernel clock * @version: SAI version * @fifo_size: SAI fifo size as words number * @has_spdif_pdm: SAI S/PDIF and PDM features support flag + * @no_dma_burst: Support only DMA single transfers if set */ struct stm32_sai_conf { + int (*get_sai_ck_parent)(struct stm32_sai_data *sai); u32 version; u32 fifo_size; bool has_spdif_pdm; + bool no_dma_burst; }; /** diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 5828f9dd866e..3efbf4aaf965 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -53,13 +53,16 @@ #define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif) #define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf.has_spdif_pdm) #define STM_SAI_HAS_PDM(x) ((x)->pdata->conf.has_spdif_pdm) -#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) +#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4((x)->pdata)) #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 #define SAI_MCLK_NAME_LEN 32 #define SAI_RATE_11K 11025 +#define SAI_MAX_SAMPLE_RATE_8K 192000 +#define SAI_MAX_SAMPLE_RATE_11K 176400 +#define SAI_CK_RATE_TOLERANCE 1000 /* ppm */ /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) @@ -80,6 +83,7 @@ * @dir: SAI block direction (playback or capture). set at init * @master: SAI block mode flag. (true=master, false=slave) set at init * @spdif: SAI S/PDIF iec60958 mode flag. set at init + * @sai_ck_used: flag set while exclusivity on SAI kernel clock is active * @fmt: SAI block format. relevant only for custom protocols. set at init * @sync: SAI block synchronization mode. (none, internal or external) * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) @@ -93,6 +97,8 @@ * @iec958: iec958 data * @ctrl_lock: control lock * @irq_lock: prevent race condition with IRQ + * @set_sai_ck_rate: set SAI kernel clock rate + * @put_sai_ck_rate: put SAI kernel clock rate */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -112,6 +118,7 @@ struct stm32_sai_sub_data { int dir; bool master; bool spdif; + bool sai_ck_used; int fmt; int sync; int synco; @@ -125,6 +132,8 @@ struct stm32_sai_sub_data { struct snd_aes_iec958 iec958; struct mutex ctrl_lock; /* protect resources accessed by controls */ spinlock_t irq_lock; /* used to prevent race condition with IRQ */ + int (*set_sai_ck_rate)(struct stm32_sai_sub_data *sai, unsigned int rate); + void (*put_sai_ck_rate)(struct stm32_sai_sub_data *sai); }; enum stm32_sai_fifo_th { @@ -351,8 +360,26 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, return ret; } -static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, - unsigned int rate) +static bool stm32_sai_rate_accurate(unsigned int max_rate, unsigned int rate) +{ + u64 delta, dividend; + int ratio; + + ratio = DIV_ROUND_CLOSEST(max_rate, rate); + if (!ratio) + return false; + + dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate))); + delta = div_u64(dividend, max_rate); + + if (delta <= SAI_CK_RATE_TOLERANCE) + return true; + + return false; +} + +static int stm32_sai_set_parent_clk(struct stm32_sai_sub_data *sai, + unsigned int rate) { struct platform_device *pdev = sai->pdev; struct clk *parent_clk = sai->pdata->clk_x8k; @@ -370,6 +397,92 @@ static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, return ret; } +static void stm32_sai_put_parent_rate(struct stm32_sai_sub_data *sai) +{ + if (sai->sai_ck_used) { + sai->sai_ck_used = false; + clk_rate_exclusive_put(sai->sai_ck); + } +} + +static int stm32_sai_set_parent_rate(struct stm32_sai_sub_data *sai, + unsigned int rate) +{ + struct platform_device *pdev = sai->pdev; + unsigned int sai_ck_rate, sai_ck_max_rate, sai_curr_rate, sai_new_rate; + int div, ret; + + /* + * Set maximum expected kernel clock frequency + * - mclk on or spdif: + * f_sai_ck = MCKDIV * mclk-fs * fs + * Here typical 256 ratio is assumed for mclk-fs + * - mclk off: + * f_sai_ck = MCKDIV * FRL * fs + * Where FRL=[8..256], MCKDIV=[1..n] (n depends on SAI version) + * Set constraint MCKDIV * FRL <= 256, to ensure MCKDIV is in available range + * f_sai_ck = sai_ck_max_rate * pow_of_two(FRL) / 256 + */ + if (!(rate % SAI_RATE_11K)) + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_11K * 256; + else + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_8K * 256; + + if (!sai->sai_mclk && !STM_SAI_PROTOCOL_IS_SPDIF(sai)) + sai_ck_max_rate /= DIV_ROUND_CLOSEST(256, roundup_pow_of_two(sai->fs_length)); + + /* + * Request exclusivity, as the clock is shared by SAI sub-blocks and by + * some SAI instances. This allows to ensure that the rate cannot be + * changed while one or more SAIs are using the clock. + */ + clk_rate_exclusive_get(sai->sai_ck); + sai->sai_ck_used = true; + + /* + * Check current kernel clock rate. If it gives the expected accuracy + * return immediately. + */ + sai_curr_rate = clk_get_rate(sai->sai_ck); + if (stm32_sai_rate_accurate(sai_ck_max_rate, sai_curr_rate)) + return 0; + + /* + * Otherwise try to set the maximum rate and check the new actual rate. + * If the new rate does not give the expected accuracy, try to set + * lower rates for the kernel clock. + */ + sai_ck_rate = sai_ck_max_rate; + div = 1; + do { + /* Check new rate accuracy. Return if ok */ + sai_new_rate = clk_round_rate(sai->sai_ck, sai_ck_rate); + if (stm32_sai_rate_accurate(sai_ck_rate, sai_new_rate)) { + ret = clk_set_rate(sai->sai_ck, sai_ck_rate); + if (ret) { + dev_err(&pdev->dev, "Error %d setting sai_ck rate. %s", + ret, ret == -EBUSY ? + "Active stream rates may be in conflict\n" : "\n"); + goto err; + } + + return 0; + } + + /* Try a lower frequency */ + div++; + sai_ck_rate = sai_ck_max_rate / div; + } while (sai_ck_rate > rate); + + /* No accurate rate found */ + dev_err(&pdev->dev, "Failed to find an accurate rate"); + +err: + stm32_sai_put_parent_rate(sai); + + return -EINVAL; +} + static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -565,11 +678,15 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, clk_rate_exclusive_put(sai->sai_mclk); sai->mclk_rate = 0; } + + if (sai->put_sai_ck_rate) + sai->put_sai_ck_rate(sai); + return 0; } - /* If master clock is used, set parent clock now */ - ret = stm32_sai_set_parent_clock(sai, freq); + /* If master clock is used, configure SAI kernel clock now */ + ret = sai->set_sai_ck_rate(sai, freq); if (ret) return ret; @@ -993,7 +1110,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, int ret; if (!sai->sai_mclk) { - ret = stm32_sai_set_parent_clock(sai, rate); + ret = sai->set_sai_ck_rate(sai, rate); if (ret) return ret; } @@ -1154,6 +1271,14 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(sai->sai_ck); + /* + * Release kernel clock if following conditions are fulfilled + * - Master clock is not used. Kernel clock won't be released trough sysclk + * - Put handler is defined. Involve that clock is managed exclusively + */ + if (!sai->sai_mclk && sai->put_sai_ck_rate) + sai->put_sai_ck_rate(sai); + spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = NULL; spin_unlock_irqrestore(&sai->irq_lock, flags); @@ -1188,7 +1313,7 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) * constraints). */ sai->dma_params.maxburst = 4; - if (sai->pdata->conf.fifo_size < 8) + if (sai->pdata->conf.fifo_size < 8 || sai->pdata->conf.no_dma_burst) sai->dma_params.maxburst = 1; /* Buswidth will be set by framework at runtime */ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; @@ -1526,6 +1651,13 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) return -EINVAL; } + if (sai->pdata->conf.get_sai_ck_parent) { + sai->set_sai_ck_rate = stm32_sai_set_parent_clk; + } else { + sai->set_sai_ck_rate = stm32_sai_set_parent_rate; + sai->put_sai_ck_rate = stm32_sai_put_parent_rate; + } + ret = stm32_sai_sub_parse_of(pdev, sai); if (ret) return ret; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 330bc0c09f56..933a0913237c 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -226,6 +226,43 @@ #define SUN8I_H3_CODEC_DAC_DBG (0x48) #define SUN8I_H3_CODEC_ADC_DBG (0x4c) +/* H616 specific registers */ +#define SUN50I_H616_CODEC_DAC_FIFOC (0x10) + +#define SUN50I_DAC_FIFO_STA (0x14) +#define SUN50I_DAC_TXE_INT (3) +#define SUN50I_DAC_TXU_INT (2) +#define SUN50I_DAC_TXO_INT (1) + +#define SUN50I_DAC_CNT (0x24) +#define SUN50I_DAC_DG_REG (0x28) +#define SUN50I_DAC_DAP_CTL (0xf0) + +#define SUN50I_H616_DAC_AC_DAC_REG (0x310) +#define SUN50I_H616_DAC_LEN (15) +#define SUN50I_H616_DAC_REN (14) +#define SUN50I_H616_LINEOUTL_EN (13) +#define SUN50I_H616_LMUTE (12) +#define SUN50I_H616_LINEOUTR_EN (11) +#define SUN50I_H616_RMUTE (10) +#define SUN50I_H616_RSWITCH (9) +#define SUN50I_H616_RAMPEN (8) +#define SUN50I_H616_LINEOUTL_SEL (6) +#define SUN50I_H616_LINEOUTR_SEL (5) +#define SUN50I_H616_LINEOUT_VOL (0) + +#define SUN50I_H616_DAC_AC_MIXER_REG (0x314) +#define SUN50I_H616_LMIX_LDAC (21) +#define SUN50I_H616_LMIX_RDAC (20) +#define SUN50I_H616_RMIX_RDAC (17) +#define SUN50I_H616_RMIX_LDAC (16) +#define SUN50I_H616_LMIXEN (11) +#define SUN50I_H616_RMIXEN (10) + +#define SUN50I_H616_DAC_AC_RAMP_REG (0x31c) +#define SUN50I_H616_RAMP_STEP (4) +#define SUN50I_H616_RDEN (0) + /* TODO H3 DAP (Digital Audio Processing) bits */ struct sun4i_codec { @@ -238,6 +275,8 @@ struct sun4i_codec { /* ADC_FIFOC register is at different offset on different SoCs */ struct regmap_field *reg_adc_fifoc; + /* DAC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_dac_fifoc; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -246,19 +285,19 @@ struct sun4i_codec { static void sun4i_codec_start_playback(struct sun4i_codec *scodec) { /* Flush TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Enable DAC DRQ */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) { /* Disable DAC DRQ */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_start_capture(struct sun4i_codec *scodec) @@ -356,13 +395,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, u32 val; /* Flush the TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Set TX FIFO Empty Trigger Level */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, - 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); + regmap_field_update_bits(scodec->reg_dac_fifoc, + 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, + 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); if (substream->runtime->rate > 32000) /* Use 64 bits FIR filter */ @@ -371,13 +410,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, /* Use 32 bits FIR filter */ val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION); - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), - val); + regmap_field_update_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), + val); /* Send zeros when we have an underrun */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); return 0; }; @@ -510,9 +549,9 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, u32 val; /* Set DAC sample rate */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, - hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); + regmap_field_update_bits(scodec->reg_dac_fifoc, + 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, + hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); /* Set the number of channels we want to use */ if (params_channels(params) == 1) @@ -520,27 +559,27 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, else val = 0; - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), - val); + regmap_field_update_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), + val); /* Set the number of sample bits to either 16 or 24 bits */ if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to padding the LSBs with 0 */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; } else { - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to repeat the MSB */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; } @@ -587,8 +626,8 @@ static int sun4i_codec_startup(struct snd_pcm_substream *substream, * Stop issuing DRQ when we have room for less than 16 samples * in our TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); + regmap_field_set_bits(scodec->reg_dac_fifoc, + 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); return clk_prepare_enable(scodec->clk_module); } @@ -1518,6 +1557,150 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) return card; }; +static const struct snd_kcontrol_new sun50i_h616_codec_codec_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUT_VOL, 0x1f, 0, + sun6i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUTL_EN, + SUN50I_H616_LINEOUTR_EN, 1, 0), +}; + +static const struct snd_kcontrol_new sun50i_h616_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE("DAC Playback Switch", + SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIX_LDAC, + SUN50I_H616_RMIX_RDAC, 1, 0), + SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", + SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIX_RDAC, + SUN50I_H616_RMIX_LDAC, 1, 0), +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_h616_codec_lineout_src_enum, + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUTL_SEL, + SUN50I_H616_LINEOUTR_SEL, + sun6i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun50i_h616_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_h616_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun50i_h616_codec_codec_widgets[] = { + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, + NULL, 0), + + /* Analog parts of the DACs */ + SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_DAC_LEN, 0), + SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_DAC_REN, 0), + + /* Mixers */ + SOC_MIXER_ARRAY("Left Mixer", SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIXEN, 0, + sun50i_h616_codec_mixer_controls), + SOC_MIXER_ARRAY("Right Mixer", SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_RMIXEN, 0, + sun50i_h616_codec_mixer_controls), + + /* Line Out path */ + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_h616_codec_lineout_src), + SND_SOC_DAPM_OUT_DRV("Line Out Ramp Controller", + SUN50I_H616_DAC_AC_RAMP_REG, + SUN50I_H616_RDEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_component_driver sun50i_h616_codec_codec = { + .controls = sun50i_h616_codec_codec_controls, + .num_controls = ARRAY_SIZE(sun50i_h616_codec_codec_controls), + .dapm_widgets = sun50i_h616_codec_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_codec_widgets), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct snd_kcontrol_new sun50i_h616_card_controls[] = { + SOC_DAPM_PIN_SWITCH("LINEOUT"), +}; + +static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun50i_h616_codec_card_routes[] = { + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + + /* Line Out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, + { "Line Out Ramp Controller", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Line Out Ramp Controller" }, +}; + +static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dai_link->playback_only = true; + card->dai_link->capture_only = false; + + card->dev = dev; + card->owner = THIS_MODULE; + card->name = "H616 Audio Codec"; + card->driver_name = "sun4i-codec"; + card->controls = sun50i_h616_card_controls; + card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls); + card->dapm_widgets = sun50i_h616_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_card_dapm_widgets); + card->dapm_routes = sun50i_h616_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun50i_h616_codec_card_routes); + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1560,14 +1743,24 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = { .max_register = SUN8I_H3_CODEC_ADC_DBG, }; +static const struct regmap_config sun50i_h616_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN50I_H616_DAC_AC_RAMP_REG, + .cache_type = REGCACHE_NONE, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_component_driver *codec; struct snd_soc_card * (*create_card)(struct device *dev); struct reg_field reg_adc_fifoc; /* used for regmap_field */ + struct reg_field reg_dac_fifoc; /* used for regmap_field */ unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ bool has_reset; + bool playback_only; }; static const struct sun4i_codec_quirks sun4i_codec_quirks = { @@ -1575,6 +1768,7 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = { .codec = &sun4i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; @@ -1584,6 +1778,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { .codec = &sun6i_codec_codec, .create_card = sun6i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1594,6 +1789,7 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = { .codec = &sun7i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; @@ -1603,6 +1799,7 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_a23_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1618,6 +1815,7 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_h3_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1632,11 +1830,21 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_v3s_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, }; +static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = { + .regmap_config = &sun50i_h616_codec_regmap_config, + .codec = &sun50i_h616_codec_codec, + .create_card = sun50i_h616_codec_create_card, + .reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1662,6 +1870,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun8i-v3s-codec", .data = &sun8i_v3s_codec_quirks, }, + { + .compatible = "allwinner,sun50i-h616-codec", + .data = &sun50i_h616_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); @@ -1739,6 +1951,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, + quirks->reg_dac_fifoc); + if (IS_ERR(scodec->reg_dac_fifoc)) { + ret = PTR_ERR(scodec->reg_dac_fifoc); + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", + ret); + return ret; + } + /* Enable the bus clock */ if (clk_prepare_enable(scodec->clk_apb)) { dev_err(&pdev->dev, "Failed to enable the APB clock\n"); @@ -1760,10 +1982,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) scodec->playback_dma_data.maxburst = 8; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - /* DMA configuration for RX FIFO */ - scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; - scodec->capture_dma_data.maxburst = 8; - scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + if (!quirks->playback_only) { + /* DMA configuration for RX FIFO */ + scodec->capture_dma_data.addr = res->start + + quirks->reg_adc_rxdata; + scodec->capture_dma_data.maxburst = 8; + scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + } ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, &sun4i_codec_dai, 1); @@ -1837,4 +2062,5 @@ MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>"); MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); +MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 508128b7783e..1be6c09cbe1a 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -245,6 +245,7 @@ static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream, cif_conf.audio_bits = TEGRA_ACIF_BITS_16; cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; cif_conf.client_bits = TEGRA_ACIF_BITS_24; @@ -313,6 +314,7 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -324,6 +326,7 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra186_dspk_dai_ops, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index a866aeb2719d..58fdb0e79954 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_admaif.c - Tegra ADMAIF driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -285,6 +285,11 @@ static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, cif_conf.client_bits = TEGRA_ACIF_BITS_16; valid_bit = DATA_16BIT; break; + case SNDRV_PCM_FORMAT_S24_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + cif_conf.client_bits = TEGRA_ACIF_BITS_24; + valid_bit = DATA_32BIT; + break; case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; cif_conf.client_bits = TEGRA_ACIF_BITS_32; @@ -561,6 +566,7 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -570,6 +576,7 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra_admaif_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 109f763fe211..3e6e8f51f380 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_adx.c - Tegra210 ADX driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -127,6 +127,7 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -237,6 +238,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -246,6 +248,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_adx_in_dai_ops, \ @@ -261,6 +264,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -270,6 +274,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_adx_out_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index 38a2d6ec033b..a9ef22c19e81 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_amx.c - Tegra210 AMX driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -144,6 +144,7 @@ static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -266,6 +267,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -275,6 +277,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_amx_in_dai_ops, \ @@ -290,6 +293,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -299,6 +303,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_amx_out_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index d9b577f146dc..7986be71f43d 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_dmic.c - Tegra210 DMIC driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -139,6 +139,7 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; break; @@ -325,6 +326,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -336,6 +338,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_dmic_dai_ops, diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index a3908b15dfdc..07ce2dbe6c00 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_i2s.c - Tegra210 I2S driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -629,6 +629,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; break; @@ -656,6 +657,11 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, sample_size = 16; cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: + val = I2S_BITS_24; + sample_size = 32; + cif_conf.client_bits = TEGRA_ACIF_BITS_24; + break; case SNDRV_PCM_FORMAT_S32_LE: val = I2S_BITS_32; sample_size = 32; @@ -720,6 +726,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -729,6 +736,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -741,6 +749,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -750,6 +759,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_i2s_dai_ops, diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h index fe478f3d8435..543332de7405 100644 --- a/sound/soc/tegra/tegra210_i2s.h +++ b/sound/soc/tegra/tegra210_i2s.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tegra210_i2s.h - Definitions for Tegra210 I2S driver +/* SPDX-License-Identifier: GPL-2.0-only + * SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. * - * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + * tegra210_i2s.h - Definitions for Tegra210 I2S driver * */ @@ -87,6 +87,7 @@ #define I2S_BITS_8 1 #define I2S_BITS_16 3 +#define I2S_BITS_24 5 #define I2S_BITS_32 7 #define I2S_CTRL_BIT_SIZE_MASK 0x7 diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index e07e2f1d2f70..410259d98dfb 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_mixer.c - Tegra210 MIXER driver -// -// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -248,6 +248,7 @@ static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -312,6 +313,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -321,6 +323,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_mixer_in_dai_ops, \ @@ -336,6 +339,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -345,6 +349,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_mixer_out_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index 4ead52564ab6..119f17501478 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_mvc.c - Tegra210 MVC driver -// -// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -441,6 +441,7 @@ static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -569,6 +570,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -578,6 +580,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -592,6 +595,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -601,6 +605,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_mvc_dai_ops, diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index e2bc604e8b79..c595cec9baab 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_ope.c - Tegra210 OPE driver -// -// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -47,6 +47,7 @@ static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -129,6 +130,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -138,6 +140,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -150,6 +153,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -159,6 +163,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_ope_dai_ops, diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index e16bbb44cc77..df88708c733c 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_sfc.c - Tegra210 SFC driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -3133,6 +3133,7 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -3395,6 +3396,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -3404,6 +3406,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_sfc_in_dai_ops, @@ -3417,6 +3420,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -3426,6 +3430,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_sfc_out_dai_ops, diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index 77296237575a..d9900c69e536 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -371,7 +371,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0); if (!dai_node) { - dev_err(&pdev->dev, "McBSP node is not provided\n"); + dev_err(card->dev, "McBSP node is not provided\n"); return -EINVAL; } rx51_dai[0].cpus->dai_name = NULL; @@ -381,7 +381,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 0); if (!dai_node) { - dev_err(&pdev->dev, "Codec node is not provided\n"); + dev_err(card->dev, "Codec node is not provided\n"); return -EINVAL; } rx51_dai[0].codecs->name = NULL; @@ -389,7 +389,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 1); if (!dai_node) { - dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n"); + dev_err(card->dev, "Auxiliary Codec node is not provided\n"); return -EINVAL; } rx51_aux_dev[0].dlc.name = NULL; @@ -399,7 +399,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0); if (!dai_node) { - dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); + dev_err(card->dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } rx51_aux_dev[1].dlc.name = NULL; @@ -408,7 +408,7 @@ static int rx51_soc_probe(struct platform_device *pdev) rx51_codec_conf[1].dlc.of_node = dai_node; } - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) return -ENOMEM; @@ -439,7 +439,7 @@ static int rx51_soc_probe(struct platform_device *pdev) err = devm_snd_soc_register_card(card->dev, card); if (err) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err); + dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err); return err; } diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c index 0eba60758134..d63def8615eb 100644 --- a/sound/soc/uniphier/aio-core.c +++ b/sound/soc/uniphier/aio-core.c @@ -838,6 +838,7 @@ int aio_oport_set_stream_type(struct uniphier_aio_sub *sub, { struct regmap *r = sub->aio->chip->regmap; u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN; + int ret; switch (pc) { case IEC61937_PC_AC3: @@ -880,8 +881,13 @@ int aio_oport_set_stream_type(struct uniphier_aio_sub *sub, break; } - regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet); - regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause); + ret = regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet); + if (ret) + return ret; + + ret = regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause); + if (ret) + return ret; return 0; } @@ -921,16 +927,19 @@ int aio_src_set_param(struct uniphier_aio_sub *sub, { struct regmap *r = sub->aio->chip->regmap; u32 v; + int ret; if (sub->swm->dir != PORT_DIR_OUTPUT) return 0; - regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map), + ret = regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map), OPORTMXSRC1CTR_THMODE_SRC | OPORTMXSRC1CTR_SRCPATH_CALC | OPORTMXSRC1CTR_SYNC_ASYNC | OPORTMXSRC1CTR_FSIIPSEL_INNER | OPORTMXSRC1CTR_FSISEL_ACLK); + if (ret) + return ret; switch (params_rate(params)) { default: @@ -951,12 +960,18 @@ int aio_src_set_param(struct uniphier_aio_sub *sub, break; } - regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map), + + ret = regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map), v | OPORTMXRATE_I_ACLKSRC_APLL | OPORTMXRATE_I_LRCKSTP_STOP); - regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map), + if (ret) + return ret; + + ret = regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map), OPORTMXRATE_I_LRCKSTP_MASK, OPORTMXRATE_I_LRCKSTP_START); + if (ret) + return ret; return 0; } diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index 662e45882c90..f6c6eb95262a 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -384,7 +384,7 @@ err_out_clock: return ret; } -static struct snd_soc_component_driver soc_codec_evea = { +static const struct snd_soc_component_driver soc_codec_evea = { .probe = evea_codec_probe, .suspend = evea_codec_suspend, .resume = evea_codec_resume, diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index a2dd739fdf2d..7798957c6504 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -733,7 +733,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape"); if (IS_ERR(drvdata->reg_vape)) { - ret = (int)PTR_ERR(drvdata->reg_vape); + ret = PTR_ERR(drvdata->reg_vape); dev_err(&pdev->dev, "%s: ERROR: Failed to get Vape supply (%d)!\n", __func__, ret); @@ -743,7 +743,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(drvdata->pclk)) { - ret = (int)PTR_ERR(drvdata->pclk); + ret = PTR_ERR(drvdata->pclk); dev_err(&pdev->dev, "%s: ERROR: devm_clk_get of pclk failed (%d)!\n", __func__, ret); @@ -752,7 +752,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { - ret = (int)PTR_ERR(drvdata->clk); + ret = PTR_ERR(drvdata->clk); dev_err(&pdev->dev, "%s: ERROR: devm_clk_get failed (%d)!\n", __func__, ret); diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index a1339f9ef12a..1b44119edfbc 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2107,7 +2107,7 @@ static struct platform_driver cs4231_driver = { .of_match_table = cs4231_match, }, .probe = cs4231_probe, - .remove_new = cs4231_remove, + .remove = cs4231_remove, }; module_platform_driver(cs4231_driver); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 050e98f32d36..69f1c9e37f4b 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2616,7 +2616,7 @@ static int dbri_probe(struct platform_device *op) strcpy(card->driver, "DBRI"); strcpy(card->shortname, "Sun DBRI"); rp = &op->resource[0]; - sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", + sprintf(card->longname, "%s at 0x%02lx:0x%016llx, irq %d", card->shortname, rp->flags & 0xffL, (unsigned long long)rp->start, irq); @@ -2682,7 +2682,7 @@ static struct platform_driver dbri_sbus_driver = { .of_match_table = dbri_match, }, .probe = dbri_probe, - .remove_new = dbri_remove, + .remove = dbri_remove, }; module_platform_driver(dbri_sbus_driver); diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 33e962178c93..d562a30b087f 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -61,8 +61,10 @@ static void usb6fire_chip_abort(struct sfire_chip *chip) } } -static void usb6fire_chip_destroy(struct sfire_chip *chip) +static void usb6fire_card_free(struct snd_card *card) { + struct sfire_chip *chip = card->private_data; + if (chip) { if (chip->pcm) usb6fire_pcm_destroy(chip); @@ -72,8 +74,6 @@ static void usb6fire_chip_destroy(struct sfire_chip *chip) usb6fire_comm_destroy(chip); if (chip->control) usb6fire_control_destroy(chip); - if (chip->card) - snd_card_free(chip->card); } } @@ -136,6 +136,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, chip->regidx = regidx; chip->intf_count = 1; chip->card = card; + card->private_free = usb6fire_card_free; ret = usb6fire_comm_init(chip); if (ret < 0) @@ -162,7 +163,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, return 0; destroy_chip: - usb6fire_chip_destroy(chip); + snd_card_free(card); return ret; } @@ -181,7 +182,6 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) chip->shutdown = true; usb6fire_chip_abort(chip); - usb6fire_chip_destroy(chip); } } } diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 772c0ecb7077..05f964347ed6 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -858,14 +858,20 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) return 0; } -void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev) { struct device *dev = caiaqdev_to_dev(cdev); dev_dbg(dev, "%s(%p)\n", __func__, cdev); stream_stop(cdev); +} + +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +{ + struct device *dev = caiaqdev_to_dev(cdev); + + dev_dbg(dev, "%s(%p)\n", __func__, cdev); free_urbs(cdev->data_urbs_in); free_urbs(cdev->data_urbs_out); kfree(cdev->data_cb_info); } - diff --git a/sound/usb/caiaq/audio.h b/sound/usb/caiaq/audio.h index 869bf6264d6a..07f5d064456c 100644 --- a/sound/usb/caiaq/audio.h +++ b/sound/usb/caiaq/audio.h @@ -3,6 +3,7 @@ #define CAIAQ_AUDIO_H int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev); #endif /* CAIAQ_AUDIO_H */ diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index b5cbf1f195c4..dfd820483849 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -376,6 +376,17 @@ static void setup_card(struct snd_usb_caiaqdev *cdev) dev_err(dev, "Unable to set up control system (ret=%d)\n", ret); } +static void card_free(struct snd_card *card) +{ + struct snd_usb_caiaqdev *cdev = caiaqdev(card); + +#ifdef CONFIG_SND_USB_CAIAQ_INPUT + snd_usb_caiaq_input_free(cdev); +#endif + snd_usb_caiaq_audio_free(cdev); + usb_reset_device(cdev->chip.dev); +} + static int create_card(struct usb_device *usb_dev, struct usb_interface *intf, struct snd_card **cardp) @@ -489,6 +500,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev) cdev->vendor_name, cdev->product_name, usbpath); setup_card(cdev); + card->private_free = card_free; return 0; err_kill_urb: @@ -534,15 +546,14 @@ static void snd_disconnect(struct usb_interface *intf) snd_card_disconnect(card); #ifdef CONFIG_SND_USB_CAIAQ_INPUT - snd_usb_caiaq_input_free(cdev); + snd_usb_caiaq_input_disconnect(cdev); #endif - snd_usb_caiaq_audio_free(cdev); + snd_usb_caiaq_audio_disconnect(cdev); usb_kill_urb(&cdev->ep1_in_urb); usb_kill_urb(&cdev->midi_out_urb); - snd_card_free(card); - usb_reset_device(interface_to_usbdev(intf)); + snd_card_free_when_closed(card); } diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 84f26dce7f5d..a9130891bb69 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -829,15 +829,21 @@ exit_free_idev: return ret; } -void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev) { if (!cdev || !cdev->input_dev) return; usb_kill_urb(cdev->ep4_in_urb); + input_unregister_device(cdev->input_dev); +} + +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +{ + if (!cdev || !cdev->input_dev) + return; + usb_free_urb(cdev->ep4_in_urb); cdev->ep4_in_urb = NULL; - - input_unregister_device(cdev->input_dev); cdev->input_dev = NULL; } diff --git a/sound/usb/caiaq/input.h b/sound/usb/caiaq/input.h index c42891e7be88..fbe267f85d02 100644 --- a/sound/usb/caiaq/input.h +++ b/sound/usb/caiaq/input.h @@ -4,6 +4,7 @@ void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len); int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev); #endif diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bd67027c7677..66976be06bc0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1084,6 +1084,21 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { struct snd_usb_audio *chip = cval->head.mixer->chip; + + if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_384) { + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + usb_audio_info(chip, + "set resolution quirk: cval->res = 384\n"); + cval->res = 384; + } + } else if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_16) { + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + usb_audio_info(chip, + "set resolution quirk: cval->res = 16\n"); + cval->res = 16; + } + } + switch (chip->usb_id) { case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ @@ -1168,27 +1183,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, } break; - case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ - case USB_ID(0x046d, 0x0808): - case USB_ID(0x046d, 0x0809): - case USB_ID(0x046d, 0x0819): /* Logitech Webcam C210 */ - case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ - case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ - case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ - case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ - case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */ - case USB_ID(0x046d, 0x0991): - case USB_ID(0x046d, 0x09a2): /* QuickCam Communicate Deluxe/S7500 */ - /* Most audio usb devices lie about volume resolution. - * Most Logitech webcams have res = 384. - * Probably there is some logitech magic behind this number --fishor - */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 384\n"); - cval->res = 384; - } - break; case USB_ID(0x0495, 0x3042): /* ESS Technology Asus USB DAC */ if ((strstr(kctl->id.name, "Playback Volume") != NULL) || strstr(kctl->id.name, "Capture Volume") != NULL) { @@ -1197,28 +1191,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 1; } break; - case USB_ID(0x1224, 0x2a25): /* Jieli Technology USB PHY 2.0 */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; - case USB_ID(0x1bcf, 0x2283): /* NexiGo N930AF FHD Webcam */ - case USB_ID(0x03f0, 0x654a): /* HP 320 FHD Webcam */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; - case USB_ID(0x1bcf, 0x2281): /* HD Webcam */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; } } @@ -2225,7 +2197,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state, len = get_term_name(state->chip, iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (!len) - len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); + snprintf(kctl->id.name, sizeof(kctl->id.name), "Mixer Source %d", in_ch + 1); + append_ctl_name(kctl, " Volume"); usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n", diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 6456e87e2f39..8bbf070b3676 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3498,7 +3498,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) } /* - * Pioneer DJ DJM Mixers + * Pioneer DJ / AlphaTheta DJM Mixers * * These devices generally have options for soft-switching the playback and * capture sources in addition to the recording level. Although different @@ -3515,17 +3515,23 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_CAP_CDLINE 0x01 #define SND_DJM_CAP_DIGITAL 0x02 #define SND_DJM_CAP_PHONO 0x03 +#define SND_DJM_CAP_PREFADER 0x05 #define SND_DJM_CAP_PFADER 0x06 #define SND_DJM_CAP_XFADERA 0x07 #define SND_DJM_CAP_XFADERB 0x08 #define SND_DJM_CAP_MIC 0x09 #define SND_DJM_CAP_AUX 0x0d #define SND_DJM_CAP_RECOUT 0x0a +#define SND_DJM_CAP_RECOUT_NOMIC 0x0e #define SND_DJM_CAP_NONE 0x0f #define SND_DJM_CAP_CH1PFADER 0x11 #define SND_DJM_CAP_CH2PFADER 0x12 #define SND_DJM_CAP_CH3PFADER 0x13 #define SND_DJM_CAP_CH4PFADER 0x14 +#define SND_DJM_CAP_CH1PREFADER 0x31 +#define SND_DJM_CAP_CH2PREFADER 0x32 +#define SND_DJM_CAP_CH3PREFADER 0x33 +#define SND_DJM_CAP_CH4PREFADER 0x34 // Playback types #define SND_DJM_PB_CH1 0x00 @@ -3551,6 +3557,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_900NXS2_IDX 0x3 #define SND_DJM_750MK2_IDX 0x4 #define SND_DJM_450_IDX 0x5 +#define SND_DJM_A9_IDX 0x6 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -3579,7 +3586,7 @@ struct snd_djm_ctl { u16 wIndex; }; -static const char *snd_djm_get_label_caplevel(u16 wvalue) +static const char *snd_djm_get_label_caplevel_common(u16 wvalue) { switch (wvalue) { case 0x0000: return "-19dB"; @@ -3590,6 +3597,20 @@ static const char *snd_djm_get_label_caplevel(u16 wvalue) } }; +// The DJM-A9 has different capture levels than other, older models +static const char *snd_djm_get_label_caplevel_a9(u16 wvalue) +{ + switch (wvalue) { + case 0x0000: return "+15dB"; + case 0x0100: return "+12dB"; + case 0x0200: return "+9dB"; + case 0x0300: return "+6dB"; + case 0x0400: return "+3dB"; + case 0x0500: return "0dB"; + default: return NULL; + } +}; + static const char *snd_djm_get_label_cap_common(u16 wvalue) { switch (wvalue & 0x00ff) { @@ -3602,8 +3623,13 @@ static const char *snd_djm_get_label_cap_common(u16 wvalue) case SND_DJM_CAP_XFADERB: return "Cross Fader B"; case SND_DJM_CAP_MIC: return "Mic"; case SND_DJM_CAP_RECOUT: return "Rec Out"; + case SND_DJM_CAP_RECOUT_NOMIC: return "Rec Out without Mic"; case SND_DJM_CAP_AUX: return "Aux"; case SND_DJM_CAP_NONE: return "None"; + case SND_DJM_CAP_CH1PREFADER: return "Pre Fader Ch1"; + case SND_DJM_CAP_CH2PREFADER: return "Pre Fader Ch2"; + case SND_DJM_CAP_CH3PREFADER: return "Pre Fader Ch3"; + case SND_DJM_CAP_CH4PREFADER: return "Pre Fader Ch4"; case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1"; case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; @@ -3623,6 +3649,14 @@ static const char *snd_djm_get_label_cap_850(u16 wvalue) } }; +static const char *snd_djm_get_label_caplevel(u8 device_idx, u16 wvalue) +{ + switch (device_idx) { + case SND_DJM_A9_IDX: return snd_djm_get_label_caplevel_a9(wvalue); + default: return snd_djm_get_label_caplevel_common(wvalue); + } +}; + static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) { switch (device_idx) { @@ -3644,7 +3678,7 @@ static const char *snd_djm_get_label_pb(u16 wvalue) static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) { switch (windex) { - case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); + case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(device_idx, wvalue); case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); default: return NULL; @@ -3653,7 +3687,7 @@ static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) // common DJM capture level option values static const u16 snd_djm_opts_cap_level[] = { - 0x0000, 0x0100, 0x0200, 0x0300 }; + 0x0000, 0x0100, 0x0200, 0x0300, 0x400, 0x500 }; // DJM-250MK2 @@ -3795,6 +3829,28 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { }; +// DJM-A9 +static const u16 snd_djm_opts_a9_cap1[] = { + 0x0107, 0x0108, 0x0109, 0x010a, 0x010e, + 0x111, 0x112, 0x113, 0x114, 0x0131, 0x132, 0x133, 0x134 }; +static const u16 snd_djm_opts_a9_cap2[] = { + 0x0201, 0x0202, 0x0203, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020e }; +static const u16 snd_djm_opts_a9_cap3[] = { + 0x0301, 0x0302, 0x0303, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030e }; +static const u16 snd_djm_opts_a9_cap4[] = { + 0x0401, 0x0402, 0x0403, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040e }; +static const u16 snd_djm_opts_a9_cap5[] = { + 0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e }; + +static const struct snd_djm_ctl snd_djm_ctls_a9[] = { + SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Master Input", a9_cap1, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch1 Input", a9_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch2 Input", a9_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch3 Input", a9_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch4 Input", a9_cap5, 2, SND_DJM_WINDEX_CAP) +}; + static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2), [SND_DJM_750_IDX] = SND_DJM_DEVICE(750), @@ -3802,6 +3858,7 @@ static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2), [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2), [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), + [SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9), }; @@ -4079,6 +4136,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); break; + case USB_ID(0x2b73, 0x003c): /* Pioneer DJ / AlphaTheta DJM-A9 */ + err = snd_djm_controls_create(mixer, SND_DJM_A9_IDX); + break; } return err; diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 4cddf84db631..7f595c1752a5 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -11,7 +11,7 @@ * - Clarett 2Pre/4Pre/8Pre USB * - Clarett+ 2Pre/4Pre/8Pre * - * Copyright (c) 2018-2023 by Geoffrey D. Bennett <g at b4.vu> + * Copyright (c) 2018-2024 by Geoffrey D. Bennett <g at b4.vu> * Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com> * Copyright (c) 2022 by Christian Colglazier <christian@cacolglazier.com> * @@ -1079,6 +1079,9 @@ struct scarlett2_device_info { /* minimum firmware version required */ u16 min_firmware_version; + /* has a downloadable device map */ + u8 has_devmap; + /* support for main/alt speaker switching */ u8 has_speaker_switching; @@ -1253,7 +1256,7 @@ struct scarlett2_data { u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; u8 input_select_switch; - u8 input_link_switch[SCARLETT2_INPUT_GAIN_MAX / 2]; + u8 input_link_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 gain[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_status[SCARLETT2_INPUT_GAIN_MAX]; @@ -1284,7 +1287,7 @@ struct scarlett2_data { struct snd_kcontrol *input_mute_ctls[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; struct snd_kcontrol *input_select_ctl; - struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX / 2]; + struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *input_gain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_status_ctls[SCARLETT2_INPUT_GAIN_MAX]; @@ -1773,6 +1776,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { static const struct scarlett2_device_info vocaster_one_info = { .config_set = &scarlett2_config_set_vocaster, .min_firmware_version = 1769, + .has_devmap = 1, .phantom_count = 1, .inputs_per_phantom = 1, @@ -1815,6 +1819,7 @@ static const struct scarlett2_device_info vocaster_one_info = { static const struct scarlett2_device_info vocaster_two_info = { .config_set = &scarlett2_config_set_vocaster, .min_firmware_version = 1769, + .has_devmap = 1, .phantom_count = 2, .inputs_per_phantom = 1, @@ -1858,6 +1863,7 @@ static const struct scarlett2_device_info vocaster_two_info = { static const struct scarlett2_device_info solo_gen4_info = { .config_set = &scarlett2_config_set_gen4_solo, .min_firmware_version = 2115, + .has_devmap = 1, .level_input_count = 1, .air_input_count = 1, @@ -1912,6 +1918,7 @@ static const struct scarlett2_device_info solo_gen4_info = { static const struct scarlett2_device_info s2i2_gen4_info = { .config_set = &scarlett2_config_set_gen4_2i2, .min_firmware_version = 2115, + .has_devmap = 1, .level_input_count = 2, .air_input_count = 2, @@ -1966,6 +1973,7 @@ static const struct scarlett2_device_info s2i2_gen4_info = { static const struct scarlett2_device_info s4i4_gen4_info = { .config_set = &scarlett2_config_set_gen4_4i4, .min_firmware_version = 2089, + .has_devmap = 1, .level_input_count = 2, .air_input_count = 2, @@ -2264,6 +2272,8 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_SET_DATA 0x00800001 #define SCARLETT2_USB_DATA_CMD 0x00800002 +#define SCARLETT2_USB_INFO_DEVMAP 0x0080000c +#define SCARLETT2_USB_GET_DEVMAP 0x0080000d #define SCARLETT2_USB_CONFIG_SAVE 6 @@ -2277,6 +2287,14 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_SEGMENT_SETTINGS_NAME "App_Settings" #define SCARLETT2_SEGMENT_FIRMWARE_NAME "App_Upgrade" +/* Gen 4 device firmware provides access to a base64-encoded + * zlib-compressed JSON description of the device's capabilities and + * configuration. This device map is made available in + * /proc/asound/cardX/device-map.json.zz.b64 + */ +#define SCARLETT2_DEVMAP_BLOCK_SIZE 1024 +#define SCARLETT2_DEVMAP_FILENAME "device-map.json.zz.b64" + /* proprietary request/response format */ struct scarlett2_usb_packet { __le32 cmd; @@ -3409,7 +3427,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) private->num_autogain_status_texts - 1; - for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) if (scarlett2_has_config_item(private, scarlett2_ag_target_configs[i])) { err = scarlett2_usb_get_config( @@ -3420,7 +3438,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) } /* convert from negative dBFS as used by the device */ - for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) private->ag_targets[i] = -ag_target_values[i]; return 0; @@ -3439,7 +3457,7 @@ static void scarlett2_autogain_update_access(struct usb_mixer_interface *mixer) scarlett2_set_ctl_access(private->input_select_ctl, val); if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) scarlett2_set_ctl_access(private->input_link_ctls[i], val); for (i = 0; i < info->gain_input_count; i++) @@ -3480,7 +3498,7 @@ static void scarlett2_autogain_notify_access(struct usb_mixer_interface *mixer) &private->input_select_ctl->id); if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->input_link_ctls[i]->id); for (i = 0; i < info->gain_input_count; i++) @@ -3825,7 +3843,7 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int link_count = info->gain_input_count / 2; + int link_count = info->gain_input_count; int err; private->input_select_updated = 0; @@ -3847,10 +3865,6 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) if (err < 0) return err; - /* simplified because no model yet has link_count > 1 */ - if (private->input_link_switch[0]) - private->input_select_switch = 0; - return 0; } @@ -3887,9 +3901,9 @@ static int scarlett2_input_select_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; int oval, val, err; - int max_val = private->input_link_switch[0] ? 0 : 1; mutex_lock(&private->data_mutex); @@ -3907,19 +3921,18 @@ static int scarlett2_input_select_ctl_put( if (val < 0) val = 0; - else if (val > max_val) - val = max_val; + else if (val >= info->gain_input_count) + val = info->gain_input_count - 1; if (oval == val) goto unlock; private->input_select_switch = val; - /* Send switch change to the device if inputs not linked */ - if (!private->input_link_switch[0]) - err = scarlett2_usb_set_config( - mixer, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, - 1, val); + /* Send new value to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, + 0, val); if (err == 0) err = 1; @@ -3936,8 +3949,7 @@ static int scarlett2_input_select_ctl_info( struct scarlett2_data *private = mixer->private_data; int inputs = private->info->gain_input_count; - int i, j; - int err; + int i, err; char **values = kcalloc(inputs, sizeof(char *), GFP_KERNEL); if (!values) @@ -3954,21 +3966,11 @@ static int scarlett2_input_select_ctl_info( if (err < 0) goto unlock; - /* Loop through each input - * Linked inputs have one value for the pair - */ - for (i = 0, j = 0; i < inputs; i++) { - if (private->input_link_switch[i / 2]) { - values[j++] = kasprintf( - GFP_KERNEL, "Input %d-%d", i + 1, i + 2); - i++; - } else { - values[j++] = kasprintf( - GFP_KERNEL, "Input %d", i + 1); - } - } + /* Loop through each input */ + for (i = 0; i < inputs; i++) + values[i] = kasprintf(GFP_KERNEL, "Input %d", i + 1); - err = snd_ctl_enum_info(uinfo, 1, j, + err = snd_ctl_enum_info(uinfo, 1, i, (const char * const *)values); unlock: @@ -4077,18 +4079,8 @@ static int scarlett2_input_link_ctl_put( private->input_link_switch[index] = val; - /* Notify of change in input select options available */ - snd_ctl_notify(mixer->chip->card, - SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, - &private->input_select_ctl->id); - private->input_select_updated = 1; - - /* Send switch change to the device - * Link for channels 1-2 is at index 1 - * No device yet has more than 2 channels linked - */ err = scarlett2_usb_set_config( - mixer, SCARLETT2_CONFIG_INPUT_LINK_SWITCH, index + 1, val); + mixer, SCARLETT2_CONFIG_INPUT_LINK_SWITCH, index, val); if (err == 0) err = 1; @@ -5385,6 +5377,8 @@ static int scarlett2_compressor_ctl_put( int index = elem->control; int channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; + const struct compressor_param *param = &compressor_params[param_index]; + int oval, val, err; s32 scaled_val; @@ -5406,8 +5400,6 @@ static int scarlett2_compressor_ctl_put( private->compressor_values[index] = val; - const struct compressor_param *param = &compressor_params[param_index]; - scaled_val = val << param->scale_bits; /* Send change to the device */ @@ -6916,10 +6908,9 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) { - for (i = 0; i < info->gain_input_count / 2; i++) { + for (i = 0; i < info->gain_input_count; i++) { scnprintf(s, sizeof(s), - "Line In %d-%d Link Capture Switch", - (i * 2) + 1, (i * 2) + 2); + "Line In %d Link Capture Switch", i + 1); err = scarlett2_add_new_ctl( mixer, &scarlett2_input_link_ctl, i, 1, s, &private->input_link_ctls[i]); @@ -8246,7 +8237,7 @@ static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer) SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &private->input_select_ctl->id); - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->input_link_ctls[i]->id); } @@ -9518,7 +9509,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, SCARLETT2_FLASH_BLOCK_SIZE; if (count < 0 || *offset < 0 || *offset + count >= flash_size) - return -EINVAL; + return -ENOSPC; if (!count) return 0; @@ -9591,6 +9582,116 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) return 0; } +/*** device-map file ***/ + +static ssize_t scarlett2_devmap_read( + struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, + size_t count, + loff_t pos) +{ + struct usb_mixer_interface *mixer = entry->private_data; + u8 *resp_buf; + const size_t block_size = SCARLETT2_DEVMAP_BLOCK_SIZE; + size_t copied = 0; + + if (pos >= entry->size) + return 0; + + if (pos + count > entry->size) + count = entry->size - pos; + + resp_buf = kmalloc(block_size, GFP_KERNEL); + if (!resp_buf) + return -ENOMEM; + + while (count > 0) { + /* SCARLETT2_USB_GET_DEVMAP reads only on block boundaries, + * so we need to read a whole block and copy the requested + * chunk to userspace. + */ + + __le32 req; + int err; + + /* offset within the block that we're reading */ + size_t offset = pos % block_size; + + /* read_size is block_size except for the last block */ + size_t block_start = pos - offset; + size_t read_size = min_t(size_t, + block_size, + entry->size - block_start); + + /* size of the chunk to copy to userspace */ + size_t copy_size = min_t(size_t, count, read_size - offset); + + /* request the block */ + req = cpu_to_le32(pos / block_size); + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_DEVMAP, + &req, sizeof(req), resp_buf, read_size); + if (err < 0) { + kfree(resp_buf); + return copied ? copied : err; + } + + if (copy_to_user(buf, resp_buf + offset, copy_size)) { + kfree(resp_buf); + return -EFAULT; + } + + buf += copy_size; + pos += copy_size; + copied += copy_size; + count -= copy_size; + } + + kfree(resp_buf); + return copied; +} + +static const struct snd_info_entry_ops scarlett2_devmap_ops = { + .read = scarlett2_devmap_read, +}; + +static int scarlett2_devmap_init(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + __le16 config_len_buf[2]; + int config_len; + struct snd_info_entry *entry; + int err; + + /* If the device doesn't support the DEVMAP commands, don't + * create the /proc/asound/cardX/scarlett.json.zlib entry + */ + if (!info->has_devmap) + return 0; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_DEVMAP, + NULL, 0, &config_len_buf, sizeof(config_len_buf)); + if (err < 0) + return err; + + config_len = le16_to_cpu(config_len_buf[1]); + + err = snd_card_proc_new(card, SCARLETT2_DEVMAP_FILENAME, &entry); + if (err < 0) + return err; + + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->private_data = mixer; + entry->c.ops = &scarlett2_devmap_ops; + entry->size = config_len; + entry->mode = S_IFREG | 0444; + + return 0; +} + int snd_scarlett2_init(struct usb_mixer_interface *mixer) { struct snd_usb_audio *chip = mixer->chip; @@ -9641,11 +9742,20 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer) } err = scarlett2_hwdep_init(mixer); - if (err < 0) + if (err < 0) { usb_audio_err(mixer->chip, "Error creating %s hwdep device: %d", entry->series_name, err); + return err; + } + + err = scarlett2_devmap_init(mixer); + if (err < 0) + usb_audio_err(mixer->chip, + "Error creating %s devmap entry: %d", + entry->series_name, + err); return err; } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 199d0603cf8e..c49383e64678 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3131,6 +3131,63 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* + * Pioneer DJ / AlphaTheta DJM-A9 + * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x003c), + QUIRK_DRIVER_INFO { + QUIRK_DATA_COMPOSITE { + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { + 44100, 48000, 96000 + } + } + }, + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_idx = 1, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { + 44100, 48000, 96000 + } + } + }, + QUIRK_COMPOSITE_END + } + } +}, + /* * MacroSilicon MS2100/MS2106 based AV capture cards * diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index c5fd180357d1..cbfbb064a9c2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2115,7 +2115,7 @@ struct usb_audio_quirk_flags_table { static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { /* Device matches */ DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */ @@ -2123,10 +2123,31 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x045e, 0x083c, /* MS USB Link headset */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_DISABLE_AUTOSUSPEND), + DEVICE_FLG(0x046d, 0x0807, /* Logitech Webcam C500 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0808, /* Logitech Webcam C600 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0809, + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0819, /* Logitech Webcam C210 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x081b, /* HD Webcam c310 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x081d, /* HD Webcam c510 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0825, /* HD Webcam c270 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0826, /* HD Webcam c525 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x046d, 0x08ca, /* Logitech Quickcam Fusion */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x0991, /* Logitech QuickCam Pro */ - QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR), + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR | + QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x09a2, /* QuickCam Communicate Deluxe/S7500 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */ @@ -2194,7 +2215,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */ @@ -2232,9 +2253,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1bcf, 0x2281, /* HD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b0f042c99608..158ec053dc44 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -194,6 +194,8 @@ extern bool snd_usb_skip_validation; * QUIRK_FLAG_FIXED_RATE * Do not set PCM rate (frequency) when only one rate is available * for the given endpoint. + * QUIRK_FLAG_MIC_RES_16 and QUIRK_FLAG_MIC_RES_384 + * Set the fixed resolution for Mic Capture Volume (mostly for webcams) */ #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) @@ -218,5 +220,7 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_IFACE_SKIP_CLOSE (1U << 19) #define QUIRK_FLAG_FORCE_IFACE_RESET (1U << 20) #define QUIRK_FLAG_FIXED_RATE (1U << 21) +#define QUIRK_FLAG_MIC_RES_16 (1U << 22) +#define QUIRK_FLAG_MIC_RES_384 (1U << 23) #endif /* __USBAUDIO_H */ diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 1be0e980feb9..6bcf8b859ebb 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -89,13 +89,6 @@ static void pt_info_set(struct usb_device *dev, u8 v) v, 0, NULL, 0, 1000, GFP_NOIO); } -static void usb_stream_hwdep_vm_open(struct vm_area_struct *area) -{ - struct us122l *us122l = area->vm_private_data; - - atomic_inc(&us122l->mmap_count); -} - static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) { unsigned long offset; @@ -132,17 +125,9 @@ unlock: return VM_FAULT_SIGBUS; } -static void usb_stream_hwdep_vm_close(struct vm_area_struct *area) -{ - struct us122l *us122l = area->vm_private_data; - - atomic_dec(&us122l->mmap_count); -} static const struct vm_operations_struct usb_stream_hwdep_vm_ops = { - .open = usb_stream_hwdep_vm_open, .fault = usb_stream_hwdep_vm_fault, - .close = usb_stream_hwdep_vm_close, }; static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) @@ -218,7 +203,6 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw, if (!read) vm_flags_set(area, VM_DONTEXPAND); area->vm_private_data = us122l; - atomic_inc(&us122l->mmap_count); out: mutex_unlock(&us122l->mutex); return err; @@ -606,10 +590,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); usb_put_dev(us122l->dev); - while (atomic_read(&us122l->mmap_count)) - msleep(500); - - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index c32ae5e981e9..8e59b78d3514 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -16,8 +16,6 @@ struct us122l { struct file *slave; struct list_head midi_list; - atomic_t mmap_count; - bool is_us144; }; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 2f9cede242b3..5f81c68fd42b 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -422,7 +422,7 @@ static void snd_usx2y_disconnect(struct usb_interface *intf) } if (usx2y->us428ctls_sharedmem) wake_up(&usx2y->us428ctls_wait_queue_head); - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_usx2y_probe(struct usb_interface *intf, |