diff options
524 files changed, 16273 insertions, 4997 deletions
diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index f2bcc5a7ea43..ae92a2571388 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -162,8 +162,10 @@ Base 2 log and power Functions .. kernel-doc:: include/linux/log2.h :internal: -Integer power Functions ------------------------ +Integer log and power Functions +------------------------------- + +.. kernel-doc:: include/linux/int_log.h .. kernel-doc:: lib/math/int_pow.c :export: diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml index bf1234550343..5db718e4d0e7 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml @@ -9,6 +9,9 @@ title: Amlogic AXG sound card maintainers: - Jerome Brunet <jbrunet@baylibre.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: amlogic,axg-sound-card @@ -17,23 +20,12 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array description: list of auxiliary devices - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - patternProperties: "^dai-link-[0-9]+$": type: object @@ -108,7 +100,6 @@ patternProperties: - sound-dai required: - - model - dai-link-0 unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index b358fd601ed3..d4277d342e69 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -9,6 +9,9 @@ title: Amlogic GX sound card maintainers: - Jerome Brunet <jbrunet@baylibre.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: items: @@ -18,14 +21,6 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array description: list of auxiliary devices - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - minItems: 2 - description: |- - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array minItems: 2 @@ -33,10 +28,6 @@ properties: A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - patternProperties: "^dai-link-[0-9]+$": type: object @@ -86,7 +77,7 @@ required: - model - dai-link-0 -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml new file mode 100644 index 000000000000..d3cc1ea4a175 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/audio-iio-aux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Audio IIO auxiliary + +maintainers: + - Herve Codina <herve.codina@bootlin.com> + +description: + Auxiliary device based on Industrial I/O device channels + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: audio-iio-aux + + io-channels: + description: + Industrial I/O device channels used + + io-channel-names: + description: + Industrial I/O channel names related to io-channels. + These names are used to provides sound controls, widgets and routes names. + + snd-control-invert-range: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + A list of 0/1 flags defining whether or not the related channel is + inverted + items: + enum: [0, 1] + default: 0 + description: | + Invert the sound control value compared to the IIO channel raw value. + - 1: The related sound control value is inverted meaning that the + minimum sound control value correspond to the maximum IIO channel + raw value and the maximum sound control value correspond to the + minimum IIO channel raw value. + - 0: The related sound control value is not inverted meaning that the + minimum (resp maximum) sound control value correspond to the + minimum (resp maximum) IIO channel raw value. + +required: + - compatible + - io-channels + - io-channel-names + +unevaluatedProperties: false + +examples: + - | + iio-aux { + compatible = "audio-iio-aux"; + io-channels = <&iio 0>, <&iio 1>, <&iio 2>, <&iio 3>; + io-channel-names = "CH0", "CH1", "CH2", "CH3"; + /* Invert CH1 and CH2 */ + snd-control-invert-range = <0 1 1 0>; + }; diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml index 35eef7d818a2..4051c2538caf 100644 --- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml +++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml @@ -19,7 +19,9 @@ allOf: properties: compatible: - const: awinic,aw88395 + enum: + - awinic,aw88395 + - awinic,aw88261 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml index e847611a85f7..188f38baddec 100644 --- a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -17,6 +17,9 @@ description: | such as SAI, MICFIL, .etc through building rpmsg channels between Cortex-A and Cortex-M. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: @@ -25,10 +28,7 @@ properties: - fsl,imx8mm-rpmsg-audio - fsl,imx8mp-rpmsg-audio - fsl,imx8ulp-rpmsg-audio - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name + - fsl,imx93-rpmsg-audio clocks: items: @@ -65,13 +65,6 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle to a node of audio codec - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: | - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - fsl,enable-lpa: $ref: /schemas/types.yaml#/definitions/flag description: enable low power audio path. @@ -100,9 +93,8 @@ properties: required: - compatible - - model -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml index ba5b7728cf33..bac940553965 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml @@ -13,23 +13,15 @@ maintainers: description: This binding describes the SC7180 sound card which uses LPASS for audio. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - google,sc7180-trogdor - google,sc7180-coachz - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - "#address-cells": const: 1 @@ -86,11 +78,10 @@ patternProperties: required: - compatible - - model - "#address-cells" - "#size-cells" -additionalProperties: false +unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml index 0b1a01a4c14e..ec4b6e547ca6 100644 --- a/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml +++ b/Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml @@ -13,22 +13,14 @@ maintainers: description: This binding describes the SC7280 sound card which uses LPASS for audio. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - google,sc7280-herobrine - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. - - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - "#address-cells": const: 1 @@ -97,11 +89,10 @@ patternProperties: required: - compatible - - model - "#address-cells" - "#size-cells" -additionalProperties: false +unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt deleted file mode 100644 index efa32a486c4a..000000000000 --- a/Documentation/devicetree/bindings/sound/gtm601.txt +++ /dev/null @@ -1,19 +0,0 @@ -GTM601 UMTS modem audio interface CODEC - -This device has no configuration interface. The sample rate and channels are -based on the compatible string - "option,gtm601" = 8kHz mono - "broadmobi,bm818" = 48KHz stereo - -Required properties: - - - compatible : one of - "option,gtm601" - "broadmobi,bm818" - - -Example: - -codec: gtm601_codec { - compatible = "option,gtm601"; -}; diff --git a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml index b6f5d486600e..f7ad5ea2491e 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/imx-audio-card.yaml @@ -9,23 +9,14 @@ title: NXP i.MX audio sound card. maintainers: - Shengjiu Wang <shengjiu.wang@nxp.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - fsl,imx-audio-card - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - description: - A list of the connections between audio components. Each entry is a - pair of strings, the first being the connection's sink, the second - being the connection's source. Valid names could be power supplies, - MicBias of codec and the jacks on the board. - patternProperties: ".*-dai-link$": description: @@ -84,9 +75,8 @@ patternProperties: required: - compatible - - model -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt deleted file mode 100644 index 98cb9ba5b328..000000000000 --- a/Documentation/devicetree/bindings/sound/max9892x.txt +++ /dev/null @@ -1,44 +0,0 @@ -Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier - -This device supports I2C. - -Required properties: - - - compatible : should be one of the following - - "maxim,max98925" - - "maxim,max98926" - - "maxim,max98927" - - - vmon-slot-no : slot number used to send voltage information - or in inteleave mode this will be used as - interleave slot. - MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 - MAX98927 slot range : 0 ~ 15, Default : 0 - - - imon-slot-no : slot number used to send current information - MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 - MAX98927 slot range : 0 ~ 15, Default : 0 - - - interleave-mode : When using two MAX9892X in a system it is - possible to create ADC data that that will - overflow the frame size. Digital Audio Interleave - mode provides a means to output VMON and IMON data - from two devices on a single DOUT line when running - smaller frames sizes such as 32 BCLKS per LRCLK or - 48 BCLKS per LRCLK. - Range : 0 (off), 1 (on), Default : 0 - - - reg : the I2C address of the device for I2C - -Optional properties: - - reset-gpios : GPIO to reset the device - -Example: - -codec: max98927@3a { - compatible = "maxim,max98927"; - vmon-slot-no = <0>; - imon-slot-no = <1>; - interleave-mode = <0>; - reg = <0x3a>; -}; diff --git a/Documentation/devicetree/bindings/sound/maxim,max98925.yaml b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml new file mode 100644 index 000000000000..32fd86204a7a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/maxim,max98925.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX98925/MAX98926/MAX98927 speaker amplifier + +maintainers: + - Ryan Lee <ryans.lee@maximintegrated.com> + +properties: + compatible: + enum: + - maxim,max98925 + - maxim,max98926 + - maxim,max98927 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + vmon-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 30 + default: 0 + description: + Slot number used to send voltage information or in inteleave mode this + will be used as interleave slot. + + imon-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 30 + default: 0 + description: + Slot number used to send current information. + + maxim,interleave-mode: + type: boolean + description: + When using two MAX9892X in a system it is possible to create ADC data + that will overflow the frame size. When enabled, the Digital Audio + Interleave mode provides a means to output VMON and IMON data from two + devices on a single DOUT line when running smaller frames sizes such as + 32 BCLKS per LRCLK or 48 BCLKS per LRCLK. + +required: + - compatible + - reg + +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - maxim,max98927 + then: + properties: + vmon-slot-no: + minimum: 0 + maximum: 15 + + imon-slot-no: + minimum: 0 + maximum: 15 + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + #include <dt-bindings/gpio/gpio.h> + audio-codec@3a { + compatible = "maxim,max98927"; + reg = <0x3a>; + #sound-dai-cells = <0>; + + pinctrl-0 = <&speaker_default>; + pinctrl-names = "default"; + + reset-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + + vmon-slot-no = <1>; + imon-slot-no = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml new file mode 100644 index 000000000000..398efdfe00f5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt7986-afe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek AFE PCM controller for MT7986 + +maintainers: + - Maso Huang <maso.huang@mediatek.com> + +properties: + compatible: + oneOf: + - const: mediatek,mt7986-afe + - items: + - enum: + - mediatek,mt7981-afe + - mediatek,mt7988-afe + - const: mediatek,mt7986-afe + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 5 + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + - description: audio i2s/pcm mck + + clock-names: + minItems: 5 + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + - const: i2s_m + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt7986-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + + - if: + properties: + compatible: + contains: + const: mediatek,mt7981-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + + - if: + properties: + compatible: + contains: + const: mediatek,mt7988-afe + then: + properties: + clocks: + items: + - description: audio bus clock + - description: audio 26M clock + - description: audio intbus clock + - description: audio hopping clock + - description: audio pll clock + - description: mux for pcm_mck + - description: audio i2s/pcm mck + clock-names: + items: + - const: bus_ck + - const: 26m_ck + - const: l_ck + - const: aud_ck + - const: eg2_ck + - const: sel + - const: i2s_m + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/clock/mt7986-clk.h> + + afe@11210000 { + compatible = "mediatek,mt7986-afe"; + reg = <0x11210000 0x9000>; + interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&infracfg_ao CLK_INFRA_AUD_BUS_CK>, + <&infracfg_ao CLK_INFRA_AUD_26M_CK>, + <&infracfg_ao CLK_INFRA_AUD_L_CK>, + <&infracfg_ao CLK_INFRA_AUD_AUD_CK>, + <&infracfg_ao CLK_INFRA_AUD_EG2_CK>; + clock-names = "bus_ck", + "26m_ck", + "l_ck", + "aud_ck", + "eg2_ck"; + assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>, + <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL2_D4>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml new file mode 100644 index 000000000000..09247ceea3f7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt7986-wm8960.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7986 sound card with WM8960 codec + +maintainers: + - Maso Huang <maso.huang@mediatek.com> + +allOf: + - $ref: sound-card-common.yaml# + +properties: + compatible: + const: mediatek,mt7986-wm8960-sound + + platform: + type: object + additionalProperties: false + properties: + sound-dai: + description: The phandle of MT7986 platform. + maxItems: 1 + required: + - sound-dai + + codec: + type: object + additionalProperties: false + properties: + sound-dai: + description: The phandle of wm8960 codec. + maxItems: 1 + required: + - sound-dai + +unevaluatedProperties: false + +required: + - compatible + - audio-routing + - platform + - codec + +examples: + - | + sound { + compatible = "mediatek,mt7986-wm8960-sound"; + model = "mt7986-wm8960"; + audio-routing = + "Headphone", "HP_L", + "Headphone", "HP_R", + "LINPUT1", "AMIC", + "RINPUT1", "AMIC"; + + platform { + sound-dai = <&afe>; + }; + + codec { + sound-dai = <&wm8960>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml index e6cb711ece77..0b92c71d8779 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml @@ -25,6 +25,12 @@ properties: reset-names: const: audiosys + memory-region: + maxItems: 1 + description: | + Shared memory region for AFE memif. A "shared-dma-pool". + See ../reserved-memory/reserved-memory.yaml for details. + mediatek,topckgen: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the mediatek topckgen controller @@ -176,6 +182,7 @@ examples: interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>; resets = <&watchdog 14>; reset-names = "audiosys"; + memory-region = <&snd_dma_mem_reserved>; mediatek,topckgen = <&topckgen>; mediatek,infracfg = <&infracfg_ao>; power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml index 05e532b5d50a..43b3b67bdf3b 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml @@ -9,23 +9,19 @@ title: MediaTek MT8188 ASoC sound card maintainers: - Trevor Wu <trevor.wu@mediatek.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: - mediatek,mt8188-mt6359-evb - mediatek,mt8188-nau8825 - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - audio-routing: - $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: - A list of the connections between audio components. Each entry is a - sink/source pair of strings. Valid names could be the input or output - widgets of audio components, power supplies, MicBias of codec and the - software switch. + Valid names could be the input or output widgets of audio components, + power supplies, MicBias of codec and the software switch. mediatek,platform: $ref: /schemas/types.yaml#/definitions/phandle @@ -86,7 +82,7 @@ patternProperties: required: - link-name -additionalProperties: false +unevaluatedProperties: false required: - compatible @@ -96,6 +92,7 @@ examples: - | sound { compatible = "mediatek,mt8188-mt6359-evb"; + model = "MT6359-EVB"; mediatek,platform = <&afe>; pinctrl-names = "default"; pinctrl-0 = <&aud_pins_default>; diff --git a/Documentation/devicetree/bindings/sound/nau8821.txt b/Documentation/devicetree/bindings/sound/nau8821.txt deleted file mode 100644 index 7c84e7c7327a..000000000000 --- a/Documentation/devicetree/bindings/sound/nau8821.txt +++ /dev/null @@ -1,55 +0,0 @@ -Nuvoton NAU88L21 audio codec - -This device supports I2C only. - -Required properties: - - compatible : Must be "nuvoton,nau8821" - - - reg : the I2C address of the device. This is either 0x1B (CSB=0) or 0x54 (CSB=1). - -Optional properties: - - nuvoton,jkdet-enable: Enable jack detection via JKDET pin. - - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled, - otherwise pin in high impedance state. - - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down. - - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. - - - nuvoton,vref-impedance: VREF Impedance selection - 0 - Open - 1 - 25 kOhm - 2 - 125 kOhm - 3 - 2.5 kOhm - - - nuvoton,micbias-voltage: Micbias voltage level. - 0 - VDDA - 1 - VDDA - 2 - VDDA * 1.1 - 3 - VDDA * 1.2 - 4 - VDDA * 1.3 - 5 - VDDA * 1.4 - 6 - VDDA * 1.53 - 7 - VDDA * 1.53 - - - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - - nuvoton,dmic-clk-threshold: the ADC threshold of DMIC clock. - - nuvoton,key_enable: Headset button detection switch. - -Example: - - headset: nau8821@1b { - compatible = "nuvoton,nau8821"; - reg = <0x1b>; - interrupt-parent = <&gpio>; - interrupts = <23 IRQ_TYPE_LEVEL_LOW>; - nuvoton,jkdet-enable; - nuvoton,jkdet-pull-enable; - nuvoton,jkdet-pull-up; - nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>; - nuvoton,vref-impedance = <2>; - nuvoton,micbias-voltage = <6>; - nuvoton,jack-insert-debounce = <7>; - nuvoton,jack-eject-debounce = <7>; - nuvoton,dmic-clk-threshold = 3072000; - }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml new file mode 100644 index 000000000000..fc2f4ce4db88 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nuvoton,nau8821.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NAU88L21 audio codec + +maintainers: + - Seven Lee <wtli@nuvoton.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: nuvoton,nau8821 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + nuvoton,jkdet-enable: + description: Enable jack detection via JKDET pin. + type: boolean + + nuvoton,jkdet-pull-enable: + description: Enable JKDET pin pull. If set - pin pull enabled, + otherwise pin in high impedance state. + type: boolean + + nuvoton,jkdet-pull-up: + description: Pull-up JKDET pin. If set then JKDET pin is pull up, + otherwise pull down. + type: boolean + + nuvoton,key-enable: + description: handles key press detection. + type: boolean + + nuvoton,jkdet-polarity: + description: JKDET pin polarity. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # active high + - 1 # active low + default: 1 + + nuvoton,micbias-voltage: + description: MICBIAS output level select. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # VDDA + - 1 # VDDA * 1 + - 2 # VDDA * 1.1 + - 3 # VDDA * 1.2 + - 4 # VDDA * 1.3 + - 5 # VDDA * 1.4 + - 6 # VDDA * 1.53 + - 7 # VDDA * 1.53 + default: 6 + + nuvoton,vref-impedance: + description: VMID Tie-off impedance select. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # open + - 1 # 25KOhms + - 2 # 125KOhms + - 3 # 2.5KOhms + default: 2 + + nuvoton,jack-insert-debounce: + description: number from 0 to 7 that sets debounce time to 2^(n+2)ms. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 7 + + nuvoton,jack-eject-debounce: + description: number from 0 to 7 that sets debounce time to 2^(n+2)ms. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 0 + + nuvoton,dmic-clk-threshold: + description: DMIC clock speed expected value. Unit is Hz. + $ref: /schemas/types.yaml#/definitions/uint32 + default: 3072000 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1b { + compatible = "nuvoton,nau8821"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + nuvoton,jkdet-enable; + nuvoton,jkdet-pull-enable; + nuvoton,jkdet-pull-up; + nuvoton,key-enable; + nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>; + nuvoton,micbias-voltage = <6>; + nuvoton,vref-impedance = <2>; + nuvoton,jack-insert-debounce = <7>; + nuvoton,jack-eject-debounce = <0>; + nuvoton,dmic-clk-threshold = <3072000>; + #sound-dai-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml index 65105402a53d..cb8182bbc491 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml @@ -21,6 +21,15 @@ properties: reg: maxItems: 1 + "#sound-dai-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + nuvoton,spk-btl: description: If set, configure the two loudspeaker outputs as a Bridge Tied Load output @@ -31,6 +40,9 @@ required: - compatible - reg +allOf: + - $ref: dai-common.yaml# + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/option,gtm601.yaml b/Documentation/devicetree/bindings/sound/option,gtm601.yaml new file mode 100644 index 000000000000..ff813d97fc59 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/option,gtm601.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/option,gtm601.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GTM601 UMTS modem audio interface CODEC + +maintainers: + - kernel@puri.sm + +description: > + This device has no configuration interface. The sample rate and channels are + based on the compatible string + +properties: + compatible: + oneOf: + - description: Broadmobi BM818 (48Khz stereo) + items: + - const: broadmobi,bm818 + - const: option,gtm601 + - description: GTM601 (8kHz mono) + const: option,gtm601 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + +allOf: + - $ref: dai-common.yaml# + +additionalProperties: false + +examples: + - | + codec { + compatible = "option,gtm601"; + #sound-dai-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt deleted file mode 100644 index e7d17dda55db..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt +++ /dev/null @@ -1,101 +0,0 @@ -msm8916 analog audio CODEC - -Bindings for codec Analog IP which is integrated in pmic pm8916, - -## Bindings for codec core on pmic: - -Required properties - - compatible = "qcom,pm8916-wcd-analog-codec"; - - reg: represents the slave base address provided to the peripheral. - - interrupts: List of interrupts in given SPMI peripheral. - - interrupt-names: Names specified to above list of interrupts in same - order. List of supported interrupt names are: - "cdc_spk_cnp_int" - Speaker click and pop interrupt. - "cdc_spk_clip_int" - Speaker clip interrupt. - "cdc_spk_ocp_int" - Speaker over current protect interrupt. - "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1. - "mbhc_but_rel_det" - button release interrupt. - "mbhc_but_press_det" - button press event - "mbhc_ins_rem_det" - jack insert removal detect interrupt. - "mbhc_switch_int" - multi button headset interrupt. - "cdc_ear_ocp_int" - Earphone over current protect interrupt. - "cdc_hphr_ocp_int" - Headphone R over current protect interrupt. - "cdc_hphl_ocp_det" - Headphone L over current protect interrupt. - "cdc_ear_cnp_int" - earphone cnp interrupt. - "cdc_hphr_cnp_int" - hphr click and pop interrupt. - "cdc_hphl_cnp_int" - hphl click and pop interrupt. - - - clocks: Handle to mclk. - - clock-names: should be "mclk" - - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. - - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. - - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. - -Optional Properties: - - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons - detection on headset when the mbhc is powered up - by internal current source, this is a low power. - - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons - detection on headset when mbhc is powered up - from micbias. -- qcom,micbias-lvl: Voltage (mV) for Mic Bias -- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a - NO (Normally Open). If not specified, then - its assumed that hphl pin on jack is NC - (Normally Closed). -- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is - NO (Normally Open). If not specified, then - its assumed that gnd pin on jack is NC - (Normally Closed). -- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor - connected. -- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor - connected. - -Example: - -spmi_bus { - ... - audio-codec@f000{ - compatible = "qcom,pm8916-wcd-analog-codec"; - reg = <0xf000 0x200>; - reg-names = "pmic-codec-core"; - clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; - clock-names = "mclk"; - qcom,mbhc-vthreshold-low = <75 150 237 450 500>; - qcom,mbhc-vthreshold-high = <75 150 237 450 500>; - interrupt-parent = <&spmi_bus>; - interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, - <0x1 0xf0 0x1 IRQ_TYPE_NONE>, - <0x1 0xf0 0x2 IRQ_TYPE_NONE>, - <0x1 0xf0 0x3 IRQ_TYPE_NONE>, - <0x1 0xf0 0x4 IRQ_TYPE_NONE>, - <0x1 0xf0 0x5 IRQ_TYPE_NONE>, - <0x1 0xf0 0x6 IRQ_TYPE_NONE>, - <0x1 0xf0 0x7 IRQ_TYPE_NONE>, - <0x1 0xf1 0x0 IRQ_TYPE_NONE>, - <0x1 0xf1 0x1 IRQ_TYPE_NONE>, - <0x1 0xf1 0x2 IRQ_TYPE_NONE>, - <0x1 0xf1 0x3 IRQ_TYPE_NONE>, - <0x1 0xf1 0x4 IRQ_TYPE_NONE>, - <0x1 0xf1 0x5 IRQ_TYPE_NONE>; - interrupt-names = "cdc_spk_cnp_int", - "cdc_spk_clip_int", - "cdc_spk_ocp_int", - "mbhc_ins_rem_det1", - "mbhc_but_rel_det", - "mbhc_but_press_det", - "mbhc_ins_rem_det", - "mbhc_switch_int", - "cdc_ear_ocp_int", - "cdc_hphr_ocp_int", - "cdc_hphl_ocp_det", - "cdc_ear_cnp_int", - "cdc_hphr_cnp_int", - "cdc_hphl_cnp_int"; - vdd-cdc-io-supply = <&pm8916_l5>; - vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; - vdd-micbias-supply = <&pm8916_l13>; - #sound-dai-cells = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml new file mode 100644 index 000000000000..94e7a1860977 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -0,0 +1,153 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,pm8916-wcd-analog-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8916 WCD Analog Audio Codec + +maintainers: + - Konrad Dybcio <konradybcio@kernel.org> + +description: + The analog WCD audio codec found on Qualcomm PM8916 PMIC. + +properties: + compatible: + const: qcom,pm8916-wcd-analog-codec + + reg: + maxItems: 1 + + interrupts: + maxItems: 14 + + interrupt-names: + items: + - const: cdc_spk_cnp_int + - const: cdc_spk_clip_int + - const: cdc_spk_ocp_int + - const: mbhc_ins_rem_det1 + - const: mbhc_but_rel_det + - const: mbhc_but_press_det + - const: mbhc_ins_rem_det + - const: mbhc_switch_int + - const: cdc_ear_ocp_int + - const: cdc_hphr_ocp_int + - const: cdc_hphl_ocp_det + - const: cdc_ear_cnp_int + - const: cdc_hphr_cnp_int + - const: cdc_hphl_cnp_int + + vdd-cdc-io-supply: + description: 1.8V buck supply + + vdd-cdc-tx-rx-cx-supply: + description: 1.8V SIDO buck supply + + vdd-micbias-supply: + description: micbias supply + + qcom,mbhc-vthreshold-low: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Array of 5 threshold voltages in mV for 5-button detection on + headset when MBHC is powered by an internal current source. + minItems: 5 + maxItems: 5 + + qcom,mbhc-vthreshold-high: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + Array of 5 threshold voltages in mV for 5-button detection on + headset when MBHC is powered from micbias. + minItems: 5 + maxItems: 5 + + qcom,micbias-lvl: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Voltage (mV) for Mic Bias + + qcom,hphl-jack-type-normally-open: + type: boolean + description: + True if the HPHL pin on the jack is NO (Normally Open), false if it's + NC (Normally Closed). + + qcom,gnd-jack-type-normally-open: + type: boolean + description: + True if the GND pin on the jack is NO (Normally Open), false if it's + NC (Normally Closed). + + qcom,micbias1-ext-cap: + type: boolean + description: + True if micbias1 has an external capacitor. + + qcom,micbias2-ext-cap: + type: boolean + description: + True if micbias2 has an external capacitor. + + "#sound-dai-cells": + const: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/spmi/spmi.h> + + pmic@1 { + compatible = "qcom,pm8916", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + audio-codec@f000 { + compatible = "qcom,pm8916-wcd-analog-codec"; + reg = <0xf000>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, + <0x1 0xf0 0x1 IRQ_TYPE_NONE>, + <0x1 0xf0 0x2 IRQ_TYPE_NONE>, + <0x1 0xf0 0x3 IRQ_TYPE_NONE>, + <0x1 0xf0 0x4 IRQ_TYPE_NONE>, + <0x1 0xf0 0x5 IRQ_TYPE_NONE>, + <0x1 0xf0 0x6 IRQ_TYPE_NONE>, + <0x1 0xf0 0x7 IRQ_TYPE_NONE>, + <0x1 0xf1 0x0 IRQ_TYPE_NONE>, + <0x1 0xf1 0x1 IRQ_TYPE_NONE>, + <0x1 0xf1 0x2 IRQ_TYPE_NONE>, + <0x1 0xf1 0x3 IRQ_TYPE_NONE>, + <0x1 0xf1 0x4 IRQ_TYPE_NONE>, + <0x1 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "cdc_spk_cnp_int", + "cdc_spk_clip_int", + "cdc_spk_ocp_int", + "mbhc_ins_rem_det1", + "mbhc_but_rel_det", + "mbhc_but_press_det", + "mbhc_ins_rem_det", + "mbhc_switch_int", + "cdc_ear_ocp_int", + "cdc_hphr_ocp_int", + "cdc_hphl_ocp_det", + "cdc_ear_cnp_int", + "cdc_hphr_cnp_int", + "cdc_hphl_cnp_int"; + vdd-cdc-io-supply = <&pm8916_l5>; + vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; + vdd-micbias-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 8a821dec9526..13a5a0a10fe6 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -9,6 +9,20 @@ title: Renesas R-Car Sound Driver maintainers: - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +definitions: + port-def: + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + "^endpoint(@[0-9a-f]+)?": + $ref: audio-graph-port.yaml#/definitions/endpoint-base + properties: + playback: + $ref: /schemas/types.yaml#/definitions/phandle-array + capture: + $ref: /schemas/types.yaml#/definitions/phandle-array + unevaluatedProperties: false + properties: compatible: @@ -77,6 +91,12 @@ properties: it must be 1 if your system has audio_clkout0/1/2/3 enum: [0, 1] + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + clock-frequency: description: for audio_clkout0/1/2/3 @@ -103,35 +123,9 @@ properties: description: List of necessary clock names. # details are defined below - ports: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - '^port(@[0-9a-f]+)?$': - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false - + # ports is below port: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false + $ref: "#/definitions/port-def" rcar_sound,dvc: description: DVC subnode. @@ -248,8 +242,9 @@ properties: - interrupts additionalProperties: false +patternProperties: # For DAI base - rcar_sound,dai: + 'rcar_sound,dai(@[0-9a-f]+)?$': description: DAI subnode. type: object patternProperties: @@ -269,6 +264,13 @@ properties: - capture additionalProperties: false + 'ports(@[0-9a-f]+)?$': + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + '^port(@[0-9a-f]+)?$': + $ref: "#/definitions/port-def" + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml index 447e013f6e17..5ea0819a261a 100644 --- a/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml @@ -9,6 +9,9 @@ title: Samsung Aries audio complex with WM8994 codec maintainers: - Jonathan Bakker <xc-racer2@live.ca> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: enum: @@ -17,10 +20,6 @@ properties: # Without FM radio and modem slave - samsung,fascinate4g-wm8994 - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - cpu: type: object additionalProperties: false @@ -46,6 +45,7 @@ properties: samsung,audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array + deprecated: true description: | List of the connections between audio components; each entry is a pair of strings, the first being the @@ -56,6 +56,7 @@ properties: or FM In For samsung,fascinate4g-wm8994: HP, SPK, RCV, LINE, Main Mic, or HeadsetMic + Deprecated, use audio-routing. extcon: description: Extcon phandle for dock detection @@ -87,10 +88,9 @@ properties: required: - compatible - - model - cpu - codec - - samsung,audio-routing + - audio-routing - extcon - main-micbias-supply - headset-micbias-supply @@ -98,7 +98,7 @@ required: - headset-detect-gpios - headset-key-gpios -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -121,7 +121,7 @@ examples: headset-detect-gpios = <&gph0 6 GPIO_ACTIVE_HIGH>; headset-key-gpios = <&gph3 6 GPIO_ACTIVE_HIGH>; - samsung,audio-routing = + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", diff --git a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml index 31095913e330..6ec80f529d84 100644 --- a/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml @@ -9,14 +9,13 @@ title: Samsung Midas audio complex with WM1811 codec maintainers: - Sylwester Nawrocki <s.nawrocki@samsung.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: samsung,midas-audio - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - cpu: type: object additionalProperties: false @@ -38,6 +37,7 @@ properties: - sound-dai samsung,audio-routing: + deprecated: true $ref: /schemas/types.yaml#/definitions/non-unique-string-array description: | List of the connections between audio components; each entry is @@ -45,6 +45,7 @@ properties: being the connection's source; valid names for sources and sinks are the WM1811's pins (as documented in its binding), and the jacks on the board: HP, SPK, Main Mic, Sub Mic, Headset Mic. + Deprecated, use audio-routing. mic-bias-supply: description: Supply for the micbias on the Main microphone @@ -62,14 +63,13 @@ properties: required: - compatible - - model - cpu - codec - - samsung,audio-routing + - audio-routing - mic-bias-supply - submic-bias-supply -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -84,7 +84,7 @@ examples: mic-bias-supply = <&mic_bias_reg>; submic-bias-supply = <&submic_bias_reg>; - samsung,audio-routing = + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml index c6751c40e63f..b77284e3e26a 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroid.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.yaml @@ -10,6 +10,9 @@ maintainers: - Krzysztof Kozlowski <krzk@kernel.org> - Sylwester Nawrocki <s.nawrocki@samsung.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: oneOf: @@ -24,10 +27,6 @@ properties: - const: samsung,odroid-xu4-audio deprecated: true - model: - $ref: /schemas/types.yaml#/definitions/string - description: The user-visible name of this sound complex. - assigned-clock-parents: true assigned-clock-rates: true assigned-clocks: true @@ -52,6 +51,7 @@ properties: samsung,audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array + deprecated: true description: | List of the connections between audio components; each entry is a pair of strings, the first being the @@ -61,6 +61,7 @@ properties: For Odroid X2: "Headphone Jack", "Mic Jack", "DMIC" For Odroid U3, XU3: "Headphone Jack", "Speakers" For Odroid XU4: no entries + Deprecated, use audio-routing. samsung,audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array @@ -70,18 +71,17 @@ properties: required: - compatible - - model - cpu - codec -additionalProperties: false +unevaluatedProperties: false examples: - | sound { compatible = "hardkernel,odroid-xu3-audio"; model = "Odroid-XU3"; - samsung,audio-routing = + audio-routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "IN1", "Mic Jack", diff --git a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml index 491e08019c04..760592599143 100644 --- a/Documentation/devicetree/bindings/sound/samsung,tm2.yaml +++ b/Documentation/devicetree/bindings/sound/samsung,tm2.yaml @@ -10,6 +10,9 @@ maintainers: - Krzysztof Kozlowski <krzk@kernel.org> - Sylwester Nawrocki <s.nawrocki@samsung.com> +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: samsung,tm2-audio @@ -32,6 +35,8 @@ properties: being the connection's source; valid names for sources and sinks are the WM5110's and MAX98504's pins and the jacks on the board: HP, SPK, Main Mic, Sub Mic, Third Mic, Headset Mic. + Deprecated, use audio-routing. + deprecated: true $ref: /schemas/types.yaml#/definitions/non-unique-string-array i2s-controller: @@ -44,20 +49,15 @@ properties: mic-bias-gpios: description: GPIO pin that enables the Main Mic bias regulator. - model: - description: The user-visible name of this sound complex. - $ref: /schemas/types.yaml#/definitions/string - required: - compatible - audio-amplifier - audio-codec - - samsung,audio-routing + - audio-routing - i2s-controller - mic-bias-gpios - - model -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -70,7 +70,7 @@ examples: audio-amplifier = <&max98504>; mic-bias-gpios = <&gpr3 2 GPIO_ACTIVE_HIGH>; model = "wm5110"; - samsung,audio-routing = "HP", "HPOUT1L", + audio-routing = "HP", "HPOUT1L", "HP", "HPOUT1R", "SPK", "SPKOUT", "SPKOUT", "HPOUT2L", diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml index b05e05c81cc4..59ac2d1d1ccf 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.yaml +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml @@ -148,6 +148,15 @@ definitions: required: - sound-dai + additional-devs: + type: object + description: + Additional devices used by the simple audio card. + patternProperties: + '^iio-aux(-.+)?$': + type: object + $ref: audio-iio-aux.yaml# + properties: compatible: contains: @@ -187,6 +196,8 @@ properties: $ref: "#/definitions/mclk-fs" simple-audio-card,aux-devs: $ref: "#/definitions/aux-devs" + simple-audio-card,additional-devs: + $ref: "#/definitions/additional-devs" simple-audio-card,convert-rate: $ref: "#/definitions/convert-rate" simple-audio-card,convert-channels: @@ -360,6 +371,48 @@ examples: }; # -------------------- +# route audio to/from a codec through an amplifier +# designed with a potentiometer driven by IIO: +# -------------------- + - | + sound { + compatible = "simple-audio-card"; + + simple-audio-card,aux-devs = <&_in>, <&_out>; + simple-audio-card,routing = + "CODEC LEFTIN", "AMP_IN LEFT OUT", + "CODEC RIGHTIN", "AMP_IN RIGHT OUT", + "AMP_OUT LEFT IN", "CODEC LEFTOUT", + "AMP_OUT RIGHT IN", "CODEC RIGHTOUT"; + + simple-audio-card,additional-devs { + amp_out: iio-aux-out { + compatible = "audio-iio-aux"; + io-channels = <&pot_out 0>, <&pot_out 1>; + io-channel-names = "LEFT", "RIGHT"; + snd-control-invert-range = <1 1>; + sound-name-prefix = "AMP_OUT"; + }; + + amp_in: iio_aux-in { + compatible = "audio-iio-aux"; + io-channels = <&pot_in 0>, <&pot_in 1>; + io-channel-names = "LEFT", "RIGHT"; + sound-name-prefix = "AMP_IN"; + }; + }; + + simple-audio-card,cpu { + sound-dai = <&cpu>; + }; + + simple-audio-card,codec { + sound-dai = <&codec>; + clocks = <&clocks>; + }; + }; + +# -------------------- # Sampling Rate Conversion # -------------------- - | diff --git a/Documentation/devicetree/bindings/sound/sound-card-common.yaml b/Documentation/devicetree/bindings/sound/sound-card-common.yaml new file mode 100644 index 000000000000..3a941177f684 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sound-card-common.yaml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sound-card-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Board Sound Card Common Properties + +maintainers: + - Mark Brown <broonie@kernel.org> + +properties: + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. Each entry is a + pair of strings, the first being the connection's sink, the second + being the connection's source. + + model: + $ref: /schemas/types.yaml#/definitions/string + description: User specified audio sound card name + +required: + - model + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml new file mode 100644 index 000000000000..329260cf0fa0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/wlf,wm8904.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wolfson WM8904/WM8912 audio codecs + +maintainers: + - patches@opensource.cirrus.com + +description: | + Pins on the device (for linking into audio routes): + IN1L, IN1R, IN2L, IN2R, IN3L, IN3R, HPOUTL, HPOUTR, LINEOUTL, LINEOUTR, + MICBIAS + +properties: + compatible: + enum: + - wlf,wm8904 + - wlf,wm8912 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + AVDD-supply: true + CPVDD-supply: true + DBVDD-supply: true + DCVDD-supply: true + MICVDD-supply: true + +required: + - compatible + - reg + - clocks + - clock-names + - AVDD-supply + - CPVDD-supply + - DBVDD-supply + - DCVDD-supply + - MICVDD-supply + +allOf: + - $ref: dai-common.yaml# + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + clocks = <&pck0>; + clock-names = "mclk"; + AVDD-supply = <®_1p8v>; + CPVDD-supply = <®_1p8v>; + DBVDD-supply = <®_1p8v>; + DCVDD-supply = <®_1p8v>; + MICVDD-supply = <®_1p8v>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml index ee8eba7f0104..62e62c335d07 100644 --- a/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8960.yaml @@ -26,6 +26,21 @@ properties: '#sound-dai-cells': const: 0 + AVDD-supply: + description: Analogue supply. + + DBVDD-supply: + description: Digital Buffer Supply. + + DCVDD-supply: + description: Digital Core Supply. + + SPKVDD1-supply: + description: Supply for speaker drivers 1. + + SPKVDD2-supply: + description: Supply for speaker drivers 2. + wlf,capless: type: boolean description: @@ -84,5 +99,10 @@ examples: wlf,hp-cfg = <3 2 3>; wlf,gpio-cfg = <1 3>; wlf,shared-lrclk; + DCVDD-supply = <®_audio>; + DBVDD-supply = <®_audio>; + AVDD-supply = <®_audio>; + SPKVDD1-supply = <®_audio>; + SPKVDD2-supply = <®_audio>; }; }; diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt deleted file mode 100644 index 66bf261423b9..000000000000 --- a/Documentation/devicetree/bindings/sound/wm8904.txt +++ /dev/null @@ -1,33 +0,0 @@ -WM8904 audio CODEC - -This device supports I2C only. - -Required properties: - - compatible: "wlf,wm8904" or "wlf,wm8912" - - reg: the I2C address of the device. - - clock-names: "mclk" - - clocks: reference to - <Documentation/devicetree/bindings/clock/clock-bindings.txt> - -Pins on the device (for linking into audio routes): - - * IN1L - * IN1R - * IN2L - * IN2R - * IN3L - * IN3R - * HPOUTL - * HPOUTR - * LINEOUTL - * LINEOUTR - * MICBIAS - -Examples: - -codec: wm8904@1a { - compatible = "wlf,wm8904"; - reg = <0x1a>; - clocks = <&pck0>; - clock-names = "mclk"; -}; diff --git a/Documentation/driver-api/media/dtv-common.rst b/Documentation/driver-api/media/dtv-common.rst index f8b2c4dc8170..207a22bcaf4a 100644 --- a/Documentation/driver-api/media/dtv-common.rst +++ b/Documentation/driver-api/media/dtv-common.rst @@ -3,15 +3,6 @@ Digital TV Common functions --------------------------- -Math functions -~~~~~~~~~~~~~~ - -Provide some commonly-used math functions, usually required in order to -estimate signal strength and signal to noise measurements in dB. - -.. kernel-doc:: include/media/dvb_math.h - - DVB devices ~~~~~~~~~~~ diff --git a/MAINTAINERS b/MAINTAINERS index 0b5ecca0b39b..3aaec9532ff9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21061,6 +21061,39 @@ S: Maintained F: Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml F: sound/soc/ti/ +TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS +M: Shenghao Ding <shenghao-ding@ti.com> +M: Kevin Lu <kevin-lu@ti.com> +M: Baojun Xu <x1077012@ti.com> +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/tas2552.txt +F: Documentation/devicetree/bindings/sound/tas2562.yaml +F: Documentation/devicetree/bindings/sound/tas2770.yaml +F: Documentation/devicetree/bindings/sound/tas27xx.yaml +F: Documentation/devicetree/bindings/sound/ti,pcm1681.txt +F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml +F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml +F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +F: Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +F: Documentation/devicetree/bindings/sound/tpa6130a2.txt +F: include/sound/tas2*.h +F: include/sound/tlv320*.h +F: include/sound/tpa6130a2-plat.h +F: sound/pci/hda/tas2781_hda_i2c.c +F: sound/soc/codecs/pcm1681.c +F: sound/soc/codecs/pcm1789*.* +F: sound/soc/codecs/pcm179x*.* +F: sound/soc/codecs/pcm186x*.* +F: sound/soc/codecs/pcm3008.* +F: sound/soc/codecs/pcm3060*.* +F: sound/soc/codecs/pcm3168a*.* +F: sound/soc/codecs/pcm5102a.c +F: sound/soc/codecs/pcm512x*.* +F: sound/soc/codecs/tas2*.* +F: sound/soc/codecs/tlv320*.* +F: sound/soc/codecs/tpa6130a2.* + TEXAS INSTRUMENTS DMA DRIVERS M: Peter Ujfalusi <peter.ujfalusi@gmail.com> L: dmaengine@vger.kernel.org diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 6a9aa97373d3..49b70c70dc69 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -978,7 +978,8 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, ctl->alg_region.alg == alg_region->alg && ctl->alg_region.type == alg_region->type) { if ((!subname && !ctl->subname) || - (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) { + (subname && (ctl->subname_len == subname_len) && + !strncmp(ctl->subname, subname, ctl->subname_len))) { if (!ctl->enabled) ctl->enabled = 1; return 0; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 5261526d286f..a8dec24b146b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2615,9 +2615,13 @@ static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops vc4_snd_dai_ops = { + .probe = vc4_hdmi_audio_cpu_dai_probe, +}; + static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { .name = "vc4-hdmi-cpu-dai", - .probe = vc4_hdmi_audio_cpu_dai_probe, + .ops = &vc4_snd_dai_ops, .playback = { .stream_name = "Playback", .channels_min = 1, diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 872fd5c24147..7a1f6713318a 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -5,9 +5,10 @@ */ #include <linux/err.h> #include <linux/export.h> +#include <linux/minmax.h> +#include <linux/mutex.h> #include <linux/property.h> #include <linux/slab.h> -#include <linux/mutex.h> #include <linux/iio/iio.h> #include <linux/iio/iio-opaque.h> @@ -849,15 +850,14 @@ static int iio_channel_read_max(struct iio_channel *chan, int *val, int *val2, int *type, enum iio_chan_info_enum info) { - int unused; const int *vals; int length; int ret; - if (!val2) - val2 = &unused; - ret = iio_channel_read_avail(chan, &vals, type, &length, info); + if (ret < 0) + return ret; + switch (ret) { case IIO_AVAIL_RANGE: switch (*type) { @@ -866,7 +866,8 @@ static int iio_channel_read_max(struct iio_channel *chan, break; default: *val = vals[4]; - *val2 = vals[5]; + if (val2) + *val2 = vals[5]; } return 0; @@ -875,20 +876,16 @@ static int iio_channel_read_max(struct iio_channel *chan, return -EINVAL; switch (*type) { case IIO_VAL_INT: - *val = vals[--length]; - while (length) { - if (vals[--length] > *val) - *val = vals[length]; - } + *val = max_array(vals, length); break; default: - /* FIXME: learn about max for other iio values */ + /* TODO: learn about max for other iio values */ return -EINVAL; } return 0; default: - return ret; + return -EINVAL; } } @@ -912,6 +909,69 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); +static int iio_channel_read_min(struct iio_channel *chan, + int *val, int *val2, int *type, + enum iio_chan_info_enum info) +{ + const int *vals; + int length; + int ret; + + ret = iio_channel_read_avail(chan, &vals, type, &length, info); + if (ret < 0) + return ret; + + switch (ret) { + case IIO_AVAIL_RANGE: + switch (*type) { + case IIO_VAL_INT: + *val = vals[0]; + break; + default: + *val = vals[0]; + if (val2) + *val2 = vals[1]; + } + return 0; + + case IIO_AVAIL_LIST: + if (length <= 0) + return -EINVAL; + switch (*type) { + case IIO_VAL_INT: + *val = min_array(vals, length); + break; + default: + /* TODO: learn about min for other iio values */ + return -EINVAL; + } + return 0; + + default: + return -EINVAL; + } +} + +int iio_read_min_channel_raw(struct iio_channel *chan, int *val) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); + int ret; + int type; + + mutex_lock(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); +err_unlock: + mutex_unlock(&iio_dev_opaque->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_min_channel_raw); + int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile index 62b028ded9f7..1cb3ca67bed9 100644 --- a/drivers/media/dvb-core/Makefile +++ b/drivers/media/dvb-core/Makefile @@ -8,6 +8,6 @@ dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ dvb_ca_en50221.o dvb_frontend.o \ - $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o + $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 3b9b9424fe1a..bba7a9693a23 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -12,7 +12,7 @@ #define AF9013_PRIV_H #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "af9013.h" #include <linux/firmware.h> #include <linux/i2c-mux.h> diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 0e64da0cdeab..7560da75ef00 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -14,7 +14,7 @@ #include <linux/math64.h> #include <linux/regmap.h> #include <linux/kernel.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> struct reg_val { u32 reg; diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index 9b4d9cf8563d..605320bbc12b 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h @@ -11,7 +11,7 @@ #include <linux/dvb/version.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "cxd2820r.h" #include <linux/gpio/driver.h> /* For gpio_chip */ #include <linux/math64.h> diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 5431f922f55e..ef403a9fb753 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -22,7 +22,7 @@ #include <linux/dynamic_debug.h> #include <linux/kernel.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> #include "cxd2841er.h" #include "cxd2841er_priv.h" diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c index 604580bf7cf7..4e173dd87ecf 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt2.h" #include "cxd2880_tnrdmd_dvbt2_mon.h" -#include <media/dvb_math.h> +#include <linux/int_log.h> static const int ref_dbm_1000[4][8] = { {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c index fedc3b4a2fa0..86d5a1e4022a 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c @@ -11,7 +11,7 @@ #include "cxd2880_tnrdmd_dvbt.h" #include "cxd2880_tnrdmd_dvbt_mon.h" -#include <media/dvb_math.h> +#include <linux/int_log.h> static const int ref_dbm_1000[3][5] = { {-93000, -91000, -90000, -89000, -88000}, diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c index d5b1b3788e39..f67b6d24b8d4 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c @@ -11,7 +11,7 @@ #include <linux/spi/spi.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "cxd2880.h" #include "cxd2880_tnrdmd_mon.h" diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index a90d2f51868f..b791e687d2e2 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -13,7 +13,7 @@ #include <linux/mutex.h> #include <asm/div64.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> #include "dib7000p.h" diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index fe19d127abb3..2abda7d1cb6e 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -13,7 +13,7 @@ #include <linux/mutex.h> #include <asm/div64.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 914ca820c174..1c57587a917a 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -11,7 +11,7 @@ #include <linux/i2c.h> #include <linux/mutex.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> #include "dib9000.h" diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 3301ef75d441..6ad4f202f1bf 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -20,7 +20,7 @@ #include <media/dvb_frontend.h> #include "drxk.h" #include "drxk_hard.h" -#include <media/dvb_math.h> +#include <linux/int_log.h> static int power_down_dvbt(struct drxk_state *state, bool set_power_mode); static int power_down_qam(struct drxk_state *state); diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index 62d743988919..c15d3735d34c 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -10,7 +10,7 @@ #include <asm/div64.h> #include <linux/dvb/frontend.h> #include <linux/slab.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "lgdt3305.h" static int debug; diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 70258884126b..3c6650f6e9a3 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -12,7 +12,7 @@ #include <asm/div64.h> #include <linux/kernel.h> #include <linux/dvb/frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "lgdt3306a.h" #include <linux/i2c-mux.h> diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 83565209c3b1..97a10996c7fa 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -28,7 +28,7 @@ #include <asm/byteorder.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "lgdt330x_priv.h" #include "lgdt330x.h" diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h index aa5306f40201..594ad9cbc2cc 100644 --- a/drivers/media/dvb-frontends/m88ds3103_priv.h +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h @@ -10,7 +10,7 @@ #include <media/dvb_frontend.h> #include "m88ds3103.h" -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <linux/firmware.h> #include <linux/i2c-mux.h> #include <linux/regmap.h> diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 2ce5692bc22c..db2921c736af 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -10,7 +10,7 @@ #include <linux/gpio/consumer.h> #include <linux/of_device.h> #include <linux/regmap.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "mn88443x.h" diff --git a/drivers/media/dvb-frontends/mn88472_priv.h b/drivers/media/dvb-frontends/mn88472_priv.h index 337562723f88..41f14bd67bfd 100644 --- a/drivers/media/dvb-frontends/mn88472_priv.h +++ b/drivers/media/dvb-frontends/mn88472_priv.h @@ -9,7 +9,7 @@ #define MN88472_PRIV_H #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "mn88472.h" #include <linux/firmware.h> #include <linux/regmap.h> diff --git a/drivers/media/dvb-frontends/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h index eca7f4e2b769..e9daaacfa22f 100644 --- a/drivers/media/dvb-frontends/mn88473_priv.h +++ b/drivers/media/dvb-frontends/mn88473_priv.h @@ -9,7 +9,7 @@ #define MN88473_PRIV_H #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "mn88473.h" #include <linux/math64.h> #include <linux/firmware.h> diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index 24de1b115158..355f3598627b 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -27,7 +27,7 @@ #include <linux/slab.h> #include <asm/byteorder.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> #include "or51132.h" diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index ddcaea5c9941..ae732dc5116e 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <asm/byteorder.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include <media/dvb_frontend.h> #include "or51211.h" diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h index fae78ed78522..ae1fc24a4d84 100644 --- a/drivers/media/dvb-frontends/rtl2830_priv.h +++ b/drivers/media/dvb-frontends/rtl2830_priv.h @@ -9,7 +9,7 @@ #define RTL2830_PRIV_H #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "rtl2830.h" #include <linux/i2c-mux.h> #include <linux/math64.h> diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 5f79f95b9475..f11ba038d5f0 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -14,7 +14,7 @@ #include <linux/bitops.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "rtl2832.h" struct rtl2832_dev { diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 72810efd1a96..434d003bf397 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -19,7 +19,7 @@ #include <linux/regmap.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "si2165_priv.h" #include "si2165.h" diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 95e376f23506..a93f40617469 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -15,7 +15,7 @@ #include <linux/slab.h> #include <linux/i2c.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "stv0367.h" #include "stv0367_defs.h" diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index 879f028f9682..1f8cbf45554a 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -21,7 +21,7 @@ #include <linux/kernel.h> #include <linux/math64.h> #include <linux/dvb/frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "tc90522.h" #define TC90522_I2C_THRU_REG 0xfe diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index 0b3f6999515e..3cb4e5270e4f 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -16,7 +16,7 @@ #include <linux/math64.h> #include <asm/div64.h> #include <media/dvb_frontend.h> -#include <media/dvb_math.h> +#include <linux/int_log.h> #include "tda10048.h" #define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw" diff --git a/include/linux/device.h b/include/linux/device.h index bbaeabd04b0d..6731d7dc1a2a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -349,6 +349,7 @@ unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); void devm_free_pages(struct device *dev, unsigned long addr); +#ifdef CONFIG_HAS_IOMEM void __iomem *devm_ioremap_resource(struct device *dev, const struct resource *res); void __iomem *devm_ioremap_resource_wc(struct device *dev, @@ -357,6 +358,31 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev, void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, resource_size_t *size); +#else + +static inline +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res) +{ + return ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_ioremap_resource_wc(struct device *dev, + const struct resource *res) +{ + return ERR_PTR(-EINVAL); +} + +static inline +void __iomem *devm_of_iomap(struct device *dev, + struct device_node *node, int index, + resource_size_t *size) +{ + return ERR_PTR(-EINVAL); +} + +#endif /* allows to add/remove a custom action to devres stack */ void devm_remove_action(struct device *dev, void (*action)(void *), void *data); diff --git a/include/linux/firmware/imx/dsp.h b/include/linux/firmware/imx/dsp.h index 4f7895a3b73c..1f176a2683fe 100644 --- a/include/linux/firmware/imx/dsp.h +++ b/include/linux/firmware/imx/dsp.h @@ -37,17 +37,11 @@ struct imx_dsp_ipc { static inline void imx_dsp_set_data(struct imx_dsp_ipc *ipc, void *data) { - if (!ipc) - return; - ipc->private_data = data; } static inline void *imx_dsp_get_data(struct imx_dsp_ipc *ipc) { - if (!ipc) - return NULL; - return ipc->private_data; } diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h index 28fd313340b8..5b1d16fa3f56 100644 --- a/include/linux/firmware/mediatek/mtk-adsp-ipc.h +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -46,17 +46,11 @@ struct mtk_adsp_ipc { static inline void mtk_adsp_ipc_set_data(struct mtk_adsp_ipc *ipc, void *data) { - if (!ipc) - return; - ipc->private_data = data; } static inline void *mtk_adsp_ipc_get_data(struct mtk_adsp_ipc *ipc) { - if (!ipc) - return NULL; - return ipc->private_data; } diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 6802596b017c..e9910b41d48e 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -201,8 +201,9 @@ struct iio_dev * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_channel_raw(struct iio_channel *chan, int *val); @@ -212,8 +213,9 @@ int iio_read_channel_raw(struct iio_channel *chan, * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. * * In opposit to the normal iio_read_channel_raw this function * returns the average of multiple reads. @@ -281,8 +283,9 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, * @chan: The channel being queried. * @val: Value being written. * - * Note raw writes to iio channels are in dac counts and hence - * scale will need to be applied if standard units required. + * Note that for raw writes to iio channels, if the value provided is + * in standard units, the affect of the scale and offset must be removed + * as (value / scale) - offset. */ int iio_write_channel_raw(struct iio_channel *chan, int val); @@ -292,12 +295,25 @@ int iio_write_channel_raw(struct iio_channel *chan, int val); * @chan: The channel being queried. * @val: Value read back. * - * Note raw reads from iio channels are in adc counts and hence - * scale will need to be applied if standard units are required. + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_max_channel_raw(struct iio_channel *chan, int *val); /** + * iio_read_min_channel_raw() - read minimum available raw value from a given + * channel, i.e. the minimum possible value. + * @chan: The channel being queried. + * @val: Value read back. + * + * Note, if standard units are required, raw reads from iio channels + * need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. + */ +int iio_read_min_channel_raw(struct iio_channel *chan, int *val); + +/** * iio_read_avail_channel_raw() - read available raw values from a given channel * @chan: The channel being queried. * @vals: Available values read back. @@ -308,8 +324,9 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val); * For ranges, three vals are always returned; min, step and max. * For lists, all the possible values are enumerated. * - * Note raw available values from iio channels are in adc counts and - * hence scale will need to be applied if standard units are required. + * Note, if standard units are required, raw available values from iio + * channels need the offset (default 0) and scale (default 1) to be applied + * as (raw + offset) * scale. */ int iio_read_avail_channel_raw(struct iio_channel *chan, const int **vals, int *length); diff --git a/include/media/dvb_math.h b/include/linux/int_log.h index 8690ec42954d..0a6f58c38b61 100644 --- a/include/media/dvb_math.h +++ b/include/linux/int_log.h @@ -1,22 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff + * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. */ -#ifndef __DVB_MATH_H -#define __DVB_MATH_H +#ifndef __LINUX_INT_LOG_H +#define __LINUX_INT_LOG_H #include <linux/types.h> diff --git a/include/linux/minmax.h b/include/linux/minmax.h index 396df1121bff..798c6963909f 100644 --- a/include/linux/minmax.h +++ b/include/linux/minmax.h @@ -133,6 +133,70 @@ */ #define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >) +/* + * Remove a const qualifier from integer types + * _Generic(foo, type-name: association, ..., default: association) performs a + * comparison against the foo type (not the qualified type). + * Do not use the const keyword in the type-name as it will not match the + * unqualified type of foo. + */ +#define __unconst_integer_type_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unconst_integer_typeof(x) typeof( \ + _Generic((x), \ + char: (char)0, \ + __unconst_integer_type_cases(char), \ + __unconst_integer_type_cases(short), \ + __unconst_integer_type_cases(int), \ + __unconst_integer_type_cases(long), \ + __unconst_integer_type_cases(long long), \ + default: (x))) + +/* + * Do not check the array parameter using __must_be_array(). + * In the following legit use-case where the "array" passed is a simple pointer, + * __must_be_array() will return a failure. + * --- 8< --- + * int *buff + * ... + * min = min_array(buff, nb_items); + * --- 8< --- + * + * The first typeof(&(array)[0]) is needed in order to support arrays of both + * 'int *buff' and 'int buff[N]' types. + * + * The array can be an array of const items. + * typeof() keeps the const qualifier. Use __unconst_integer_typeof() in order + * to discard the const qualifier for the __element variable. + */ +#define __minmax_array(op, array, len) ({ \ + typeof(&(array)[0]) __array = (array); \ + typeof(len) __len = (len); \ + __unconst_integer_typeof(__array[0]) __element = __array[--__len]; \ + while (__len--) \ + __element = op(__element, __array[__len]); \ + __element; }) + +/** + * min_array - return minimum of values present in an array + * @array: array + * @len: array length + * + * Note that @len must not be zero (empty array). + */ +#define min_array(array, len) __minmax_array(min, array, len) + +/** + * max_array - return maximum of values present in an array + * @array: array + * @len: array length + * + * Note that @len must not be zero (empty array). + */ +#define max_array(array, len) __minmax_array(max, array, len) + /** * clamp_t - return a value clamped to a given range using a given type * @type: the type of variable to use diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2dc75df1437f..a6411aa4c331 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2644,6 +2644,7 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 +#define PCI_DEVICE_ID_INTEL_HDA_CML_LP 0x02c8 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 @@ -2659,8 +2660,10 @@ #define PCI_DEVICE_ID_INTEL_82424 0x0483 #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82425 0x0486 +#define PCI_DEVICE_ID_INTEL_HDA_CML_H 0x06c8 #define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807 #define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808 +#define PCI_DEVICE_ID_INTEL_HDA_OAKTRAIL 0x080a #define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820 #define PCI_DEVICE_ID_INTEL_MFD_SDIO1 0x0821 #define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822 @@ -2670,15 +2673,19 @@ #define PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB 0x095e #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 +#define PCI_DEVICE_ID_INTEL_HDA_HSW_0 0x0a0c +#define PCI_DEVICE_ID_INTEL_HDA_HSW_2 0x0c0c #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60 +#define PCI_DEVICE_ID_INTEL_HDA_HSW_3 0x0d0c +#define PCI_DEVICE_ID_INTEL_HDA_BYT 0x0f04 +#define PCI_DEVICE_ID_INTEL_SST_BYT 0x0f28 #define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062 #define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085 #define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108f #define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 #define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 +#define PCI_DEVICE_ID_INTEL_SST_TNG 0x119a #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 -#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 -#define PCI_DEVICE_ID_INTEL_7205_0 0x255d #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e #define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 @@ -2704,20 +2711,26 @@ #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE 0x1576 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI 0x1577 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE 0x1578 +#define PCI_DEVICE_ID_INTEL_HDA_BDW 0x160c #define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX 0x19e2 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF 0x19e3 #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 +#define PCI_DEVICE_ID_INTEL_HDA_CPT 0x1c20 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_HDA_PBG 0x1d20 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 +#define PCI_DEVICE_ID_INTEL_HDA_PPT 0x1e20 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f #define PCI_DEVICE_ID_INTEL_VMD_201D 0x201d +#define PCI_DEVICE_ID_INTEL_HDA_BSW 0x2284 +#define PCI_DEVICE_ID_INTEL_SST_BSW 0x22a8 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 @@ -2772,6 +2785,8 @@ #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 #define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 #define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c +#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 +#define PCI_DEVICE_ID_INTEL_7205_0 0x255d #define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 #define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 #define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 @@ -2793,12 +2808,14 @@ #define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 #define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 #define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 +#define PCI_DEVICE_ID_INTEL_HDA_ICH6 0x2668 #define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a #define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d #define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e #define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f #define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 #define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 +#define PCI_DEVICE_ID_INTEL_HDA_ESB2 0x269a #define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b #define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e #define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770 @@ -2806,11 +2823,12 @@ #define PCI_DEVICE_ID_INTEL_3000_HB 0x2778 #define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27a0 #define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27a2 +#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 #define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 -#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 #define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc #define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd +#define PCI_DEVICE_ID_INTEL_HDA_ICH7 0x27d8 #define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da #define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd #define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de @@ -2821,17 +2839,20 @@ #define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814 #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e +#define PCI_DEVICE_ID_INTEL_HDA_ICH8 0x284b #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 #define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c0 #define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 #define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 #define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 #define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 #define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 #define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_HDA_ICH9_0 0x293e +#define PCI_DEVICE_ID_INTEL_HDA_ICH9_1 0x293f #define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 #define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 #define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a @@ -2848,8 +2869,8 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 -#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70 @@ -2883,6 +2904,7 @@ #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3 +#define PCI_DEVICE_ID_INTEL_HDA_GML 0x3198 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a @@ -2893,12 +2915,13 @@ #define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 #define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 #define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 +#define PCI_DEVICE_ID_INTEL_HDA_ICL_LP 0x34c8 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c -#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 #define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c +#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e #define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 #define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 #define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 @@ -2908,11 +2931,11 @@ #define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 #define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e +#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b +#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c #define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610 -#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b -#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c #define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710 #define PCI_DEVICE_ID_INTEL_IOAT_JSF1 0x3711 #define PCI_DEVICE_ID_INTEL_IOAT_JSF2 0x3712 @@ -2925,14 +2948,19 @@ #define PCI_DEVICE_ID_INTEL_IOAT_JSF9 0x3719 #define PCI_DEVICE_ID_INTEL_QAT_C62X 0x37c8 #define PCI_DEVICE_ID_INTEL_QAT_C62X_VF 0x37c9 +#define PCI_DEVICE_ID_INTEL_HDA_ICL_N 0x38c8 #define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14 #define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16 #define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18 #define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a #define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 +#define PCI_DEVICE_ID_INTEL_HDA_ICH10_0 0x3a3e #define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 +#define PCI_DEVICE_ID_INTEL_HDA_ICH10_1 0x3a6e #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f +#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_0 0x3b56 +#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_1 0x3b57 #define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 #define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 #define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 @@ -2943,16 +2971,12 @@ #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f -#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 -#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 -#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 -#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 -#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 #define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 #define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS 0x3c71 /* 15.1 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0 0x3c72 /* 16.2 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1 0x3c73 /* 16.3 */ @@ -2964,17 +2988,40 @@ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1 0x3cab /* 15.3 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2 0x3cac /* 15.4 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3 0x3cad /* 15.5 */ +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO 0x3cb8 /* 17.0 */ #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */ #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1 0x3cf6 /* 12.7 */ +#define PCI_DEVICE_ID_INTEL_HDA_ICL_H 0x3dc8 #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 #define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035 #define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036 +#define PCI_DEVICE_ID_INTEL_HDA_TGL_H 0x43c8 +#define PCI_DEVICE_ID_INTEL_HDA_DG1 0x490d +#define PCI_DEVICE_ID_INTEL_HDA_EHL_0 0x4b55 +#define PCI_DEVICE_ID_INTEL_HDA_EHL_3 0x4b58 +#define PCI_DEVICE_ID_INTEL_HDA_JSL_N 0x4dc8 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_0 0x4f90 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_1 0x4f91 +#define PCI_DEVICE_ID_INTEL_HDA_DG2_2 0x4f92 #define PCI_DEVICE_ID_INTEL_EP80579_0 0x5031 #define PCI_DEVICE_ID_INTEL_EP80579_1 0x5032 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_P 0x51c8 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_PS 0x51c9 +#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_0 0x51ca +#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_1 0x51cb +#define PCI_DEVICE_ID_INTEL_HDA_ADL_M 0x51cc +#define PCI_DEVICE_ID_INTEL_HDA_ADL_PX 0x51cd +#define PCI_DEVICE_ID_INTEL_HDA_RPL_M 0x51ce +#define PCI_DEVICE_ID_INTEL_HDA_RPL_PX 0x51cf +#define PCI_DEVICE_ID_INTEL_HDA_ADL_N 0x54c8 +#define PCI_DEVICE_ID_INTEL_HDA_APL 0x5a98 #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 #define PCI_DEVICE_ID_INTEL_5100_19 0x65f3 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 @@ -3008,8 +3055,13 @@ #define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 #define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_HDA_RPL_S 0x7a50 +#define PCI_DEVICE_ID_INTEL_HDA_ADL_S 0x7ad0 +#define PCI_DEVICE_ID_INTEL_HDA_MTL 0x7e28 +#define PCI_DEVICE_ID_INTEL_HDA_ARL_S 0x7f50 #define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 #define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a +#define PCI_DEVICE_ID_INTEL_HDA_POULSBO 0x811b #define PCI_DEVICE_ID_INTEL_E6XX_CU 0x8183 #define PCI_DEVICE_ID_INTEL_ITC_LPC 0x8186 #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 @@ -3018,9 +3070,31 @@ #define PCI_DEVICE_ID_INTEL_82454NX 0x84cb #define PCI_DEVICE_ID_INTEL_84460GX 0x84ea #define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 +#define PCI_DEVICE_ID_INTEL_HDA_LPT 0x8c20 +#define PCI_DEVICE_ID_INTEL_HDA_9_SERIES 0x8ca0 +#define PCI_DEVICE_ID_INTEL_HDA_WBG_0 0x8d20 +#define PCI_DEVICE_ID_INTEL_HDA_WBG_1 0x8d21 #define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 +#define PCI_DEVICE_ID_INTEL_HDA_LKF 0x98c8 #define PCI_DEVICE_ID_INTEL_VMD_9A0B 0x9a0b +#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_0 0x9c20 +#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_1 0x9c21 +#define PCI_DEVICE_ID_INTEL_HDA_WPT_LP 0x9ca0 +#define PCI_DEVICE_ID_INTEL_HDA_SKL_LP 0x9d70 +#define PCI_DEVICE_ID_INTEL_HDA_KBL_LP 0x9d71 +#define PCI_DEVICE_ID_INTEL_HDA_CNL_LP 0x9dc8 +#define PCI_DEVICE_ID_INTEL_HDA_TGL_LP 0xa0c8 +#define PCI_DEVICE_ID_INTEL_HDA_SKL 0xa170 +#define PCI_DEVICE_ID_INTEL_HDA_KBL 0xa171 +#define PCI_DEVICE_ID_INTEL_HDA_LBG_0 0xa1f0 +#define PCI_DEVICE_ID_INTEL_HDA_LBG_1 0xa270 +#define PCI_DEVICE_ID_INTEL_HDA_KBL_H 0xa2f0 +#define PCI_DEVICE_ID_INTEL_HDA_CNL_H 0xa348 +#define PCI_DEVICE_ID_INTEL_HDA_CML_S 0xa3f0 +#define PCI_DEVICE_ID_INTEL_HDA_LNL_P 0xa828 #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 +#define PCI_DEVICE_ID_INTEL_HDA_CML_R 0xf0c8 +#define PCI_DEVICE_ID_INTEL_HDA_RKL_S 0xf1c8 #define PCI_VENDOR_ID_WANGXUN 0x8088 diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index b845fd83f429..7a41c72c1959 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -63,6 +63,8 @@ extern struct resource *platform_get_mem_or_io(struct platform_device *, extern struct device * platform_find_device_by_driver(struct device *start, const struct device_driver *drv); + +#ifdef CONFIG_HAS_IOMEM extern void __iomem * devm_platform_get_and_ioremap_resource(struct platform_device *pdev, unsigned int index, struct resource **res); @@ -72,6 +74,32 @@ devm_platform_ioremap_resource(struct platform_device *pdev, extern void __iomem * devm_platform_ioremap_resource_byname(struct platform_device *pdev, const char *name); +#else + +static inline void __iomem * +devm_platform_get_and_ioremap_resource(struct platform_device *pdev, + unsigned int index, struct resource **res) +{ + return ERR_PTR(-EINVAL); +} + + +static inline void __iomem * +devm_platform_ioremap_resource(struct platform_device *pdev, + unsigned int index) +{ + return ERR_PTR(-EINVAL); +} + +static inline void __iomem * +devm_platform_ioremap_resource_byname(struct platform_device *pdev, + const char *name) +{ + return ERR_PTR(-EINVAL); +} + +#endif + extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 8923387a7405..a388160f4be0 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -486,6 +486,11 @@ struct sdw_slave_id { __u8 sdw_version:4; }; +struct sdw_extended_slave_id { + int link_id; + struct sdw_slave_id id; +}; + /* * Helper macros to extract the MIPI-defined IDs * diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 11fc88fb0d78..fa67fad4ef51 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -264,11 +264,6 @@ struct sdw_intel_link_dev; */ #define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3) -struct sdw_intel_slave_id { - int link_id; - struct sdw_slave_id id; -}; - struct hdac_bus; /** @@ -298,7 +293,7 @@ struct sdw_intel_ctx { int num_slaves; acpi_handle handle; struct sdw_intel_link_dev **ldev; - struct sdw_intel_slave_id *ids; + 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; diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 1f9713d7ca76..3950322bf3cb 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -252,15 +252,40 @@ #define CS35L56_NUM_BULK_SUPPLIES 3 #define CS35L56_NUM_DSP_REGIONS 5 +struct cs35l56_base { + struct device *dev; + struct regmap *regmap; + int irq; + struct mutex irq_lock; + u8 rev; + bool init_done; + bool fw_patched; + bool secured; + bool can_hibernate; + struct gpio_desc *reset_gpio; +}; + extern struct regmap_config cs35l56_regmap_i2c; extern struct regmap_config cs35l56_regmap_spi; extern struct regmap_config cs35l56_regmap_sdw; -extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS]; extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC]; extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC]; -void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap); +int cs35l56_set_patch(struct cs35l56_base *cs35l56_base); +int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command); +int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base); +int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base); +void cs35l56_wait_control_port_ready(void); +void cs35l56_wait_min_reset_pulse(void); +void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire); +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); +irqreturn_t cs35l56_irq(int irq, void *data); +int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); +int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base); +int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire); +void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); +int cs35l56_hw_init(struct cs35l56_base *cs35l56_base); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index 4f44f0bd5388..228114aca415 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -42,6 +42,7 @@ int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, i int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink); int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink); +int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid); int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num); int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, @@ -146,6 +147,9 @@ static inline int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return 0; } static inline int +hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) { return 0; } + +static inline int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { return 0; } static inline int diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index bbb7805e85d8..5497dc9c396a 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -18,9 +18,6 @@ #include <sound/hda_verbs.h> #include <sound/hda_regmap.h> -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) - /* * Structures */ diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 2ffdf58bd6d4..32c59053b48e 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -11,6 +11,7 @@ #include <linux/io.h> #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/iopoll.h> +#include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/timecounter.h> #include <sound/core.h> @@ -704,4 +705,29 @@ static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) for ((idx) = 0, (ptr) = (array)->list; (idx) < (array)->used; \ (ptr) = snd_array_elem(array, ++(idx))) +/* + * Device matching + */ + +#define HDA_CONTROLLER_IS_HSW(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_0) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_2) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_3) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_BDW) }, \ + { } \ + }, pci)) + +#define HDA_CONTROLLER_IS_APL(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_APL) }, \ + { } \ + }, pci)) + +#define HDA_CONTROLLER_IN_GPU(pci) (pci_match_id((struct pci_device_id []){ \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG1) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_0) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_1) }, \ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_2) }, \ + { } \ + }, pci) || HDA_CONTROLLER_IS_HSW(pci)) + #endif /* __SOUND_HDAUDIO_H */ diff --git a/include/sound/rt5665.h b/include/sound/rt5665.h index 3b3d6a19ca49..e865f041929b 100644 --- a/include/sound/rt5665.h +++ b/include/sound/rt5665.h @@ -31,8 +31,6 @@ struct rt5665_platform_data { bool in3_diff; bool in4_diff; - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5665_dmic1_data_pin dmic1_data_pin; enum rt5665_dmic2_data_pin dmic2_data_pin; enum rt5665_jd_src jd_src; diff --git a/include/sound/rt5668.h b/include/sound/rt5668.h index 182edfbc9e7a..b682418c6cd6 100644 --- a/include/sound/rt5668.h +++ b/include/sound/rt5668.h @@ -25,9 +25,6 @@ enum rt5668_jd_src { }; struct rt5668_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5668_dmic1_data_pin dmic1_data_pin; enum rt5668_dmic1_clk_pin dmic1_clk_pin; enum rt5668_jd_src jd_src; diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h index 3900a07e3935..4256df721e3a 100644 --- a/include/sound/rt5682.h +++ b/include/sound/rt5682.h @@ -31,9 +31,6 @@ enum rt5682_dai_clks { }; struct rt5682_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5682_dmic1_data_pin dmic1_data_pin; enum rt5682_dmic1_clk_pin dmic1_clk_pin; enum rt5682_jd_src jd_src; diff --git a/include/sound/rt5682s.h b/include/sound/rt5682s.h index f18d91308b9a..66ca0c75b914 100644 --- a/include/sound/rt5682s.h +++ b/include/sound/rt5682s.h @@ -32,9 +32,6 @@ enum rt5682s_dai_clks { }; struct rt5682s_platform_data { - - int ldo1_en; /* GPIO for LDO1_EN */ - enum rt5682s_dmic1_data_pin dmic1_data_pin; enum rt5682s_dmic1_clk_pin dmic1_clk_pin; enum rt5682s_jd_src jd_src; diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index b450d5873227..d1a95bc33c56 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -192,9 +192,8 @@ int asoc_simple_remove(struct platform_device *pdev); int asoc_graph_card_probe(struct snd_soc_card *card); int asoc_graph_is_ports0(struct device_node *port); -int asoc_graph_parse_dai(struct device_node *ep, - struct snd_soc_dai_link_component *dlc, - int *is_single_link); +int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, + struct snd_soc_dai_link_component *dlc, int *is_single_link); #ifdef DEBUG static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 528279056b3a..6d31d535e8f6 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -9,6 +9,7 @@ #include <linux/stddef.h> #include <linux/acpi.h> #include <linux/mod_devicetable.h> +#include <linux/soundwire/sdw.h> struct snd_soc_acpi_package_context { char *name; /* package name */ @@ -150,6 +151,7 @@ struct snd_soc_acpi_link_adr { * all firmware/topology related fields. * * @id: ACPI ID (usually the codec's) used to find a matching machine driver. + * @uid: ACPI Unique ID, can be used to disambiguate matches. * @comp_ids: list of compatible audio codecs using the same machine driver, * firmware and topology * @link_mask: describes required board layout, e.g. for SoundWire. @@ -208,4 +210,9 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev) !strncmp(dev->parent->driver->name, "sof-audio-acpi", strlen("sof-audio-acpi")); } +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); + #endif diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e3906ecda740..5fcfba47d98c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -271,7 +271,18 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); +const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); + struct snd_soc_dai_ops { + /* DAI driver callbacks */ + 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); + /* Optional Callback used at pcm creation*/ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); + /* * DAI clocking configuration, all optional. * Called by soc_card drivers, normally in their hw_params. @@ -353,6 +364,10 @@ struct snd_soc_dai_ops { u64 *auto_selectable_formats; int num_auto_selectable_formats; + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; + /* bit field */ unsigned int no_capture_mute:1; }; @@ -397,15 +412,7 @@ struct snd_soc_dai_driver { unsigned int id; unsigned int base; struct snd_soc_dobj dobj; - - /* DAI driver callbacks */ - 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); - /* Optional Callback used at pcm creation*/ - int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); + struct of_phandle_args *dai_args; /* ops */ const struct snd_soc_dai_ops *ops; @@ -417,10 +424,6 @@ struct snd_soc_dai_driver { unsigned int symmetric_rate:1; unsigned int symmetric_channels:1; unsigned int symmetric_sample_bits:1; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* for Playback/Capture */ diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 87f8e1793af1..d2faec9a323e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -42,36 +42,45 @@ struct soc_enum; /* codec domain */ #define SND_SOC_DAPM_VMID(wname) \ -{ .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0} /* platform domain */ #define SND_SOC_DAPM_SIGGEN(wname) \ -{ .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_SINK(wname) \ -{ .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_INPUT(wname) \ -{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_OUTPUT(wname) \ -{ .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_MIC(wname, wevent) \ -{ .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} #define SND_SOC_DAPM_HP(wname, wevent) \ -{ .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_SPK(wname, wevent) \ -{ .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_LINE(wname, wevent) \ -{ .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} @@ -82,93 +91,110 @@ struct soc_enum; /* path domain */ #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ wcontrols, wncontrols) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ wcontrols, wncontrols) \ -{ .id = snd_soc_dapm_out_drv, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_out_drv, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ wcontrols, wncontrols)\ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ wcontrols, wncontrols)\ -{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} /* DEPRECATED: use SND_SOC_DAPM_SUPPLY */ #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_micbias, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_micbias, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = NULL, .num_kcontrols = 0} #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_switch, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_switch, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_mux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \ -{ .id = snd_soc_dapm_demux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_demux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1} /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ wcontrols) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ wcontrols)\ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ wcontrols)\ -{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} /* path domain with event - event handler must return 0 for success */ #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_out_drv, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_out_drv, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ wcontrols, wncontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, \ .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_switch, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_switch, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_mux, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mux, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = 1, \ .event = wevent, .event_flags = wflags} @@ -176,101 +202,121 @@ struct soc_enum; /* additional sequencing control within an event type */ #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags, \ .subseq = wsubseq} #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \ wflags) \ -{ .id = snd_soc_dapm_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_supply, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags, .subseq = wsubseq} /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_pga, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pga, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ wcontrols, wevent, wflags) \ -{ .id = snd_soc_dapm_mixer, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_mixer, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ .event = wevent, .event_flags = wflags} /* events that are pre and post DAPM */ #define SND_SOC_DAPM_PRE(wname, wevent) \ -{ .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD} #define SND_SOC_DAPM_POST(wname, wevent) \ -{ .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ #define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) } #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ -{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ wevent, wflags) \ -{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ -{ .id = snd_soc_dapm_clock_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_clock_supply, .name = wname, \ .reg = SND_SOC_NOPM, .event = dapm_clock_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } /* generic widgets */ #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ -{ .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ +(struct snd_soc_dapm_widget) { \ + .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ .reg = wreg, .shift = wshift, .mask = wmask, \ .on_val = won_val, .off_val = woff_val, } #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ -{ .id = snd_soc_dapm_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_supply, .name = wname, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ -{ .id = snd_soc_dapm_regulator_supply, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_regulator_supply, .name = wname, \ .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ .on_val = wflags} #define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \ -{ .id = snd_soc_dapm_pinctrl, .name = wname, \ +(struct snd_soc_dapm_widget) { \ + .id = snd_soc_dapm_pinctrl, .name = wname, \ .priv = (&(struct snd_soc_dapm_pinctrl_priv) \ { .active_state = active, .sleep_state = sleep,}), \ .reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \ @@ -604,6 +650,7 @@ struct snd_soc_dapm_widget { unsigned char power_checked:1; /* power checked this run */ unsigned char is_supply:1; /* Widget is a supply type widget */ unsigned char is_ep:2; /* Widget is a endpoint type widget */ + unsigned char no_wname_in_kcontrol_name:1; /* No widget name prefix in kcontrol name */ int subseq; /* sort within widget type */ int (*power_check)(struct snd_soc_dapm_widget *w); diff --git a/include/sound/soc.h b/include/sound/soc.h index b27f84580c5b..fa2337a3cf4c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -651,6 +651,7 @@ struct snd_soc_dai_link_component { const char *name; struct device_node *of_node; const char *dai_name; + struct of_phandle_args *dai_args; }; struct snd_soc_dai_link_codec_ch_map { @@ -1335,6 +1336,11 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card, void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd); +void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus); +struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, + struct of_phandle_args *args); +struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args); struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, bool legacy_dai_naming); diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 88560281d420..906e2f327ad2 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -26,9 +26,9 @@ enum sof_comp_type { SOF_COMP_MIXER, SOF_COMP_MUX, SOF_COMP_SRC, - SOF_COMP_SPLITTER, + SOF_COMP_DEPRECATED0, /* Formerly SOF_COMP_SPLITTER */ SOF_COMP_TONE, - SOF_COMP_SWITCH, + SOF_COMP_DEPRECATED1, /* Formerly SOF_COMP_SWITCH */ SOF_COMP_BUFFER, SOF_COMP_EQ_IIR, SOF_COMP_EQ_FIR, diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index e9ec7e4eb982..453cab2a1209 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -99,7 +99,11 @@ #define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME 414 #define SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS 415 #define SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS 416 - +/* + * The token value is copied to the dapm_widget's + * no_wname_in_kcontrol_name. + */ +#define SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME 417 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 diff --git a/lib/math/Makefile b/lib/math/Makefile index bfac26ddfc22..91fcdb0c9efe 100644 --- a/lib/math/Makefile +++ b/lib/math/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += div64.o gcd.o lcm.o int_pow.o int_sqrt.o reciprocal_div.o +obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o obj-$(CONFIG_CORDIC) += cordic.o obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o diff --git a/drivers/media/dvb-core/dvb_math.c b/lib/math/int_log.c index dc90564d7f34..8f9da3a2ad39 100644 --- a/drivers/media/dvb-core/dvb_math.c +++ b/lib/math/int_log.c @@ -1,25 +1,17 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* - * dvb-math provides some complex fixed-point math - * operations shared between the dvb related stuff + * Provides fixed-point logarithm operations. * * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. */ #include <linux/bitops.h> +#include <linux/export.h> +#include <linux/int_log.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/types.h> + #include <asm/bug.h> -#include <media/dvb_math.h> static const unsigned short logtable[256] = { 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, @@ -53,7 +45,7 @@ static const unsigned short logtable[256] = { 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, - 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 + 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47, }; unsigned int intlog2(u32 value) @@ -90,7 +82,7 @@ unsigned int intlog2(u32 value) * so we would use the entry 0x18 */ significand = value << (31 - msb); - logentry = (significand >> 23) & 0xff; + logentry = (significand >> 23) % ARRAY_SIZE(logtable); /** * last step we do is interpolation because of the @@ -108,7 +100,7 @@ unsigned int intlog2(u32 value) * logtable_next is 256 */ interpolation = ((significand & 0x7fffff) * - ((logtable[(logentry + 1) & 0xff] - + ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] - logtable[logentry]) & 0xffff)) >> 15; /* now we return the result */ diff --git a/sound/Kconfig b/sound/Kconfig index 0ddfb717b81d..f0e15822e858 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -39,8 +39,6 @@ config SOUND_OSS_CORE_PRECLAIM source "sound/oss/dmasound/Kconfig" -if !UML - menuconfig SND tristate "Advanced Linux Sound Architecture" help @@ -103,8 +101,6 @@ source "sound/virtio/Kconfig" endif # SND -endif # !UML - endif # SOUND config AC97_BUS diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c index e1f864dc7939..ea8072bf3aa4 100644 --- a/sound/drivers/serial-generic.c +++ b/sound/drivers/serial-generic.c @@ -366,7 +366,7 @@ MODULE_DEVICE_TABLE(of, snd_serial_generic_dt_ids); static struct serdev_device_driver snd_serial_generic_driver = { .driver = { .name = "snd-serial-generic", - .of_match_table = of_match_ptr(snd_serial_generic_dt_ids), + .of_match_table = snd_serial_generic_dt_ids, }, .probe = snd_serial_generic_probe, }; diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 161a9711cd63..b428537f284c 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -11,11 +11,6 @@ #include <sound/hda_i915.h> #include <sound/hda_register.h> -#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ - ((pci)->device == 0x0c0c) || \ - ((pci)->device == 0x0d0c) || \ - ((pci)->device == 0x160c)) - /** * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW * @bus: HDA core bus @@ -39,7 +34,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ - if (!IS_HSW_CONTROLLER(pci)) + if (!HDA_CONTROLLER_IS_HSW(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); @@ -80,14 +75,20 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) if (bus_a == bus_b) return true; - /* - * on i915 discrete GPUs with embedded HDA audio, the two - * devices are connected via 2nd level PCI bridge - */ bus_a = bus_a->parent; bus_b = bus_b->parent; + + /* connected via parent bus (may be NULL!) */ + if (bus_a == bus_b) + return true; + if (!bus_a || !bus_b) return false; + + /* + * on i915 discrete GPUs with embedded HDA audio, the two + * devices are connected via 2nd level PCI bridge + */ bus_a = bus_a->parent; bus_b = bus_b->parent; if (bus_a && bus_a == bus_b) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 317bdf6dcbef..dcf2453138a5 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -50,14 +50,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) { .flags = FLAG_SOF, - .device = 0x119a, - }, -#endif -/* Broxton-T */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) - { - .flags = FLAG_SOF, - .device = 0x1a98, + .device = PCI_DEVICE_ID_INTEL_SST_TNG, }, #endif /* @@ -68,7 +61,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { .flags = FLAG_SOF, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { .ident = "Up Squared", @@ -82,14 +75,14 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .codec_hid = &essx_83x6, }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) { .flags = FLAG_SST, - .device = 0x5a98, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -110,7 +103,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) { .flags = FLAG_SST, - .device = 0x9d70, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -123,14 +116,14 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = 0x9d70, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, }, #endif /* Kabylake-LP */ #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) { .flags = FLAG_SST, - .device = 0x9d71, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -143,7 +136,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = 0x9d71, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, }, #endif @@ -155,7 +148,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) { .flags = FLAG_SOF, - .device = 0x3198, + .device = PCI_DEVICE_ID_INTEL_HDA_GML, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -168,7 +161,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x3198, + .device = PCI_DEVICE_ID_INTEL_HDA_GML, .codec_hid = &essx_83x6, }, #endif @@ -188,7 +181,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) { .flags = FLAG_SOF, - .device = 0x9dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -207,12 +200,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x09dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x9dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, }, #endif @@ -220,7 +213,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) { .flags = FLAG_SOF, - .device = 0xa348, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -233,7 +226,7 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0xa348, + .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, }, #endif @@ -241,7 +234,7 @@ static const struct config_entry config_table[] = { /* Cometlake-LP */ { .flags = FLAG_SOF, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -267,17 +260,17 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x02c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, }, /* Cometlake-H */ { .flags = FLAG_SOF, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, .dmi_table = (const struct dmi_system_id []) { { .matches = { @@ -296,12 +289,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x06c8, + .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, }, #endif @@ -309,7 +302,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) { .flags = FLAG_SOF, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -322,12 +315,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x34c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, }, #endif @@ -335,7 +328,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) { .flags = FLAG_SOF, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -348,12 +341,12 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4dc8, + .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, }, #endif @@ -361,7 +354,7 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) { .flags = FLAG_SOF, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -380,16 +373,16 @@ static const struct config_entry config_table[] = { }, { .flags = FLAG_SOF, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0xa0c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x43c8, + .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H, }, #endif @@ -397,78 +390,69 @@ static const struct config_entry config_table[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4b55, + .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, - .device = 0x4b58, + .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3, }, #endif -/* Alder Lake */ +/* Alder Lake / Raptor Lake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) - /* Alderlake-S */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7ad0, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S, }, - /* RaptorLake-S */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7a50, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S, }, - /* Alderlake-P */ { .flags = FLAG_SOF, - .device = 0x51c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cd, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX, }, - /* Alderlake-PS */ { .flags = FLAG_SOF, - .device = 0x51c9, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, .codec_hid = &essx_83x6, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51c9, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, }, - /* Alderlake-M */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cc, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, }, - /* Alderlake-N */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x54c8, + .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, }, - /* RaptorLake-P */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ca, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cb, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, }, - /* RaptorLake-M */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51ce, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, }, - /* RaptorLake-PX */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x51cf, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX, }, #endif @@ -477,10 +461,18 @@ static const struct config_entry config_table[] = { /* Meteorlake-P */ { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, - .device = 0x7e28, + .device = PCI_DEVICE_ID_INTEL_HDA_MTL, }, #endif +/* Lunar Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE) + /* Lunarlake-P */ + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, + }, +#endif }; static const struct config_entry *snd_intel_dsp_find_config @@ -549,7 +541,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) const struct config_entry *cfg; /* Intel vendor only */ - if (pci->vendor != 0x8086) + if (pci->vendor != PCI_VENDOR_ID_INTEL) return SND_INTEL_DSP_DRIVER_ANY; /* @@ -557,12 +549,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) * for HDMI/DP support, ignore kernel parameter */ switch (pci->device) { - case 0x160c: /* Broadwell */ - case 0x0a0c: /* Haswell */ - case 0x0c0c: - case 0x0d0c: - case 0x0f04: /* Baytrail */ - case 0x2284: /* Braswell */ + case PCI_DEVICE_ID_INTEL_HDA_BDW: + case PCI_DEVICE_ID_INTEL_HDA_HSW_0: + case PCI_DEVICE_ID_INTEL_HDA_HSW_2: + case PCI_DEVICE_ID_INTEL_HDA_HSW_3: + case PCI_DEVICE_ID_INTEL_HDA_BYT: + case PCI_DEVICE_ID_INTEL_HDA_BSW: return SND_INTEL_DSP_DRIVER_ANY; } diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 886255a03e8b..dd6922267a4b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -130,6 +130,37 @@ config SND_HDA_SCODEC_CS35L41_SPI comment "Set to Y if you want auto-loading the side codec driver" depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m +config SND_HDA_SCODEC_CS35L56 + tristate + +config SND_HDA_SCODEC_CS35L56_I2C + tristate "Build CS35L56 HD-audio side codec support for I2C Bus" + depends on I2C + depends on ACPI || COMPILE_TEST + depends on SND_SOC + select CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CS_DSP_CONTROLS + help + Say Y or M here to include CS35L56 amplifier support with + I2C control. + +config SND_HDA_SCODEC_CS35L56_SPI + tristate "Build CS35L56 HD-audio side codec support for SPI Bus" + depends on SPI_MASTER + depends on ACPI || COMPILE_TEST + depends on SND_SOC + select CS_DSP + select SND_HDA_GENERIC + select SND_SOC_CS35L56_SHARED + select SND_HDA_SCODEC_CS35L56 + select SND_HDA_CS_DSP_CONTROLS + help + Say Y or M here to include CS35L56 amplifier support with + SPI control. + config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 00d306104484..c6e6509e7b8e 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -31,6 +31,9 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o snd-hda-scodec-cs35l41-objs := cs35l41_hda.o snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o +snd-hda-scodec-cs35l56-objs := cs35l56_hda.o +snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o +snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o # common driver @@ -55,6 +58,9 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o +obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o # this must be the last entry after codec drivers; diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c new file mode 100644 index 000000000000..71e95e64f8a4 --- /dev/null +++ b/sound/pci/hda/cs35l56_hda.c @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// HDA audio driver for Cirrus Logic CS35L56 smart amp +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include <linux/acpi.h> +#include <linux/debugfs.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/hda_codec.h> +#include <sound/tlv.h> +#include "cs35l56_hda.h" +#include "hda_component.h" +#include "hda_cs_dsp_ctl.h" +#include "hda_generic.h" + + /* + * The cs35l56_hda_dai_config[] reg sequence configures the device as + * ASP1_BCLK_FREQ = 3.072 MHz + * ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S + * ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots + * ASP1_RX_WL = 24 bits per sample + * ASP1_TX_WL = 24 bits per sample + * ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled + */ +static const struct reg_sequence cs35l56_hda_dai_config[] = { + { CS35L56_ASP1_CONTROL1, 0x00000021 }, + { CS35L56_ASP1_CONTROL2, 0x20200200 }, + { CS35L56_ASP1_CONTROL3, 0x00000003 }, + { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, + { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, + { CS35L56_ASP1_ENABLES1, 0x00000000 }, +}; + +static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) +{ + unsigned int val; + int ret; + + pm_runtime_get_sync(cs35l56->base.dev); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY); + if (ret == 0) { + /* Wait for firmware to enter PS0 power state */ + ret = regmap_read_poll_timeout(cs35l56->base.regmap, + CS35L56_TRANSDUCER_ACTUAL_PS, + val, (val == CS35L56_PS0), + CS35L56_PS0_POLL_US, + CS35L56_PS0_TIMEOUT_US); + if (ret) + dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret); + } + regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1, + BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) | + cs35l56->asp_tx_mask); + cs35l56->playing = true; +} + +static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56) +{ + cs35l56->playing = false; + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE); + regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1, + BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) | + BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) | + BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT)); + + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); +} + +static void cs35l56_hda_playback_hook(struct device *dev, int action) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action); + + switch (action) { + case HDA_GEN_PCM_ACT_PREPARE: + if (cs35l56->playing) + break; + + /* If we're suspended: flag that resume should start playback */ + if (cs35l56->suspended) { + cs35l56->playing = true; + break; + } + + cs35l56_hda_play(cs35l56); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + if (!cs35l56->playing) + break; + + cs35l56_hda_pause(cs35l56); + break; + default: + break; + } +} + +static int __maybe_unused cs35l56_hda_runtime_suspend(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + if (cs35l56->cs_dsp.booted) + cs_dsp_stop(&cs35l56->cs_dsp); + + return cs35l56_runtime_suspend_common(&cs35l56->base); +} + +static int __maybe_unused cs35l56_hda_runtime_resume(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + int ret; + + ret = cs35l56_runtime_resume_common(&cs35l56->base, false); + if (ret < 0) + return ret; + + if (cs35l56->cs_dsp.booted) { + ret = cs_dsp_run(&cs35l56->cs_dsp); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); + goto err; + } + } + + return 0; + +err: + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); + regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + CS35L56_MBOX_CMD_HIBERNATE_NOW); + + regcache_cache_only(cs35l56->base.regmap, true); + + return ret; +} + +static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC; + if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC) + uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1; + strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int reg_val; + int i; + + regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); + reg_val &= CS35L56_ASP_TXn_SRC_MASK; + + for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) { + if (cs35l56_tx_input_values[i] == reg_val) { + ucontrol->value.enumerated.item[0] = i; + break; + } + } + + return 0; +} + +static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int item = ucontrol->value.enumerated.item[0]; + bool changed; + + if (item >= CS35L56_NUM_INPUT_SRC) + return -EINVAL; + + regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, + CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], + &changed); + + return changed; +} + +static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN; + uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX; + return 0; +} + +static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int pos; + int ret; + + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = pos; + + return ret; +} + +static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned long pos = ucontrol->value.integer.value[0]; + bool changed; + int ret; + + if ((pos < CS35L56_MAIN_POSTURE_MIN) || + (pos > CS35L56_MAIN_POSTURE_MAX)) + return -EINVAL; + + ret = regmap_update_bits_check(cs35l56->base.regmap, + CS35L56_MAIN_POSTURE_NUMBER, + CS35L56_MAIN_POSTURE_MASK, + pos, &changed); + if (ret) + return ret; + + return changed; +} + +static const struct { + const char *name; + unsigned int reg; +} cs35l56_hda_mixer_controls[] = { + { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT }, + { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT }, + { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT }, + { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT }, +}; + +static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0); + +static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.step = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX - + CS35L56_MAIN_RENDER_USER_VOLUME_MIN; + + return 0; +} + +static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + unsigned int raw_vol; + int vol; + int ret; + + ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol); + + if (ret) + return ret; + + vol = (s16)(raw_vol & 0xFFFF); + vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; + + if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT)) + vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1)); + + ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN; + + return 0; +} + +static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + long vol = ucontrol->value.integer.value[0]; + unsigned int raw_vol; + bool changed; + int ret; + + if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX - + CS35L56_MAIN_RENDER_USER_VOLUME_MIN))) + return -EINVAL; + + raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) << + CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; + + ret = regmap_update_bits_check(cs35l56->base.regmap, + CS35L56_MAIN_RENDER_USER_VOLUME, + CS35L56_MAIN_RENDER_USER_VOLUME_MASK, + raw_vol, &changed); + if (ret) + return ret; + + return changed; +} + +static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56) +{ + struct snd_kcontrol_new ctl_template = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = cs35l56_hda_posture_info, + .get = cs35l56_hda_posture_get, + .put = cs35l56_hda_posture_put, + }; + char name[64]; + int i; + + snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name); + ctl_template.name = name; + cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl)) + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name); + + /* Mixer controls */ + ctl_template.info = cs35l56_hda_mixer_info; + ctl_template.get = cs35l56_hda_mixer_get; + ctl_template.put = cs35l56_hda_mixer_put; + + BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls)); + + for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) { + snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name, + cs35l56_hda_mixer_controls[i].name); + ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg; + cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) { + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", + ctl_template.name); + } + } + + ctl_template.info = cs35l56_hda_vol_info; + ctl_template.get = cs35l56_hda_vol_get; + ctl_template.put = cs35l56_hda_vol_put; + ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ); + ctl_template.tlv.p = cs35l56_hda_vol_tlv; + snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name); + ctl_template.name = name; + cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56); + if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl)) + dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name); +} + +static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56) +{ + int i; + + for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--) + snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]); + + snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl); + snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl); +} + +static const struct cs_dsp_client_ops cs35l56_hda_client_ops = { + .control_remove = hda_cs_dsp_control_remove, +}; + +static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56, + const struct firmware **firmware, char **filename, + const char *dir, const char *system_name, + const char *amp_name, + const char *filetype) +{ + char *s, c; + int ret = 0; + + if (system_name && amp_name) + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s-%s.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + system_name, amp_name, filetype); + else if (system_name) + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + system_name, filetype); + else + *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc.%s", dir, + cs35l56->base.secured ? "s" : "", cs35l56->base.rev, + filetype); + + if (!*filename) + return -ENOMEM; + + /* + * Make sure that filename is lower-case and any non alpha-numeric + * characters except full stop and forward slash are replaced with + * hyphens. + */ + s = *filename; + while (*s) { + c = *s; + if (isalnum(c)) + *s = tolower(c); + else if (c != '.' && c != '/') + *s = '-'; + s++; + } + + ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev); + if (ret) { + dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename); + kfree(*filename); + *filename = NULL; + return ret; + } + + dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename); + + return 0; +} + +static const char cirrus_dir[] = "cirrus/"; +static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56, + const struct firmware **wmfw_firmware, + char **wmfw_filename, + const struct firmware **coeff_firmware, + char **coeff_filename) +{ + const char *system_name = cs35l56->system_name; + const char *amp_name = cs35l56->amp_name; + int ret; + + if (system_name && amp_name) { + if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, amp_name, "wmfw")) { + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, amp_name, "bin"); + return; + } + } + + if (system_name) { + if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, system_name, NULL, "wmfw")) { + if (amp_name) + cs35l56_hda_request_firmware_file(cs35l56, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + amp_name, "bin"); + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, + coeff_firmware, coeff_filename, + cirrus_dir, system_name, + NULL, "bin"); + return; + } + } + + ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename, + cirrus_dir, NULL, NULL, "wmfw"); + if (!ret) { + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); + return; + } + + /* When a firmware file is not found must still search for the coeff files */ + if (system_name) { + if (amp_name) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, amp_name, "bin"); + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, system_name, NULL, "bin"); + } + + if (!*coeff_firmware) + cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename, + cirrus_dir, NULL, NULL, "bin"); +} + +static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware, + char *wmfw_filename, + const struct firmware *coeff_firmware, + char *coeff_filename) +{ + if (wmfw_firmware) + release_firmware(wmfw_firmware); + kfree(wmfw_filename); + + if (coeff_firmware) + release_firmware(coeff_firmware); + kfree(coeff_filename); +} + +static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56) +{ + struct hda_cs_dsp_ctl_info info; + + info.device_name = cs35l56->amp_name; + info.fw_type = HDA_CS_DSP_FW_MISC; + info.card = cs35l56->codec->card; + + hda_cs_dsp_add_controls(&cs35l56->cs_dsp, &info); +} + +static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) +{ + const struct firmware *coeff_firmware = NULL; + const struct firmware *wmfw_firmware = NULL; + char *coeff_filename = NULL; + char *wmfw_filename = NULL; + int ret = 0; + + cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + + /* Nothing to do - no firmware files were found to download */ + if (!wmfw_filename && !coeff_filename) + return 0; + + mutex_lock(&cs35l56->base.irq_lock); + pm_runtime_get_sync(cs35l56->base.dev); + + /* + * When the device is running in secure mode the firmware files can + * only contain insecure tunings and therefore we do not need to + * shutdown the firmware to apply them and can use the lower cost + * reinit sequence instead. + */ + if (!cs35l56->base.secured) { + ret = cs35l56_firmware_shutdown(&cs35l56->base); + if (ret) + goto err; + } + + ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename, "misc"); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret); + goto err; + } + + if (wmfw_filename) + dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename); + + if (coeff_filename) + dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename); + + ret = cs_dsp_run(&cs35l56->cs_dsp); + if (ret) { + dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret); + goto err; + } + + if (cs35l56->base.secured) { + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); + if (ret) + goto err; + } else { + /* Reset the device and wait for it to boot */ + cs35l56_system_reset(&cs35l56->base, false); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); + if (ret) + goto err; + } + + /* Disable auto-hibernate so that runtime_pm has control */ + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + regcache_mark_dirty(cs35l56->base.regmap); + regcache_sync(cs35l56->base.regmap); + + regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, + CS35L56_FIRMWARE_MISSING); + cs35l56->base.fw_patched = true; +err: + pm_runtime_put(cs35l56->base.dev); + mutex_unlock(&cs35l56->base.irq_lock); + + cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, + coeff_firmware, coeff_filename); + + return ret; +} + +static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + int ret; + + if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS) + return -EINVAL; + + comps = &comps[cs35l56->index]; + if (comps->dev) + return -EBUSY; + + comps->dev = dev; + cs35l56->codec = comps->codec; + strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + comps->playback_hook = cs35l56_hda_playback_hook; + + ret = cs35l56_hda_fw_load(cs35l56); + if (ret) + return ret; + + cs35l56_hda_create_controls(cs35l56); + cs35l56_hda_add_dsp_controls(cs35l56); + +#if IS_ENABLED(CONFIG_SND_DEBUG) + cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root); + cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root); +#endif + + dev_dbg(cs35l56->base.dev, "Bound\n"); + + return 0; +} + +static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; + + cs35l56_hda_remove_controls(cs35l56); + +#if IS_ENABLED(CONFIG_SND_DEBUG) + cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp); + debugfs_remove_recursive(cs35l56->debugfs_root); +#endif + + cs_dsp_remove(&cs35l56->cs_dsp); + + if (comps[cs35l56->index].dev == dev) + memset(&comps[cs35l56->index], 0, sizeof(*comps)); + + dev_dbg(cs35l56->base.dev, "Unbound\n"); +} + +static const struct component_ops cs35l56_hda_comp_ops = { + .bind = cs35l56_hda_bind, + .unbind = cs35l56_hda_unbind, +}; + +static int cs35l56_hda_system_suspend(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + if (cs35l56->playing) + cs35l56_hda_pause(cs35l56); + + cs35l56->suspended = true; + + /* + * The interrupt line is normally shared, but after we start suspending + * we can't check if our device is the source of an interrupt, and can't + * clear it. Prevent this race by temporarily disabling the parent irq + * until we reach _no_irq. + */ + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); + + return pm_runtime_force_suspend(dev); +} + +static int cs35l56_hda_system_suspend_late(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* + * RESET is usually shared by all amps so it must not be asserted until + * all driver instances have done their suspend() stage. + */ + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + } + + return 0; +} + +static int cs35l56_hda_system_suspend_no_irq(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */ + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); + + return 0; +} + +static int cs35l56_hda_system_resume_no_irq(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* + * WAKE interrupts unmask if the CS35L56 hibernates, which can cause + * spurious interrupts, and the interrupt line is normally shared. + * We can't check if our device is the source of an interrupt, and can't + * clear it, until it has fully resumed. Prevent this race by temporarily + * disabling the parent irq until we complete resume(). + */ + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); + + return 0; +} + +static int cs35l56_hda_system_resume_early(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + /* Ensure a spec-compliant RESET pulse. */ + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + + /* Release shared RESET before drivers start resume(). */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); + cs35l56_wait_control_port_ready(); + } + + return 0; +} + +static int cs35l56_hda_system_resume(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + int ret; + + /* Undo pm_runtime_force_suspend() before re-enabling the irq */ + ret = pm_runtime_force_resume(dev); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); + + if (ret) + return ret; + + cs35l56->suspended = false; + + ret = cs35l56_is_fw_reload_needed(&cs35l56->base); + dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); + if (ret > 0) { + ret = cs35l56_hda_fw_load(cs35l56); + if (ret) + return ret; + } + + if (cs35l56->playing) + cs35l56_hda_play(cs35l56); + + return 0; +} + +static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) +{ + u32 values[HDA_MAX_COMPONENTS]; + struct acpi_device *adev; + const char *property, *sub; + size_t nval; + int i, ret; + + /* + * ACPI_COMPANION isn't available when this driver was instantiated by + * the serial-multi-instantiate driver, so lookup the node by HID + */ + if (!ACPI_COMPANION(cs35l56->base.dev)) { + adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1); + if (!adev) { + dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n", + dev_name(cs35l56->base.dev)); + return -ENODEV; + } + ACPI_COMPANION_SET(cs35l56->base.dev, adev); + } + + property = "cirrus,dev-index"; + ret = device_property_count_u32(cs35l56->base.dev, property); + if (ret <= 0) + goto err; + + if (ret > ARRAY_SIZE(values)) { + ret = -EINVAL; + goto err; + } + nval = ret; + + ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); + if (ret) + goto err; + + cs35l56->index = -1; + for (i = 0; i < nval; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; + } + } + if (cs35l56->index == -1) { + dev_err(cs35l56->base.dev, "No index found in %s\n", property); + ret = -ENODEV; + goto err; + } + + sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); + + if (IS_ERR(sub)) { + /* If no ACPI SUB, return 0 and fallback to legacy firmware path, otherwise fail */ + if (PTR_ERR(sub) == -ENODATA) + return 0; + else + return PTR_ERR(sub); + } + + cs35l56->system_name = sub; + + cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev, + "reset", + cs35l56->index, + GPIOD_OUT_LOW); + if (IS_ERR(cs35l56->base.reset_gpio)) { + ret = PTR_ERR(cs35l56->base.reset_gpio); + + /* + * If RESET is shared the first amp to probe will grab the reset + * line and reset all the amps + */ + if (ret != -EBUSY) + return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n"); + + dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n"); + cs35l56->base.reset_gpio = NULL; + } + + return 0; + +err: + dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret); + + return ret; +} + +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) +{ + int ret; + + mutex_init(&cs35l56->base.irq_lock); + dev_set_drvdata(cs35l56->base.dev, cs35l56); + + ret = cs35l56_hda_read_acpi(cs35l56, id); + if (ret) { + dev_err_probe(cs35l56->base.dev, ret, "Platform not supported\n"); + goto err; + } + + cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d", + cs35l56->index + 1); + if (!cs35l56->amp_name) { + ret = -ENOMEM; + goto err; + } + + cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp); + cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops; + + if (cs35l56->base.reset_gpio) { + dev_dbg(cs35l56->base.dev, "Hard reset\n"); + + /* + * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the + * ACPI defines a different default state. So explicitly set low. + */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + cs35l56_wait_min_reset_pulse(); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); + } + + ret = cs35l56_hw_init(&cs35l56->base); + if (ret < 0) + goto err; + + /* Reset the device and wait for it to boot */ + cs35l56_system_reset(&cs35l56->base, false); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); + if (ret) + goto err; + + ret = cs35l56_set_patch(&cs35l56->base); + if (ret) + return ret; + + regcache_mark_dirty(cs35l56->base.regmap); + regcache_sync(cs35l56->base.regmap); + + /* Disable auto-hibernate so that runtime_pm has control */ + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + ret = cs_dsp_halo_init(&cs35l56->cs_dsp); + if (ret) { + dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n"); + goto err; + } + + dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n", + cs35l56->system_name, cs35l56->amp_name); + + regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config, + ARRAY_SIZE(cs35l56_hda_dai_config)); + + /* + * By default only enable one ASP1TXn, where n=amplifier index, + * This prevents multiple amps trying to drive the same slot. + */ + cs35l56->asp_tx_mask = BIT(cs35l56->index); + + pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000); + pm_runtime_use_autosuspend(cs35l56->base.dev); + pm_runtime_set_active(cs35l56->base.dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_enable(cs35l56->base.dev); + + ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops); + if (ret) { + dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret); + goto pm_err; + } + + cs35l56->base.init_done = true; + + return 0; + +pm_err: + pm_runtime_disable(cs35l56->base.dev); +err: + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56); + +void cs35l56_hda_remove(struct device *dev) +{ + struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + + pm_runtime_get_sync(cs35l56->base.dev); + pm_runtime_disable(cs35l56->base.dev); + + component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + + kfree(cs35l56->system_name); + pm_runtime_put_noidle(cs35l56->base.dev); + + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56); + +const struct dev_pm_ops cs35l56_hda_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume) + LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late, + cs35l56_hda_system_resume_early) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq, + cs35l56_hda_system_resume_no_irq) +}; +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56); + +MODULE_DESCRIPTION("CS35L56 HDA Driver"); +MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(FW_CS_DSP); diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h new file mode 100644 index 000000000000..6e5bc5397db5 --- /dev/null +++ b/sound/pci/hda/cs35l56_hda.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * HDA audio driver for Cirrus Logic CS35L56 smart amp + * + * Copyright (C) 2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef __CS35L56_HDA_H__ +#define __CS35L56_HDA_H__ + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/firmware/cirrus/cs_dsp.h> +#include <linux/firmware/cirrus/wmfw.h> +#include <linux/regulator/consumer.h> +#include <sound/cs35l56.h> + +struct dentry; + +struct cs35l56_hda { + struct cs35l56_base base; + struct hda_codec *codec; + + int index; + const char *system_name; + const char *amp_name; + + struct cs_dsp cs_dsp; + bool playing; + bool suspended; + u8 asp_tx_mask; + + struct snd_kcontrol *posture_ctl; + struct snd_kcontrol *volume_ctl; + struct snd_kcontrol *mixer_ctl[4]; + +#if IS_ENABLED(CONFIG_SND_DEBUG) + struct dentry *debugfs_root; +#endif +}; + +extern const struct dev_pm_ops cs35l56_hda_pm_ops; + +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id); +void cs35l56_hda_remove(struct device *dev); + +#endif /*__CS35L56_HDA_H__*/ diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c new file mode 100644 index 000000000000..83e4acdd89ac --- /dev/null +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// CS35L56 HDA audio driver I2C binding +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include "cs35l56_hda.h" + +static int cs35l56_hda_i2c_probe(struct i2c_client *clt) +{ + struct cs35l56_hda *cs35l56; + int ret; + + cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL); + if (!cs35l56) + return -ENOMEM; + + cs35l56->base.dev = &clt->dev; + cs35l56->base.can_hibernate = true; + cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = cs35l56_hda_common_probe(cs35l56, clt->addr); + if (ret) + return ret; + ret = cs35l56_irq_request(&cs35l56->base, clt->irq); + if (ret < 0) + cs35l56_hda_remove(cs35l56->base.dev); + + return ret; +} + +static void cs35l56_hda_i2c_remove(struct i2c_client *clt) +{ + cs35l56_hda_remove(&clt->dev); +} + +static const struct i2c_device_id cs35l56_hda_i2c_id[] = { + { "cs35l56-hda", 0 }, + {} +}; + +static struct i2c_driver cs35l56_hda_i2c_driver = { + .driver = { + .name = "cs35l56-hda", + .pm = &cs35l56_hda_pm_ops, + }, + .id_table = cs35l56_hda_i2c_id, + .probe = cs35l56_hda_i2c_probe, + .remove = cs35l56_hda_i2c_remove, +}; +module_i2c_driver(cs35l56_hda_i2c_driver); + +MODULE_DESCRIPTION("HDA CS35L56 I2C driver"); +MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c new file mode 100644 index 000000000000..756aec342eab --- /dev/null +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// CS35L56 HDA audio driver SPI binding +// +// Copyright (C) 2023 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "cs35l56_hda.h" + +static int cs35l56_hda_spi_probe(struct spi_device *spi) +{ + struct cs35l56_hda *cs35l56; + int ret; + + cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL); + if (!cs35l56) + return -ENOMEM; + + cs35l56->base.dev = &spi->dev; + cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = cs35l56_hda_common_probe(cs35l56, spi->chip_select); + if (ret) + return ret; + ret = cs35l56_irq_request(&cs35l56->base, spi->irq); + if (ret < 0) + cs35l56_hda_remove(cs35l56->base.dev); + + return ret; +} + +static void cs35l56_hda_spi_remove(struct spi_device *spi) +{ + cs35l56_hda_remove(&spi->dev); +} + +static const struct spi_device_id cs35l56_hda_spi_id[] = { + { "cs35l56-hda", 0 }, + {} +}; + +static struct spi_driver cs35l56_hda_spi_driver = { + .driver = { + .name = "cs35l56-hda", + .pm = &cs35l56_hda_pm_ops, + }, + .id_table = cs35l56_hda_spi_id, + .probe = cs35l56_hda_spi_probe, + .remove = cs35l56_hda_spi_remove, +}; +module_spi_driver(cs35l56_hda_spi_driver); + +MODULE_DESCRIPTION("HDA CS35L56 SPI driver"); +MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); +MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index df63d66af1ab..579b11beac71 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -8,6 +8,8 @@ #ifndef __SOUND_HDA_AUTO_PARSER_H #define __SOUND_HDA_AUTO_PARSER_H +#include "hda_local.h" + /* * Helper for automatic pin configuration */ diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 34eba40cc6e6..a8eea8367629 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -9,6 +9,9 @@ #define __SOUND_HDA_GENERIC_H #include <linux/leds.h> +#include "hda_auto_parser.h" + +struct hda_jack_callback; /* table entry for multi-io paths */ struct hda_multi_io { diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ef831770ca7d..765d95e79861 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -330,18 +330,6 @@ enum { #define needs_eld_notify_link(chip) false #endif -#define CONTROLLER_IN_GPU(pci) (((pci)->vendor == 0x8086) && \ - (((pci)->device == 0x0a0c) || \ - ((pci)->device == 0x0c0c) || \ - ((pci)->device == 0x0d0c) || \ - ((pci)->device == 0x160c) || \ - ((pci)->device == 0x490d) || \ - ((pci)->device == 0x4f90) || \ - ((pci)->device == 0x4f91) || \ - ((pci)->device == 0x4f92))) - -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) - static const char * const driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -573,7 +561,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ - if (IS_BXT(pci)) + if (HDA_CONTROLLER_IS_APL(pci)) bxt_reduce_dma_latency(chip); if (bus->mlcap != NULL) @@ -2175,7 +2163,7 @@ static int azx_probe(struct pci_dev *pci, #endif /* CONFIG_SND_HDA_PATCH_LOADER */ #ifndef CONFIG_SND_HDA_I915 - if (CONTROLLER_IN_GPU(pci)) + if (HDA_CONTROLLER_IN_GPU(pci)) dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n"); #endif @@ -2283,7 +2271,7 @@ static int azx_probe_continue(struct azx *chip) * for other chips, still continue probing as other * codecs can be on the same link. */ - if (CONTROLLER_IN_GPU(pci)) { + if (HDA_CONTROLLER_IN_GPU(pci)) { dev_err(chip->card->dev, "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n"); goto out_free; @@ -2294,7 +2282,7 @@ static int azx_probe_continue(struct azx *chip) } /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) + if (HDA_CONTROLLER_IN_GPU(pci)) hda->need_i915_power = true; } @@ -2428,333 +2416,262 @@ static void azx_shutdown(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id azx_ids[] = { /* CPT */ - { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_CPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* PBG */ - { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_PBG, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Panther Point */ - { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_PPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Lynx Point */ - { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* 9 Series */ - { PCI_DEVICE(0x8086, 0x8ca0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_9_SERIES, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Wellsburg */ - { PCI_DEVICE(0x8086, 0x8d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, - { PCI_DEVICE(0x8086, 0x8d21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_WBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, + { PCI_DEVICE_DATA(INTEL, HDA_WBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Lewisburg */ - { PCI_DEVICE(0x8086, 0xa1f0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, - { PCI_DEVICE(0x8086, 0xa270), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_LBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_LBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lynx Point-LP */ - { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Lynx Point-LP */ - { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, /* Wildcat Point-LP */ - { PCI_DEVICE(0x8086, 0x9ca0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, - /* Sunrise Point */ - { PCI_DEVICE(0x8086, 0xa170), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_WPT_LP, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) }, + /* Skylake (Sunrise Point) */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Skylake-LP (Sunrise Point-LP) */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake */ - { PCI_DEVICE(0x8086, 0xa171), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake-LP */ - { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Kabylake-H */ - { PCI_DEVICE(0x8086, 0xa2f0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Coffelake */ - { PCI_DEVICE(0x8086, 0xa348), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Cannonlake */ - { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-LP */ - { PCI_DEVICE(0x8086, 0x02C8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-H */ - { PCI_DEVICE(0x8086, 0x06C8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0xf1c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-S */ - { PCI_DEVICE(0x8086, 0xa3f0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* CometLake-R */ - { PCI_DEVICE(0x8086, 0xf0c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_R, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Icelake */ - { PCI_DEVICE(0x8086, 0x34c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Icelake-H */ - { PCI_DEVICE(0x8086, 0x3dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Jasperlake */ - { PCI_DEVICE(0x8086, 0x38c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Tigerlake */ - { PCI_DEVICE(0x8086, 0xa0c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Tigerlake-H */ - { PCI_DEVICE(0x8086, 0x43c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* DG1 */ - { PCI_DEVICE(0x8086, 0x490d), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_DG1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* DG2 */ - { PCI_DEVICE(0x8086, 0x4f90), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4f91), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4f92), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_DG2_2, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-S */ - { PCI_DEVICE(0x8086, 0x7ad0), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-P */ - { PCI_DEVICE(0x8086, 0x51c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51c9), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cd), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-M */ - { PCI_DEVICE(0x8086, 0x51cc), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Alderlake-N */ - { PCI_DEVICE(0x8086, 0x54c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Elkhart Lake */ - { PCI_DEVICE(0x8086, 0x4b55), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x4b58), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Raptor Lake */ - { PCI_DEVICE(0x8086, 0x7a50), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51ca), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cb), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51ce), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - { PCI_DEVICE(0x8086, 0x51cf), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - /* Meteorlake-P */ - { PCI_DEVICE(0x8086, 0x7e28), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lunarlake-P */ - { PCI_DEVICE(0x8086, 0xa828), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, - /* Broxton-P(Apollolake) */ - { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, - /* Broxton-T */ - { PCI_DEVICE(0x8086, 0x1a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Arrow Lake-S */ + { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Apollolake (Broxton-P) */ + { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ - { PCI_DEVICE(0x8086, 0x3198), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Haswell */ - { PCI_DEVICE(0x8086, 0x0a0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, - { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, - { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_0, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_2, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, + { PCI_DEVICE_DATA(INTEL, HDA_HSW_3, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) }, /* Broadwell */ - { PCI_DEVICE(0x8086, 0x160c), - .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_BDW, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL) }, /* 5 Series/3400 */ - { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, - { PCI_DEVICE(0x8086, 0x3b57), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_0, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) }, + { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_1, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) }, /* Poulsbo */ - { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE | - AZX_DCAPS_POSFIX_LPIB }, + { PCI_DEVICE_DATA(INTEL, HDA_POULSBO, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE | + AZX_DCAPS_POSFIX_LPIB) }, /* Oaktrail */ - { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, + { PCI_DEVICE_DATA(INTEL, HDA_OAKTRAIL, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE) }, /* BayTrail */ - { PCI_DEVICE(0x8086, 0x0f04), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL }, + { PCI_DEVICE_DATA(INTEL, HDA_BYT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL) }, /* Braswell */ - { PCI_DEVICE(0x8086, 0x2284), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL }, + { PCI_DEVICE_DATA(INTEL, HDA_BSW, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL) }, /* ICH6 */ - { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH6, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH7 */ - { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH7, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ESB2 */ - { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ESB2, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH8 */ - { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH8, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH9_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH9 */ - { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH9_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH10_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* ICH10 */ - { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + { PCI_DEVICE_DATA(INTEL, HDA_ICH10_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) }, /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE }, /* ATI SB 450/600/700/800/900 */ - { PCI_DEVICE(0x1002, 0x437b), + { PCI_VDEVICE(ATI, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, - { PCI_DEVICE(0x1002, 0x4383), + { PCI_VDEVICE(ATI, 0x4383), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, /* AMD Hudson */ - { PCI_DEVICE(0x1022, 0x780d), + { PCI_VDEVICE(AMD, 0x780d), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB }, /* AMD, X370 & co */ - { PCI_DEVICE(0x1022, 0x1457), + { PCI_VDEVICE(AMD, 0x1457), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* AMD, X570 & co */ - { PCI_DEVICE(0x1022, 0x1487), + { PCI_VDEVICE(AMD, 0x1487), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* AMD Stoney */ - { PCI_DEVICE(0x1022, 0x157a), + { PCI_VDEVICE(AMD, 0x157a), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB | AZX_DCAPS_PM_RUNTIME }, /* AMD Raven */ - { PCI_DEVICE(0x1022, 0x15e3), + { PCI_VDEVICE(AMD, 0x15e3), .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB }, /* ATI HDMI */ - { PCI_DEVICE(0x1002, 0x0002), + { PCI_VDEVICE(ATI, 0x0002), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0x1308), + { PCI_VDEVICE(ATI, 0x1308), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x157a), + { PCI_VDEVICE(ATI, 0x157a), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x15b3), + { PCI_VDEVICE(ATI, 0x15b3), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0x793b), + { PCI_VDEVICE(ATI, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x7919), + { PCI_VDEVICE(ATI, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x960f), + { PCI_VDEVICE(ATI, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x970f), + { PCI_VDEVICE(ATI, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x9840), + { PCI_VDEVICE(ATI, 0x9840), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaa00), + { PCI_VDEVICE(ATI, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa08), + { PCI_VDEVICE(ATI, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa10), + { PCI_VDEVICE(ATI, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa18), + { PCI_VDEVICE(ATI, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa20), + { PCI_VDEVICE(ATI, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa28), + { PCI_VDEVICE(ATI, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa30), + { PCI_VDEVICE(ATI, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa38), + { PCI_VDEVICE(ATI, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa40), + { PCI_VDEVICE(ATI, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa48), + { PCI_VDEVICE(ATI, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa50), + { PCI_VDEVICE(ATI, 0xaa50), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa58), + { PCI_VDEVICE(ATI, 0xaa58), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa60), + { PCI_VDEVICE(ATI, 0xaa60), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa68), + { PCI_VDEVICE(ATI, 0xaa68), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa80), + { PCI_VDEVICE(ATI, 0xaa80), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa88), + { PCI_VDEVICE(ATI, 0xaa88), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa90), + { PCI_VDEVICE(ATI, 0xaa90), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0xaa98), + { PCI_VDEVICE(ATI, 0xaa98), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, - { PCI_DEVICE(0x1002, 0x9902), + { PCI_VDEVICE(ATI, 0x9902), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaaa0), + { PCI_VDEVICE(ATI, 0xaaa0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaaa8), + { PCI_VDEVICE(ATI, 0xaaa8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaab0), + { PCI_VDEVICE(ATI, 0xaab0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaac0), + { PCI_VDEVICE(ATI, 0xaac0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaac8), + { PCI_VDEVICE(ATI, 0xaac8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaad8), + { PCI_VDEVICE(ATI, 0xaad8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaae0), + { PCI_VDEVICE(ATI, 0xaae0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaae8), + { PCI_VDEVICE(ATI, 0xaae8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaaf0), + { PCI_VDEVICE(ATI, 0xaaf0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xaaf8), + { PCI_VDEVICE(ATI, 0xaaf8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab00), + { PCI_VDEVICE(ATI, 0xab00), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab08), + { PCI_VDEVICE(ATI, 0xab08), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab10), + { PCI_VDEVICE(ATI, 0xab10), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab18), + { PCI_VDEVICE(ATI, 0xab18), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab20), + { PCI_VDEVICE(ATI, 0xab20), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab28), + { PCI_VDEVICE(ATI, 0xab28), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab30), + { PCI_VDEVICE(ATI, 0xab30), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, - { PCI_DEVICE(0x1002, 0xab38), + { PCI_VDEVICE(ATI, 0xab38), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, /* GLENFLY */ @@ -2764,15 +2681,15 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, + { PCI_VDEVICE(VIA, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */ - { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ - { PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, /* SIS966 */ - { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS }, + { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ - { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, + { PCI_VDEVICE(AL, 0x5461), .driver_data = AZX_DRIVER_ULI }, /* NVIDIA MCP */ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2785,9 +2702,9 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, /* Creative X-Fi (CA0110-IBG) */ /* CTHDA chips */ - { PCI_DEVICE(0x1102, 0x0010), + { PCI_VDEVICE(CREATIVE, 0x0010), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, - { PCI_DEVICE(0x1102, 0x0012), + { PCI_VDEVICE(CREATIVE, 0x0012), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, #if !IS_ENABLED(CONFIG_SND_CTXFI) /* the following entry conflicts with snd-ctxfi driver, @@ -2801,18 +2718,18 @@ static const struct pci_device_id azx_ids[] = { AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), + { PCI_VDEVICE(CREATIVE, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #endif /* CM8888 */ - { PCI_DEVICE(0x13f6, 0x5011), + { PCI_VDEVICE(CMEDIA, 0x5011), .driver_data = AZX_DRIVER_CMEDIA | AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF }, /* Vortex86MX */ - { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(RDC, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, /* VMware HDAudio */ - { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VMWARE, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2823,11 +2740,11 @@ static const struct pci_device_id azx_ids[] = { .class_mask = 0xffffff, .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, /* Zhaoxin */ - { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, + { PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, /* Loongson HDAudio*/ - {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), + { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), .driver_data = AZX_DRIVER_LOONGSON }, - {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), + { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), .driver_data = AZX_DRIVER_LOONGSON }, { 0, } }; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index bfa9622e1ab1..439fa631c342 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -38,6 +38,17 @@ config SND_SOC_TOPOLOGY bool select SND_DYNAMIC_MINORS +config SND_SOC_TOPOLOGY_BUILD + bool "Build topology core" + select SND_SOC_TOPOLOGY + depends on KUNIT + help + This option exists to facilitate running the KUnit tests for + the topology core, KUnit is frequently tested in virtual + environments with minimal drivers enabled but the topology + core is usually selected by drivers. There is little reason + to enable it if not doing a KUnit build. + config SND_SOC_TOPOLOGY_KUNIT_TEST tristate "KUnit tests for SoC topology" depends on KUNIT diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index d5b6f5187f8e..7b2563075743 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axi_i2s_dai_ops = { + .probe = axi_i2s_dai_probe, .startup = axi_i2s_startup, .shutdown = axi_i2s_shutdown, .trigger = axi_i2s_trigger, @@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = { }; static struct snd_soc_dai_driver axi_i2s_dai = { - .probe = axi_i2s_dai_probe, .ops = &axi_i2s_dai_ops, .symmetric_rate = 1, }; diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index e4c99bbc9cdd..10545bd99704 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops axi_spdif_dai_ops = { + .probe = axi_spdif_dai_probe, .startup = axi_spdif_startup, .shutdown = axi_spdif_shutdown, .trigger = axi_spdif_trigger, @@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = { }; static struct snd_soc_dai_driver axi_spdif_dai = { - .probe = axi_spdif_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 1dd8579e8034..273688c05317 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -79,14 +79,15 @@ config SND_SOC_AMD_ACP5x ACP DMA driver, CPU DAI driver. config SND_SOC_AMD_VANGOGH_MACH - tristate "AMD Vangogh support for NAU8821 CS35L41" + tristate "AMD Vangogh support for NAU8821/CS35L41/MAX98388" select SND_SOC_NAU8821 select SND_SOC_CS35L41_SPI + select SND_SOC_MAX98388 select SND_AMD_ACP_CONFIG depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER help This option enables machine driver for Vangogh platform - using NAU8821 and CS35L41 codecs. + using NAU8821 and either CS35L41 or MAX98388 codecs. Say m if you have such a device. If unsure select "N". diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 0932473b6394..f27c27580009 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -47,6 +47,20 @@ static const struct config_entry config_table[] = { {} }, }, + { + .flags = FLAG_AMD_SOF, + .device = ACP_PCI_DEV_ID, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + }, + {} + }, + }, }; int snd_amd_acp_find_config(struct pci_dev *pci) @@ -82,6 +96,11 @@ static struct snd_soc_acpi_codecs amp_max = { .codecs = {"MX98360A"} }; +static struct snd_soc_acpi_codecs amp_max98388 = { + .num_codecs = 1, + .codecs = {"ADS8388"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { { .id = "10EC5682", @@ -130,6 +149,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[] = { + { + .id = "NVTN2020", + .drv_name = "nau8821-max", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max98388, + .fw_filename = "sof-vangogh.ri", + .sof_tplg_filename = "sof-vangogh-nau8821-max.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_vangogh_sof_machines); + struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = { { .id = "AMDI1019", diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 7464ca2b596c..9e3133bec2b1 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -28,6 +28,21 @@ #define RT5682_PLL_FREQ (48000 * 512) static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; static struct clk *rt5682_dai_wclk; @@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(da7219_dai_bclk)) return PTR_ERR(da7219_dai_bclk); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) if (IS_ERR(rt5682_dai_bclk)) return PTR_ERR(rt5682_dai_bclk); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; @@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { static const struct snd_soc_dapm_widget cz_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), }; @@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = { static const struct snd_kcontrol_new cz_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), }; diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c index 532aa98a2241..c8ed1e0b1ccd 100644 --- a/sound/soc/amd/acp-rt5645.c +++ b/sound/soc/amd/acp-rt5645.c @@ -42,6 +42,16 @@ #define CZ_PLAT_CLK 24000000 static struct snd_soc_jack cz_jack; +static struct snd_soc_jack_pin cz_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int cz_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -76,11 +86,13 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd) codec = asoc_rtd_to_codec(rtd, 0)->component; card = rtd->card; - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cz_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, + cz_jack_pins, + ARRAY_SIZE(cz_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index ce0037810743..631cdf96d637 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -18,6 +18,9 @@ if SND_SOC_AMD_ACP_COMMON config SND_SOC_AMD_ACP_PDM tristate +config SND_SOC_AMD_ACP_LEGACY_COMMON + tristate + config SND_SOC_AMD_ACP_I2S tristate @@ -27,6 +30,7 @@ config SND_SOC_AMD_ACP_PCM config SND_SOC_AMD_ACP_PCI tristate "AMD ACP PCI Driver Support" + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This options enables generic PCI driver for ACP device. @@ -36,6 +40,7 @@ config SND_AMD_ASOC_RENOIR select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This option enables Renoir I2S support on AMD platform. @@ -45,6 +50,7 @@ config SND_AMD_ASOC_REMBRANDT select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON depends on X86 && PCI help This option enables Rembrandt I2S support on AMD platform. @@ -61,6 +67,8 @@ config SND_SOC_AMD_MACH_COMMON select SND_SOC_MAX98357A select SND_SOC_RT5682S select SND_SOC_NAU8825 + select SND_SOC_NAU8821 + select SND_SOC_MAX98388 help This option enables common Machine driver module for ACP. diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index d9abb0ee5218..4e65fdbc8dca 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -8,6 +8,7 @@ snd-acp-pcm-objs := acp-platform.o snd-acp-i2s-objs := acp-i2s.o snd-acp-pdm-objs := acp-pdm.o +snd-acp-legacy-common-objs := acp-legacy-common.o snd-acp-pci-objs := acp-pci.o #platform specific driver @@ -22,6 +23,7 @@ snd-acp-sof-mach-objs := acp-sof-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o +obj-$(CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON) += snd-acp-legacy-common.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 09b6511c0a26..df350014966a 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -149,6 +149,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } + adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution; } else { switch (dai->driver->id) { case I2S_BT_INSTANCE: @@ -167,6 +168,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } + adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution; } val = readl(adata->acp_base + reg_val); @@ -537,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .startup = acp_i2s_startup, - .hw_params = acp_i2s_hwparams, - .prepare = acp_i2s_prepare, - .trigger = acp_i2s_trigger, - .set_fmt = acp_i2s_set_fmt, - .set_tdm_slot = acp_i2s_set_tdm_slot, -}; -EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); - -int asoc_acp_i2s_probe(struct snd_soc_dai *dai) +static int acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); @@ -567,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON); + +const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { + .probe = acp_i2s_probe, + .startup = acp_i2s_startup, + .hw_params = acp_i2s_hwparams, + .prepare = acp_i2s_prepare, + .trigger = acp_i2s_trigger, + .set_fmt = acp_i2s_set_fmt, + .set_tdm_slot = acp_i2s_set_tdm_slot, +}; +EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c new file mode 100644 index 000000000000..ba58165cc6e6 --- /dev/null +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: Syed Saba Kareem <Syed.SabaKareem@amd.com> +// + +/* + * Common file to be used by amd platforms + */ + +#include "amd.h" +#include <linux/pci.h> +#include <linux/export.h> + +void acp_enable_interrupts(struct acp_dev_data *adata) +{ + struct acp_resource *rsrc = adata->rsrc; + u32 ext_intr_ctrl; + + writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); + ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_intr_ctrl |= ACP_ERROR_MASK; + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); +} +EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON); + +void acp_disable_interrupts(struct acp_dev_data *adata) +{ + struct acp_resource *rsrc = adata->rsrc; + + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); + writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); +} +EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON); + +static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct acp_stream *stream = runtime->private_data; + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + + u32 physical_addr, pdm_size, period_bytes; + + period_bytes = frames_to_bytes(runtime, runtime->period_size); + pdm_size = frames_to_bytes(runtime, runtime->buffer_size); + physical_addr = stream->reg_offset + MEM_WINDOW_START; + + /* Init ACP PDM Ring buffer */ + writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); + writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE); + writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); +} + +static void set_acp_pdm_clk(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + unsigned int pdm_ctrl; + + /* Enable default ACP PDM clk */ + writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); + pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); + pdm_ctrl |= PDM_MISC_CTRL_MASK; + writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL); + set_acp_pdm_ring_buffer(substream, dai); +} + +void restore_acp_pdm_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata) +{ + struct snd_soc_dai *dai; + struct snd_soc_pcm_runtime *soc_runtime; + u32 ext_int_ctrl; + + soc_runtime = asoc_substream_to_rtd(substream); + dai = asoc_rtd_to_cpu(soc_runtime, 0); + /* Programming channel mask and sampling rate */ + writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); + writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR); + + /* Enabling ACP Pdm interuppts */ + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); + ext_int_ctrl |= PDM_DMA_INTR_MASK; + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); + set_acp_pdm_clk(substream, dai); +} +EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON); + +static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; + struct acp_stream *stream = substream->runtime->private_data; + u32 reg_dma_size, reg_fifo_size, reg_fifo_addr; + u32 phy_addr, acp_fifo_addr, ext_int_ctrl; + unsigned int dir = substream->stream; + + switch (dai->driver->id) { + case I2S_SP_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_I2S_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + SP_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_I2S_TX_FIFOADDR; + reg_fifo_size = ACP_I2S_TX_FIFOSIZE; + phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_I2S_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + SP_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_I2S_RX_FIFOADDR; + reg_fifo_size = ACP_I2S_RX_FIFOSIZE; + phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR); + } + break; + case I2S_BT_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_BT_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + BT_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_BT_TX_FIFOADDR; + reg_fifo_size = ACP_BT_TX_FIFOSIZE; + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_BT_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + BT_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_BT_RX_FIFOADDR; + reg_fifo_size = ACP_BT_RX_FIFOSIZE; + phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); + } + break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_HS_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_TX_FIFOADDR; + reg_fifo_size = ACP_HS_TX_FIFOSIZE; + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_HS_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_RX_FIFOADDR; + reg_fifo_size = ACP_HS_RX_FIFOSIZE; + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + } + break; + default: + dev_err(dev, "Invalid dai id %x\n", dai->driver->id); + return -EINVAL; + } + + writel(DMA_SIZE, adata->acp_base + reg_dma_size); + writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); + writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); + + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | + BIT(BT_RX_THRESHOLD(rsrc->offset)) | + BIT(I2S_TX_THRESHOLD(rsrc->offset)) | + BIT(BT_TX_THRESHOLD(rsrc->offset)) | + BIT(HS_RX_THRESHOLD(rsrc->offset)) | + BIT(HS_TX_THRESHOLD(rsrc->offset)); + + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + return 0; +} + +int restore_acp_i2s_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata, + struct acp_stream *stream) +{ + struct snd_soc_dai *dai; + struct snd_soc_pcm_runtime *soc_runtime; + u32 tdm_fmt, reg_val, fmt_reg, val; + + soc_runtime = asoc_substream_to_rtd(substream); + dai = asoc_rtd_to_cpu(soc_runtime, 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1]; + switch (stream->dai_id) { + case I2S_BT_INSTANCE: + reg_val = ACP_BTTDM_ITER; + fmt_reg = ACP_BTTDM_TXFRMT; + break; + case I2S_SP_INSTANCE: + reg_val = ACP_I2STDM_ITER; + fmt_reg = ACP_I2STDM_TXFRMT; + break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + fmt_reg = ACP_HSTDM_TXFRMT; + break; + default: + pr_err("Invalid dai id %x\n", stream->dai_id); + return -EINVAL; + } + val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3; + } else { + tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1]; + switch (stream->dai_id) { + case I2S_BT_INSTANCE: + reg_val = ACP_BTTDM_IRER; + fmt_reg = ACP_BTTDM_RXFRMT; + break; + case I2S_SP_INSTANCE: + reg_val = ACP_I2STDM_IRER; + fmt_reg = ACP_I2STDM_RXFRMT; + break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + fmt_reg = ACP_HSTDM_RXFRMT; + break; + default: + pr_err("Invalid dai id %x\n", stream->dai_id); + return -EINVAL; + } + val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3; + } + writel(val, adata->acp_base + reg_val); + if (adata->tdm_mode == TDM_ENABLE) { + writel(tdm_fmt, adata->acp_base + fmt_reg); + val = readl(adata->acp_base + reg_val); + writel(val | 0x2, adata->acp_base + reg_val); + } + return set_acp_i2s_dma_fifo(substream, dai); +} +EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON); + +static int acp_power_on(struct acp_chip_info *chip) +{ + u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg; + void __iomem *base; + + base = chip->base; + switch (chip->acp_rev) { + case ACP3X_DEV: + acp_pgfsm_stat_reg = ACP_PGFSM_STATUS; + acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL; + break; + case ACP6X_DEV: + acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS; + acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL; + break; + default: + return -EINVAL; + } + + val = readl(base + acp_pgfsm_stat_reg); + if (val == ACP_POWERED_ON) + return 0; + + if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) + writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg); + + return readl_poll_timeout(base + acp_pgfsm_stat_reg, val, + !val, DELAY_US, ACP_TIMEOUT); +} + +static int acp_reset(void __iomem *base) +{ + u32 val; + int ret; + + writel(1, base + ACP_SOFT_RESET); + ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, + DELAY_US, ACP_TIMEOUT); + if (ret) + return ret; + + writel(0, base + ACP_SOFT_RESET); + return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); +} + +int acp_init(struct acp_chip_info *chip) +{ + int ret; + + /* power on */ + ret = acp_power_on(chip); + if (ret) { + pr_err("ACP power on failed\n"); + return ret; + } + writel(0x01, chip->base + ACP_CONTROL); + + /* Reset */ + ret = acp_reset(chip->base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON); + +int acp_deinit(void __iomem *base) +{ + int ret; + + /* Reset */ + ret = acp_reset(base); + if (ret) + return ret; + + writel(0, base + ACP_CONTROL); + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); + +int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +{ + pci_write_config_dword(dev, 0x60, smn_addr); + pci_write_config_dword(dev, 0x64, data); + return 0; +} +EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON); + +int smn_read(struct pci_dev *dev, u32 smn_addr) +{ + u32 data; + + pci_write_config_dword(dev, 0x60, smn_addr); + pci_read_config_dword(dev, 0x64, &data); + return data; +} +EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 676ad50638d0..6d57d17ddfd7 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -75,23 +75,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -110,11 +93,8 @@ static int acp_asoc_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 6da17140beea..a06af82b8056 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -25,12 +25,17 @@ #include "../../codecs/rt1019.h" #include "../../codecs/rt5682s.h" #include "../../codecs/nau8825.h" +#include "../../codecs/nau8821.h" #include "acp-mach.h" #define PCO_PLAT_CLK 48000000 #define RT5682_PLL_FREQ (48000 * 512) #define DUAL_CHANNEL 2 #define FOUR_CHANNEL 4 +#define NAU8821_CODEC_DAI "nau8821-hifi" +#define NAU8821_BCLK 1536000 +#define NAU8821_FREQ_OUT 12288000 +#define MAX98388_CODEC_DAI "max98388-aif1" #define TDM_MODE_ENABLE 1 @@ -46,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_quirk_table); -static struct snd_soc_jack pco_jack; - static const unsigned int channels[] = { DUAL_CHANNEL, }; @@ -81,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata, SND_SOC_DAILINK_DEF(rt5682, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); +static struct snd_soc_jack rt5682_jack; +static struct snd_soc_jack_pin rt5682_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -104,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, + ARRAY_SIZE(rt5682_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682_controls, + ARRAY_SIZE(rt5682_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682_jack, + rt5682_jack_pins, + ARRAY_SIZE(rt5682_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -269,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = { SND_SOC_DAILINK_DEF(rt5682s, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1"))); +static struct snd_soc_jack rt5682s_jack; +static struct snd_soc_jack_pin rt5682s_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682s_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682s_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -293,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); } - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets, + ARRAY_SIZE(rt5682s_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682s_controls, + ARRAY_SIZE(rt5682s_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682s_jack, + rt5682s_jack_pins, + ARRAY_SIZE(rt5682s_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -434,6 +513,16 @@ SND_SOC_DAILINK_DEF(rt1019, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"), COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); +static const struct snd_kcontrol_new rt1019_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget rt1019_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + static const struct snd_soc_dapm_route rt1019_map_lr[] = { { "Left Spk", NULL, "Left SPO" }, { "Right Spk", NULL, "Right SPO" }, @@ -454,10 +543,25 @@ static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; + int ret; if (drvdata->amp_codec_id != RT1019) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets, + ARRAY_SIZE(rt1019_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt1019_controls, + ARRAY_SIZE(rt1019_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr, ARRAY_SIZE(rt1019_map_lr)); } @@ -588,6 +692,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = { SND_SOC_DAILINK_DEF(max98360a, DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); +static const struct snd_kcontrol_new max98360a_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget max98360a_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + static const struct snd_soc_dapm_route max98360a_map[] = { {"Spk", NULL, "Speaker"}, }; @@ -596,10 +708,25 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; + int ret; if (drvdata->amp_codec_id != MAX98360A) return -EINVAL; + ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets, + ARRAY_SIZE(max98360a_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, max98360a_controls, + ARRAY_SIZE(max98360a_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map, ARRAY_SIZE(max98360a_map)); } @@ -661,10 +788,137 @@ static const struct snd_soc_ops acp_card_maxim_ops = { .hw_params = acp_card_maxim_hw_params, }; +SND_SOC_DAILINK_DEF(max98388, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"), + COMP_CODEC("i2c-ADS8388:01", "max98388-aif1"))); + +static const struct snd_kcontrol_new max98388_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget max98388_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_soc_dapm_route max98388_map[] = { + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, +}; + +static struct snd_soc_codec_conf max98388_conf[] = { + { + .dlc = COMP_CODEC_CONF("i2c-ADS8388:00"), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF("i2c-ADS8388:01"), + .name_prefix = "Right", + }, +}; + +static const unsigned int max98388_format[] = {16}; + +static struct snd_pcm_hw_constraint_list constraints_sample_bits_max = { + .list = max98388_format, + .count = ARRAY_SIZE(max98388_format), +}; + +static int acp_card_max98388_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + &constraints_sample_bits_max); + + return 0; +} + +static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + int ret; + + if (drvdata->amp_codec_id != MAX98388) + return -EINVAL; + + ret = snd_soc_dapm_new_controls(&card->dapm, max98388_widgets, + ARRAY_SIZE(max98388_widgets)); + + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, max98388_controls, + ARRAY_SIZE(max98388_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map, + ARRAY_SIZE(max98388_map)); +} + +static int acp_max98388_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = + snd_soc_card_get_codec_dai(card, + MAX98388_CODEC_DAI); + int ret; + + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF); + if (ret < 0) + return ret; + + return ret; +} + +static const struct snd_soc_ops acp_max98388_ops = { + .startup = acp_card_max98388_startup, + .hw_params = acp_max98388_hw_params, +}; + /* Declare nau8825 codec components */ SND_SOC_DAILINK_DEF(nau8825, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); +static struct snd_soc_jack nau8825_jack; +static struct snd_soc_jack_pin nau8825_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8825_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget nau8825_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route nau8825_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -683,22 +937,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != NAU8825) return -EINVAL; - ret = snd_soc_card_jack_new(card, "Headset Jack", + ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets, + ARRAY_SIZE(nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8825_controls, + ARRAY_SIZE(nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + &nau8825_jack, + nau8825_jack_pins, + ARRAY_SIZE(nau8825_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -790,6 +1060,189 @@ static const struct snd_soc_ops acp_card_nau8825_ops = { .hw_params = acp_nau8825_hw_params, }; +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, NAU8821_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FS clock %d\n", ret); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, NAU8821_BCLK, + NAU8821_FREQ_OUT); + if (ret < 0) + dev_err(codec_dai->dev, "can't set FLL: %d\n", ret); + } + return ret; +} + +static struct snd_soc_jack nau8821_jack; +static struct snd_soc_jack_pin nau8821_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8821_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget nau8821_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route nau8821_audio_route[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + { "MICL", NULL, "Headset Mic" }, + { "MICR", NULL, "Headset Mic" }, + { "DMIC", NULL, "Int Mic" }, + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, + { "Int Mic", NULL, "Platform Clock" }, +}; + +static const unsigned int nau8821_format[] = {16}; + +static struct snd_pcm_hw_constraint_list constraints_sample_bits = { + .list = nau8821_format, + .count = ARRAY_SIZE(nau8821_format), +}; + +static int acp_8821_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + int ret; + + dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); + + ret = snd_soc_dapm_new_controls(&card->dapm, nau8821_widgets, + ARRAY_SIZE(nau8821_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + // Don't need to add routes if widget addition failed + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8821_controls, + ARRAY_SIZE(nau8821_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &nau8821_jack, + nau8821_jack_pins, + ARRAY_SIZE(nau8821_jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + nau8821_enable_jack_detect(component, &nau8821_jack); + + return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route, + ARRAY_SIZE(nau8821_audio_route)); +} + +static int acp_8821_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + &constraints_sample_bits); + return 0; +} + +static int acp_nau8821_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + unsigned int fmt; + + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(card->dev, "can't set FS clock %d\n", ret); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params), + params_rate(params) * 256); + if (ret < 0) + dev_err(card->dev, "can't set FLL: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops acp_8821_ops = { + .startup = acp_8821_startup, + .hw_params = acp_nau8821_hw_params, +}; + +SND_SOC_DAILINK_DEF(nau8821, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", + "nau8821-hifi"))); + /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -920,6 +1373,12 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].init = acp_card_rt5682s_init; links[i].ops = &acp_card_rt5682s_ops; } + if (drv_data->hs_codec_id == NAU8821) { + links[i].codecs = nau8821; + links[i].num_codecs = ARRAY_SIZE(nau8821); + links[i].init = acp_8821_init; + links[i].ops = &acp_8821_ops; + } i++; } @@ -1007,6 +1466,14 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].ops = &acp_card_maxim_ops; links[i].init = acp_card_maxim_init; } + if (drv_data->amp_codec_id == MAX98388) { + links[i].codecs = max98388; + links[i].num_codecs = ARRAY_SIZE(max98388); + links[i].ops = &acp_max98388_ops; + links[i].init = acp_card_max98388_init; + card->codec_conf = max98388_conf; + card->num_configs = ARRAY_SIZE(max98388_conf); + } if (drv_data->amp_codec_id == RT1019) { links[i].codecs = rt1019; links[i].num_codecs = ARRAY_SIZE(rt1019); diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 165f407697c0..2b3ec6594023 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -41,6 +41,8 @@ enum codec_endpoints { MAX98360A, RT5682S, NAU8825, + NAU8821, + MAX98388, }; enum platform_end_point { diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 8154fbfd1229..a32c14a109b7 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -16,6 +16,7 @@ #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include "amd.h" #include "../mach-config.h" @@ -106,6 +107,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto unregister_dmic_dev; } + acp_init(chip); res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL); if (!res) { ret = -ENOMEM; @@ -139,7 +141,12 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = PTR_ERR(pdev); goto unregister_dmic_dev; } - + chip->chip_pdev = pdev; + dev_set_drvdata(&pci->dev, chip); + pm_runtime_set_autosuspend_delay(&pci->dev, 2000); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); return ret; unregister_dmic_dev: @@ -152,12 +159,56 @@ disable_pci: return ret; }; +static int __maybe_unused snd_acp_suspend(struct device *dev) +{ + struct acp_chip_info *chip; + int ret; + + chip = dev_get_drvdata(dev); + ret = acp_deinit(chip->base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + return ret; +} + +static int __maybe_unused snd_acp_resume(struct device *dev) +{ + struct acp_chip_info *chip; + struct acp_dev_data *adata; + struct device child; + int ret; + + chip = dev_get_drvdata(dev); + ret = acp_init(chip); + if (ret) + dev_err(dev, "ACP init failed\n"); + child = chip->chip_pdev->dev; + adata = dev_get_drvdata(&child); + if (adata) + acp_enable_interrupts(adata); + return ret; +} + +static const struct dev_pm_ops acp_pm_ops = { + SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) +}; + static void acp_pci_remove(struct pci_dev *pci) { + struct acp_chip_info *chip; + int ret; + + chip = pci_get_drvdata(pci); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); if (dmic_dev) platform_device_unregister(dmic_dev); if (pdev) platform_device_unregister(pdev); + ret = acp_deinit(chip->base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); } /* PCI IDs */ @@ -173,8 +224,12 @@ static struct pci_driver snd_amd_acp_pci_driver = { .id_table = acp_pci_ids, .probe = acp_pci_probe, .remove = acp_pci_remove, + .driver = { + .pm = &acp_pm_ops, + }, }; module_pci_driver(snd_amd_acp_pci_driver); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index f8030b79ac17..f754bf79b5e3 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -25,18 +25,6 @@ #define DRV_NAME "acp-pdm" -#define PDM_DMA_STAT 0x10 -#define PDM_DMA_INTR_MASK 0x10000 -#define PDM_DEC_64 0x2 -#define PDM_CLK_FREQ_MASK 0x07 -#define PDM_MISC_CTRL_MASK 0x10 -#define PDM_ENABLE 0x01 -#define PDM_DISABLE 0x00 -#define DMA_EN_MASK 0x02 -#define DELAY_US 5 -#define PDM_TIMEOUT 1000 -#define ACP_REGION2_OFFSET 0x02000000 - static int acp_dmic_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -135,6 +123,7 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream, return -EINVAL; } + adata->ch_mask = ch_mask; if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) { dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams)); return -EINVAL; diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index f220378ec20e..f516daf6fef4 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -127,7 +127,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) return IRQ_NONE; } -static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) +void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; @@ -143,8 +143,9 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } +EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); -static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) +void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) { struct snd_pcm_substream *substream = stream->substream; struct acp_resource *rsrc = adata->rsrc; @@ -168,6 +169,7 @@ static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream addr += PAGE_SIZE; } } +EXPORT_SYMBOL_NS_GPL(config_acp_dma, SND_SOC_ACP_COMMON); static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 1b997837c7d8..1bf7b2e68a11 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -19,30 +19,17 @@ #include <sound/soc.h> #include <sound/soc-dai.h> #include <linux/dma-mapping.h> +#include <linux/pci.h> +#include <linux/pm_runtime.h> #include "amd.h" #define DRV_NAME "acp_asoc_rembrandt" -#define ACP6X_PGFSM_CONTROL 0x1024 -#define ACP6X_PGFSM_STATUS 0x1028 - -#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 - -#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 -#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 -#define ACP_PGFSM_STATUS_MASK 0x03 -#define ACP_POWERED_ON 0x00 -#define ACP_POWER_ON_IN_PROGRESS 0x01 -#define ACP_POWERED_OFF 0x02 -#define ACP_POWER_OFF_IN_PROGRESS 0x03 - -#define ACP_ERROR_MASK 0x20000000 -#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF - - -static int rmb_acp_init(void __iomem *base); -static int rmb_acp_deinit(void __iomem *base); +#define MP1_C2PMSG_69 0x3B10A14 +#define MP1_C2PMSG_85 0x3B10A54 +#define MP1_C2PMSG_93 0x3B10A74 +#define HOST_BRIDGE_ID 0x14B5 static struct acp_resource rsrc = { .offset = 0, @@ -111,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -137,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-hs", @@ -163,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", @@ -180,108 +164,22 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { }, }; -static int acp6x_power_on(void __iomem *base) -{ - u32 val; - int timeout; - - val = readl(base + ACP6X_PGFSM_STATUS); - - if (val == ACP_POWERED_ON) - return 0; - - if ((val & ACP_PGFSM_STATUS_MASK) != - ACP_POWER_ON_IN_PROGRESS) - writel(ACP_PGFSM_CNTL_POWER_ON_MASK, - base + ACP6X_PGFSM_CONTROL); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP6X_PGFSM_STATUS); - if (!val) - return 0; - udelay(1); - } - return -ETIMEDOUT; -} - -static int acp6x_reset(void __iomem *base) +static int acp6x_master_clock_generate(struct device *dev) { - u32 val; - int timeout; - - writel(1, base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP_SOFT_RESET); - if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) - break; - cpu_relax(); - } - writel(0, base + ACP_SOFT_RESET); - timeout = 0; - while (++timeout < 500) { - val = readl(base + ACP_SOFT_RESET); - if (!val) - return 0; - cpu_relax(); - } - return -ETIMEDOUT; -} - -static void acp6x_enable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - u32 ext_intr_ctrl; - - writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); - ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); - ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); -} - -static void acp6x_disable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, - ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); -} + int data = 0; + struct pci_dev *smn_dev; -static int rmb_acp_init(void __iomem *base) -{ - int ret; - - /* power on */ - ret = acp6x_power_on(base); - if (ret) { - pr_err("ACP power on failed\n"); - return ret; - } - writel(0x01, base + ACP_CONTROL); - - /* Reset */ - ret = acp6x_reset(base); - if (ret) { - pr_err("ACP reset failed\n"); - return ret; - } - - return 0; -} - -static int rmb_acp_deinit(void __iomem *base) -{ - int ret = 0; - - /* Reset */ - ret = acp6x_reset(base); - if (ret) { - pr_err("ACP reset failed\n"); - return ret; + smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL); + if (!smn_dev) { + dev_err(dev, "Failed to get host bridge device\n"); + return -ENODEV; } - writel(0x00, base + ACP_CONTROL); + smn_write(smn_dev, MP1_C2PMSG_93, 0); + smn_write(smn_dev, MP1_C2PMSG_85, 0xC4); + smn_write(smn_dev, MP1_C2PMSG_69, 0x4); + read_poll_timeout(smn_read, data, data, DELAY_US, + ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93); return 0; } @@ -303,8 +201,6 @@ static int rembrandt_audio_probe(struct platform_device *pdev) return -ENODEV; } - rmb_acp_init(chip->base); - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); if (!adata) return -ENOMEM; @@ -335,9 +231,14 @@ static int rembrandt_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); - acp6x_enable_interrupts(adata); + acp6x_master_clock_generate(dev); + acp_enable_interrupts(adata); acp_platform_register(dev); - + pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); return 0; } @@ -345,19 +246,49 @@ static void rembrandt_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_chip_info *chip = dev_get_platdata(dev); - - rmb_acp_deinit(chip->base); - acp6x_disable_interrupts(adata); + acp_disable_interrupts(adata); acp_platform_unregister(dev); + pm_runtime_disable(&pdev->dev); } +static int __maybe_unused rmb_pcm_resume(struct device *dev) +{ + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_stream *stream; + struct snd_pcm_substream *substream; + snd_pcm_uframes_t buf_in_frames; + u64 buf_size; + + acp6x_master_clock_generate(dev); + spin_lock(&adata->acp_lock); + list_for_each_entry(stream, &adata->stream_list, list) { + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(adata, stream); + config_acp_dma(adata, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, adata, stream); + else + restore_acp_pdm_params(substream, adata); + } + } + spin_unlock(&adata->acp_lock); + return 0; +} + +static const struct dev_pm_ops rmb_dma_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume) +}; + static struct platform_driver rembrandt_driver = { .probe = rembrandt_audio_probe, .remove_new = rembrandt_audio_remove, .driver = { .name = "acp_asoc_rembrandt", + .pm = &rmb_dma_pm_ops, }, }; diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index f188365fe214..54235cad9cc9 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -25,20 +25,6 @@ #define DRV_NAME "acp_asoc_renoir" -#define ACP_SOFT_RST_DONE_MASK 0x00010001 - -#define ACP_PWR_ON_MASK 0x01 -#define ACP_PWR_OFF_MASK 0x00 -#define ACP_PGFSM_STAT_MASK 0x03 -#define ACP_POWERED_ON 0x00 -#define ACP_PWR_ON_IN_PROGRESS 0x01 -#define ACP_POWERED_OFF 0x02 -#define DELAY_US 5 -#define ACP_TIMEOUT 500 - -#define ACP_ERROR_MASK 0x20000000 -#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF - static struct acp_resource rsrc = { .offset = 20, .no_of_ctrls = 1, @@ -111,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-i2s-bt", @@ -137,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { .rate_max = 48000, }, .ops = &asoc_acp_cpu_dai_ops, - .probe = &asoc_acp_i2s_probe, }, { .name = "acp-pdm-dmic", @@ -154,89 +138,7 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = { }, }; -static int acp3x_power_on(void __iomem *base) -{ - u32 val; - - val = readl(base + ACP_PGFSM_STATUS); - - if (val == ACP_POWERED_ON) - return 0; - - if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS) - writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL); - - return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); -} - -static int acp3x_reset(void __iomem *base) -{ - u32 val; - int ret; - - writel(1, base + ACP_SOFT_RESET); - - ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, - DELAY_US, ACP_TIMEOUT); - if (ret) - return ret; - - writel(0, base + ACP_SOFT_RESET); - - return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); -} - -static void acp3x_enable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - u32 ext_intr_ctrl; - - writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); - ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); - ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); -} - -static void acp3x_disable_interrupts(struct acp_dev_data *adata) -{ - struct acp_resource *rsrc = adata->rsrc; - - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, - ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); -} -static int rn_acp_init(void __iomem *base) -{ - int ret; - - /* power on */ - ret = acp3x_power_on(base); - if (ret) - return ret; - - writel(0x01, base + ACP_CONTROL); - - /* Reset */ - ret = acp3x_reset(base); - if (ret) - return ret; - - return 0; -} - -static int rn_acp_deinit(void __iomem *base) -{ - int ret = 0; - - /* Reset */ - ret = acp3x_reset(base); - if (ret) - return ret; - - writel(0x00, base + ACP_CONTROL); - return 0; -} static int renoir_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -256,12 +158,6 @@ static int renoir_audio_probe(struct platform_device *pdev) return -ENODEV; } - ret = rn_acp_init(chip->base); - if (ret) { - dev_err(&pdev->dev, "ACP Init failed\n"); - return -EINVAL; - } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); if (!adata) return -ENOMEM; @@ -290,7 +186,7 @@ static int renoir_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); - acp3x_enable_interrupts(adata); + acp_enable_interrupts(adata); acp_platform_register(dev); return 0; @@ -300,17 +196,8 @@ static void renoir_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_chip_info *chip; - int ret; - - chip = dev_get_platdata(&pdev->dev); - - acp3x_disable_interrupts(adata); - - ret = rn_acp_deinit(chip->base); - if (ret) - dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret)); + acp_disable_interrupts(adata); acp_platform_unregister(dev); } diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 99a7d3879340..5223033a122f 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -83,20 +83,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { .tdm_mode = false, }; -static const struct snd_kcontrol_new acp_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget acp_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), +static struct acp_card_drvdata sof_nau8821_max98388_data = { + .hs_cpu_id = I2S_SP, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = NONE, + .hs_codec_id = NAU8821, + .amp_codec_id = MAX98388, + .dmic_codec_id = NONE, + .soc_mclk = true, + .tdm_mode = false, }; static int acp_sof_probe(struct platform_device *pdev) @@ -117,11 +112,8 @@ static int acp_sof_probe(struct platform_device *pdev) card->dev = dev; card->owner = THIS_MODULE; card->name = pdev->id_entry->name; - card->dapm_widgets = acp_widgets; - card->num_dapm_widgets = ARRAY_SIZE(acp_widgets); - card->controls = acp_controls; - card->num_controls = ARRAY_SIZE(acp_controls); card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data; + /* Widgets and controls added per-codec in acp-mach-common.c */ acp_card_drvdata = card->drvdata; dmi_id = dmi_first_match(acp_quirk_table); @@ -166,6 +158,10 @@ static const struct platform_device_id board_ids[] = { .name = "rt5682s-hs-rt1019", .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data }, + { + .name = "nau8821-max", + .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data + }, { } }; static struct platform_driver acp_asoc_audio = { @@ -187,4 +183,5 @@ MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-rt1019"); MODULE_ALIAS("platform:nau8825-max"); MODULE_ALIAS("platform:rt5682s-hs-rt1019"); +MODULE_ALIAS("platform:nau8821-max"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 12a176a50fd6..d6cfae6ec5f7 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -92,10 +92,43 @@ #define SLOT_WIDTH_24 0x18 #define SLOT_WIDTH_32 0x20 +#define ACP6X_PGFSM_CONTROL 0x1024 +#define ACP6X_PGFSM_STATUS 0x1028 + +#define ACP_SOFT_RST_DONE_MASK 0x00010001 + +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWERED_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 + +#define ACP_ERROR_MASK 0x20000000 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xffffffff + +#define ACP_TIMEOUT 500 +#define DELAY_US 5 +#define ACP_SUSPEND_DELAY_MS 2000 + +#define PDM_DMA_STAT 0x10 +#define PDM_DMA_INTR_MASK 0x10000 +#define PDM_DEC_64 0x2 +#define PDM_CLK_FREQ_MASK 0x07 +#define PDM_MISC_CTRL_MASK 0x10 +#define PDM_ENABLE 0x01 +#define PDM_DISABLE 0x00 +#define DMA_EN_MASK 0x02 +#define DELAY_US 5 +#define PDM_TIMEOUT 1000 +#define ACP_REGION2_OFFSET 0x02000000 + struct acp_chip_info { char *name; /* Platform name */ unsigned int acp_rev; /* ACP Revision id */ void __iomem *base; /* ACP memory PCI base */ + struct platform_device *chip_pdev; }; struct acp_stream { @@ -144,8 +177,11 @@ struct acp_dev_data { u32 lrclk_div; struct acp_resource *rsrc; + u32 ch_mask; u32 tdm_tx_fmt[3]; u32 tdm_rx_fmt[3]; + u32 xfer_tx_resolution[3]; + u32 xfer_rx_resolution[3]; }; union acp_i2stdm_mstrclkgen { @@ -162,15 +198,29 @@ union acp_i2stdm_mstrclkgen { extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; -int asoc_acp_i2s_probe(struct snd_soc_dai *dai); int acp_platform_register(struct device *dev); int acp_platform_unregister(struct device *dev); int acp_machine_select(struct acp_dev_data *adata); +int smn_read(struct pci_dev *dev, u32 smn_addr); +int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data); + +int acp_init(struct acp_chip_info *chip); +int acp_deinit(void __iomem *base); +void acp_enable_interrupts(struct acp_dev_data *adata); +void acp_disable_interrupts(struct acp_dev_data *adata); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); +void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream); +void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size); +void restore_acp_pdm_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata); + +int restore_acp_i2s_params(struct snd_pcm_substream *substream, + struct acp_dev_data *adata, struct acp_stream *stream); + static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction) { u64 byte_count = 0, low = 0, high = 0; diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 0543dda75b99..28ad5f5b9a76 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -28,6 +28,17 @@ #define DUAL_CHANNEL 2 static struct snd_soc_jack pco_jack; +static struct snd_soc_jack_pin pco_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct clk *rt5682_dai_wclk; static struct clk *rt5682_dai_bclk; static struct gpio_desc *dmic_sel; @@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pco_jack, + pco_jack_pins, + ARRAY_SIZE(pco_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 7b4c625da40d..d392e6d6e6e1 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -20,6 +20,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[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 324c80fca672..6230d1b12225 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -488,10 +488,9 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev) return 0; } -static int acp63_sdw_platform_remove(struct platform_device *pdev) +static void acp63_sdw_platform_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) @@ -552,7 +551,7 @@ static const struct dev_pm_ops acp63_pm_ops = { static struct platform_driver acp63_sdw_dma_driver = { .probe = acp63_sdw_platform_probe, - .remove = acp63_sdw_platform_remove, + .remove_new = acp63_sdw_platform_remove, .driver = { .name = "amd_ps_sdw_dma", .pm = &acp63_pm_ops, diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index e5bcd1e6eb73..eda464545866 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41 - * codecs. + * Machine driver for AMD Vangogh platform using either + * NAU8821 & CS35L41 or NAU8821 & MAX98388 codecs. * * Copyright 2021 Advanced Micro Devices, Inc. */ @@ -22,7 +22,6 @@ #define DRV_NAME "acp5x_mach" #define DUAL_CHANNEL 2 -#define VG_JUPITER 1 #define ACP5X_NAU8821_BCLK 3072000 #define ACP5X_NAU8821_FREQ_OUT 12288000 #define ACP5X_NAU8821_COMP_NAME "i2c-NVTN2020:00" @@ -30,8 +29,10 @@ #define ACP5X_CS35L41_COMP_LNAME "spi-VLV1776:00" #define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01" #define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm" +#define ACP5X_MAX98388_COMP_LNAME "i2c-ADS8388:00" +#define ACP5X_MAX98388_COMP_RNAME "i2c-ADS8388:01" +#define ACP5X_MAX98388_DAI_NAME "max98388-aif1" -static unsigned long acp5x_machine_id; static struct snd_soc_jack vg_headset; SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0"))); @@ -169,6 +170,9 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME); int ret, bclk; + if (!dai) + return -EINVAL; + ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN); if (ret < 0) dev_err(card->dev, "can't set FS clock %d\n", ret); @@ -242,7 +246,6 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, } return 0; - } static const struct snd_soc_ops acp5x_cs35l41_play_ops = { @@ -292,8 +295,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { }, }; - - static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -331,16 +332,110 @@ static struct snd_soc_card acp5x_8821_35l41_card = { .num_controls = ARRAY_SIZE(acp5x_8821_controls), }; -static int acp5x_vg_quirk_cb(const struct dmi_system_id *id) +static int acp5x_max98388_startup(struct snd_pcm_substream *substream) { - acp5x_machine_id = VG_JUPITER; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card); + struct snd_pcm_runtime *runtime = substream->runtime; + + machine->play_i2s_instance = I2S_HS_INSTANCE; - return 1; + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + return 0; } +static const struct snd_soc_ops acp5x_max98388_play_ops = { + .startup = acp5x_max98388_startup, +}; + +static struct snd_soc_codec_conf acp5x_max98388_conf[] = { + { + .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_LNAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_RNAME), + .name_prefix = "Right", + }, +}; + +SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_MAX98388_COMP_LNAME, + ACP5X_MAX98388_DAI_NAME), + COMP_CODEC(ACP5X_MAX98388_COMP_RNAME, + ACP5X_MAX98388_DAI_NAME))); + +static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { + { + .name = "acp5x-8821-play", + .stream_name = "Playback/Capture", + .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), + }, + { + .name = "acp5x-max98388-play", + .stream_name = "MAX98388 Playback", + .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), + }, +}; + +static const struct snd_soc_dapm_widget acp5x_8821_98388_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("SPK", NULL), +}; + +static const struct snd_soc_dapm_route acp5x_8821_98388_route[] = { + { "Headphone", NULL, "HPOL" }, + { "Headphone", NULL, "HPOR" }, + { "MICL", NULL, "Headset Mic" }, + { "MICR", NULL, "Headset Mic" }, + { "DMIC", NULL, "Int Mic" }, + + { "Headphone", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, + { "Int Mic", NULL, "Platform Clock" }, + + { "SPK", NULL, "Left BE_OUT" }, + { "SPK", NULL, "Right BE_OUT" }, +}; + +static struct snd_soc_card acp5x_8821_98388_card = { + .name = "acp5x-max98388", + .owner = THIS_MODULE, + .dai_link = acp5x_8821_98388_dai, + .num_links = ARRAY_SIZE(acp5x_8821_98388_dai), + .dapm_widgets = acp5x_8821_98388_widgets, + .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_98388_widgets), + .dapm_routes = acp5x_8821_98388_route, + .num_dapm_routes = ARRAY_SIZE(acp5x_8821_98388_route), + .codec_conf = acp5x_max98388_conf, + .num_configs = ARRAY_SIZE(acp5x_max98388_conf), + .controls = acp5x_8821_controls, + .num_controls = ARRAY_SIZE(acp5x_8821_controls), +}; + static const struct dmi_system_id acp5x_vg_quirk_table[] = { { - .callback = acp5x_vg_quirk_cb, .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"), @@ -351,23 +446,31 @@ static const struct dmi_system_id acp5x_vg_quirk_table[] = { static int acp5x_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct acp5x_platform_info *machine; struct device *dev = &pdev->dev; struct snd_soc_card *card; int ret; + card = (struct snd_soc_card *)device_get_match_data(dev); + if (!card) { + /* + * This is normally the result of directly probing the driver + * in pci-acp5x through platform_device_register_full(), which + * is necessary for the CS35L41 variant, as it doesn't support + * ACPI probing and relies on DMI quirks. + */ + dmi_id = dmi_first_match(acp5x_vg_quirk_table); + if (!dmi_id) + return -ENODEV; + + card = &acp5x_8821_35l41_card; + } + machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); if (!machine) return -ENOMEM; - dmi_check_system(acp5x_vg_quirk_table); - switch (acp5x_machine_id) { - case VG_JUPITER: - card = &acp5x_8821_35l41_card; - break; - default: - return -ENODEV; - } card->dev = dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); @@ -379,10 +482,17 @@ static int acp5x_probe(struct platform_device *pdev) return 0; } +static const struct acpi_device_id acp5x_acpi_match[] = { + { "AMDI8821", (kernel_ulong_t)&acp5x_8821_98388_card }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, acp5x_acpi_match); + static struct platform_driver acp5x_mach_driver = { .driver = { - .name = "acp5x_mach", + .name = DRV_NAME, .pm = &snd_soc_pm_ops, + .acpi_match_table = acp5x_acpi_match, }, .probe = acp5x_probe, }; @@ -390,6 +500,6 @@ static struct platform_driver acp5x_mach_driver = { module_platform_driver(acp5x_mach_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); -MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support"); +MODULE_DESCRIPTION("NAU8821/CS35L41 & NAU8821/MAX98388 audio support"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 69a88dc65165..6c20c643f321 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return err; } -static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { - .prepare = atmel_i2s_prepare, - .trigger = atmel_i2s_trigger, - .hw_params = atmel_i2s_hw_params, - .set_fmt = atmel_i2s_set_dai_fmt, -}; - static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) { struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { + .probe = atmel_i2s_dai_probe, + .prepare = atmel_i2s_prepare, + .trigger = atmel_i2s_trigger, + .hw_params = atmel_i2s_hw_params, + .set_fmt = atmel_i2s_set_dai_fmt, +}; + static struct snd_soc_dai_driver atmel_i2s_dai = { - .probe = atmel_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -730,7 +730,7 @@ static void atmel_i2s_remove(struct platform_device *pdev) static struct platform_driver atmel_i2s_driver = { .driver = { .name = "atmel_i2s", - .of_match_table = of_match_ptr(atmel_i2s_dt_ids), + .of_match_table = atmel_i2s_dt_ids, }, .probe = atmel_i2s_probe, .remove_new = atmel_i2s_remove, diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index efcbdd1a629f..0db7815d230c 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -690,7 +690,7 @@ unregister_codec: static struct platform_driver atmel_pdmic_driver = { .driver = { .name = "atmel-pdmic", - .of_match_table = of_match_ptr(atmel_pdmic_of_match), + .of_match_table = atmel_pdmic_of_match, .pm = &snd_soc_pm_ops, }, .probe = atmel_pdmic_probe, diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 7c83d48ca1a0..25ed0b953bfd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .set_sysclk = mchp_i2s_mcc_set_sysclk, - .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, - .startup = mchp_i2s_mcc_startup, - .trigger = mchp_i2s_mcc_trigger, - .hw_params = mchp_i2s_mcc_hw_params, - .hw_free = mchp_i2s_mcc_hw_free, - .set_fmt = mchp_i2s_mcc_set_dai_fmt, - .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, -}; - static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) { struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { + .probe = mchp_i2s_mcc_dai_probe, + .set_sysclk = mchp_i2s_mcc_set_sysclk, + .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, + .startup = mchp_i2s_mcc_startup, + .trigger = mchp_i2s_mcc_trigger, + .hw_params = mchp_i2s_mcc_hw_params, + .hw_free = mchp_i2s_mcc_hw_free, + .set_fmt = mchp_i2s_mcc_set_dai_fmt, + .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, +}; + #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { - .probe = mchp_i2s_mcc_dai_probe, .playback = { .stream_name = "I2SMCC-Playback", .channels_min = 1, @@ -1098,7 +1098,7 @@ static void mchp_i2s_mcc_remove(struct platform_device *pdev) static struct platform_driver mchp_i2s_mcc_driver = { .driver = { .name = "mchp_i2s_mcc", - .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids), + .of_match_table = mchp_i2s_mcc_dt_ids, }, .probe = mchp_i2s_mcc_probe, .remove_new = mchp_i2s_mcc_remove, diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index c79c73e6791e..944d78ef2f36 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -706,13 +706,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .set_fmt = mchp_pdmc_set_fmt, - .startup = mchp_pdmc_startup, - .hw_params = mchp_pdmc_hw_params, - .trigger = mchp_pdmc_trigger, -}; - static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd) { struct mchp_pdmc_chmap *info; @@ -765,8 +758,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, return ret; } +static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { + .probe = mchp_pdmc_dai_probe, + .set_fmt = mchp_pdmc_set_fmt, + .startup = mchp_pdmc_startup, + .hw_params = mchp_pdmc_hw_params, + .trigger = mchp_pdmc_trigger, + .pcm_new = &mchp_pdmc_pcm_new, +}; + static struct snd_soc_dai_driver mchp_pdmc_dai = { - .probe = mchp_pdmc_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -777,7 +778,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, .ops = &mchp_pdmc_dai_ops, - .pcm_new = &mchp_pdmc_pcm_new, }; /* PDMC interrupt handler */ diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index ff6aba143aee..33ce5e54482b 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -503,11 +503,6 @@ unlock: return ret; } -static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { - .trigger = mchp_spdifrx_trigger, - .hw_params = mchp_spdifrx_hw_params, -}; - #define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { + .probe = mchp_spdifrx_dai_probe, + .remove = mchp_spdifrx_dai_remove, + .trigger = mchp_spdifrx_trigger, + .hw_params = mchp_spdifrx_hw_params, +}; + static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", - .probe = mchp_spdifrx_dai_probe, - .remove = mchp_spdifrx_dai_remove, .capture = { .stream_name = "S/PDIF Capture", .channels_min = SPDIFRX_CHANNELS, @@ -1197,7 +1197,7 @@ static struct platform_driver mchp_spdifrx_driver = { .remove_new = mchp_spdifrx_remove, .driver = { .name = "mchp_spdifrx", - .of_match_table = of_match_ptr(mchp_spdifrx_dt_ids), + .of_match_table = mchp_spdifrx_dt_ids, .pm = pm_ptr(&mchp_spdifrx_pm_ops), }, }; diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 1d3e17119888..a201a96fa690 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream, SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); } -static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { - .startup = mchp_spdiftx_dai_startup, - .shutdown = mchp_spdiftx_dai_shutdown, - .trigger = mchp_spdiftx_trigger, - .hw_params = mchp_spdiftx_hw_params, - .hw_free = mchp_spdiftx_hw_free, -}; - #define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000 #define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { + .probe = mchp_spdiftx_dai_probe, + .startup = mchp_spdiftx_dai_startup, + .shutdown = mchp_spdiftx_dai_shutdown, + .trigger = mchp_spdiftx_trigger, + .hw_params = mchp_spdiftx_hw_params, + .hw_free = mchp_spdiftx_hw_free, +}; + static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", - .probe = mchp_spdiftx_dai_probe, .playback = { .stream_name = "S/PDIF Playback", .channels_min = 1, @@ -891,7 +891,7 @@ static struct platform_driver mchp_spdiftx_driver = { .remove_new = mchp_spdiftx_remove, .driver = { .name = "mchp_spdiftx", - .of_match_table = of_match_ptr(mchp_spdiftx_dt_ids), + .of_match_table = mchp_spdiftx_dt_ids, .pm = pm_ptr(&mchp_spdiftx_pm_ops) }, }; diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index efead272d92b..c809b121037f 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -430,7 +430,7 @@ MODULE_DEVICE_TABLE(of, tse850_dt_ids); static struct platform_driver tse850_driver = { .driver = { .name = "axentia-tse850-pcm5142", - .of_match_table = of_match_ptr(tse850_dt_ids), + .of_match_table = tse850_dt_ids, }, .probe = tse850_probe, .remove_new = tse850_remove, diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index a11d6841afc2..b0e1a1253e10 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops alchemy_ac97c_ops = { - .startup = alchemy_ac97c_startup, -}; - static int au1xac97c_dai_probe(struct snd_soc_dai *dai) { return ac97c_workdata ? 0 : -ENODEV; } +static const struct snd_soc_dai_ops alchemy_ac97c_ops = { + .probe = au1xac97c_dai_probe, + .startup = alchemy_ac97c_startup, +}; + static struct snd_soc_dai_driver au1xac97c_dai_driver = { .name = "alchemy-ac97c", - .probe = au1xac97c_dai_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 9fd91aea7d1a..5d50ebc2bdd5 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .probe = au1xpsc_ac97_probe, .startup = au1xpsc_ac97_startup, .trigger = au1xpsc_ac97_trigger, .hw_params = au1xpsc_ac97_hw_params, }; static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { - .probe = au1xpsc_ac97_probe, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 85f705afcdbb..9bda6499e66e 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream, bcm2835_i2s_stop_clock(dev); } +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, + &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], + &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); + + return 0; +} + static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { + .probe = bcm2835_i2s_dai_probe, .startup = bcm2835_i2s_startup, .shutdown = bcm2835_i2s_shutdown, .prepare = bcm2835_i2s_prepare, @@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, }; -static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, - &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return 0; -} - static struct snd_soc_dai_driver bcm2835_i2s_dai = { .name = "bcm2835-i2s", - .probe = bcm2835_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c index 18c51dbbc8dc..c64609718738 100644 --- a/sound/soc/bcm/bcm63xx-i2s-whistler.c +++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c @@ -225,7 +225,6 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev) { int ret = 0; void __iomem *regs; - struct resource *r_mem, *region; struct bcm_i2s_priv *i2s_priv; struct regmap *regmap_i2s; struct clk *i2s_clk; @@ -241,20 +240,7 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev) return PTR_ERR(i2s_clk); } - r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r_mem) { - dev_err(&pdev->dev, "Unable to get register resource.\n"); - return -ENODEV; - } - - region = devm_request_mem_region(&pdev->dev, r_mem->start, - resource_size(r_mem), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - return -EBUSY; - } - - regs = devm_ioremap_resource(&pdev->dev, r_mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); return ret; diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h index 74152b2d770d..4925e03c3c30 100644 --- a/sound/soc/bcm/cygnus-ssp.h +++ b/sound/soc/bcm/cygnus-ssp.h @@ -117,8 +117,6 @@ struct cygnus_audio { unsigned long vco_rate; }; -extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai); -extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd); extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len); extern int cygnus_soc_platform_register(struct device *dev, diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index afc6b5b570ea..522de4b80293 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) #endif static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { + .probe = ep93xx_i2s_dai_probe, .startup = ep93xx_i2s_startup, .shutdown = ep93xx_i2s_shutdown, .hw_params = ep93xx_i2s_hw_params, @@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { static struct snd_soc_dai_driver ep93xx_i2s_dai = { .symmetric_rate = 1, - .probe = ep93xx_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 3574c68e0dda..d99b674d574b 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -143,7 +143,7 @@ struct pm860x_priv { struct pm860x_det det; int irq[4]; - unsigned char name[4][MAX_NAME_LEN+1]; + unsigned char name[4][MAX_NAME_LEN]; }; /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */ @@ -1373,7 +1373,7 @@ static int pm860x_codec_probe(struct platform_device *pdev) return -EINVAL; } pm860x->irq[i] = res->start + chip->irq_base; - strncpy(pm860x->name[i], res->name, MAX_NAME_LEN); + strscpy(pm860x->name[i], res->name, MAX_NAME_LEN); } ret = devm_snd_soc_register_component(&pdev->dev, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 49367d49b416..9ddebd135892 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -53,8 +53,10 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AK5558 imply SND_SOC_ALC5623 imply SND_SOC_ALC5632 + imply SND_SOC_AUDIO_IIO_AUX imply SND_SOC_AW8738 imply SND_SOC_AW88395 + imply SND_SOC_AW88261 imply SND_SOC_BT_SCO imply SND_SOC_BD28623 imply SND_SOC_CHV3_CODEC @@ -185,6 +187,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1015 imply SND_SOC_RT1015P imply SND_SOC_RT1016 + imply SND_SOC_RT1017_SDCA_SDW imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 @@ -616,6 +619,17 @@ config SND_SOC_ALC5632 tristate depends on I2C +config SND_SOC_AUDIO_IIO_AUX + tristate "Audio IIO Auxiliary device" + depends on IIO + help + Enable support for Industrial I/O devices as audio auxiliary devices. + This allows to have an IIO device present in the audio path and + controlled using mixer controls. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-audio-iio-aux. + config SND_SOC_AW8738 tristate "Awinic AW8738 Audio Amplifier" select GPIOLIB @@ -642,6 +656,20 @@ config SND_SOC_AW88395 digital Smart K audio amplifier with an integrated 10V smart boost convert. +config SND_SOC_AW88261 + tristate "Soc Audio for awinic aw88261" + depends on I2C + select CRC8 + select REGMAP_I2C + select GPIOLIB + select SND_SOC_AW88395_LIB + help + This option enables support for aw88261 Smart PA. + The awinic AW88261 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier. The output voltage of + boost converter can be adjusted smartly according to + the input amplitude. + config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help @@ -1432,6 +1460,11 @@ config SND_SOC_RT1016 tristate depends on I2C +config SND_SOC_RT1017_SDCA_SDW + tristate "Realtek RT1017 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + config SND_SOC_RT1019 tristate depends on I2C @@ -1724,6 +1757,7 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate depends on SND_SOC_AC97_BUS + select REGMAP_AC97 config SND_SOC_STI_SAS tristate "codec Audio support for STI SAS codec" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20d1a841991d..95cbb42253e2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -45,10 +45,12 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-ak5558-objs := ak5558.o snd-soc-arizona-objs := arizona.o arizona-jack.o +snd-soc-audio-iio-aux-objs := audio-iio-aux.o snd-soc-aw8738-objs := aw8738.o snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o snd-soc-aw88395-objs := aw88395/aw88395.o \ aw88395/aw88395_device.o +snd-soc-aw88261-objs := aw88261.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-chv3-codec-objs := chv3-codec.o @@ -206,6 +208,7 @@ snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o snd-soc-rt1016-objs := rt1016.o +snd-soc-rt1017-sdca-objs := rt1017-sdca-sdw.o snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o @@ -430,9 +433,11 @@ obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o 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_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 obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o @@ -585,6 +590,7 @@ obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o +obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW) += snd-soc-rt1017-sdca.o obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2c64df96b5ce..949077108bef 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -358,7 +358,7 @@ static const struct regmap_config ad1836_regmap_config = { .max_register = AD1836_ADC_CTRL3, .reg_defaults = ad1836_reg_defaults, .num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int ad1836_spi_probe(struct spi_device *spi) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 5e777d7fd5d9..3c1ae13c1aae 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -92,7 +92,7 @@ static const struct regmap_config ad1980_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, .readable_reg = ad1980_readable_reg, diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index d9bde7eb043a..98380a7ce64d 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -1056,7 +1056,7 @@ const struct regmap_config adau1372_regmap_config = { .reg_defaults = adau1372_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults), .volatile_reg = adau1372_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1372_regmap_config); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index c5b087b8fffc..b0ab0a69b207 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1451,7 +1451,7 @@ static const struct regmap_config adau1373_regmap_config = { .volatile_reg = adau1373_register_volatile, .max_register = ADAU1373_SOFT_RESET, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adau1373_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults), }; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 8c8de3b3c901..94831aad7ac6 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -778,7 +778,7 @@ static const struct regmap_config adau1701_regmap = { .reg_bits = 16, .val_bits = 32, .max_register = ADAU1701_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = adau1701_volatile_reg, .reg_write = adau1701_reg_write, .reg_read = adau1701_reg_read, diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 3ccc7acac205..1f09ea385f8a 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -1014,7 +1014,7 @@ const struct regmap_config adau1761_regmap_config = { .readable_reg = adau1761_readable_register, .volatile_reg = adau17x1_volatile_register, .precious_reg = adau17x1_precious_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1761_regmap_config); diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index ff6be24863bf..faad2f9f8dd2 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -472,7 +472,7 @@ const struct regmap_config adau1781_regmap_config = { .readable_reg = adau1781_readable_register, .volatile_reg = adau17x1_volatile_register, .precious_reg = adau17x1_precious_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(adau1781_regmap_config); diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 7a9672f94fc6..ae59efb38f26 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -991,7 +991,7 @@ const struct regmap_config adau1977_regmap_config = { .max_register = ADAU1977_REG_DC_HPF_CAL, .volatile_reg = adau1977_register_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adau1977_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), }; diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index 73f181f7757e..b302b28eca7c 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -43,7 +43,7 @@ static const struct regmap_config adau7118_regmap_config = { .val_bits = 8, .reg_defaults = adau7118_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = ADAU7118_REG_RESET, .volatile_reg = adau7118_volatile, }; diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index fcff35f26cec..bb08969c5917 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -870,7 +870,7 @@ const struct regmap_config adav80x_regmap_config = { .max_register = ADAV80X_PLL_OUTE, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = adav80x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), }; diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index ad56caec9dac..619a817ee91c 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv, static int ak4613_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; - struct device_node *np = dev->of_node; const struct regmap_config *regmap_cfg; struct regmap *regmap; struct ak4613_priv *priv; - regmap_cfg = NULL; - if (np) - regmap_cfg = of_device_get_match_data(dev); - else { - const struct i2c_device_id *id = - i2c_match_id(ak4613_i2c_id, i2c); - regmap_cfg = (const struct regmap_config *)id->driver_data; - } - + regmap_cfg = i2c_get_match_data(i2c); if (!regmap_cfg) return -EINVAL; diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c new file mode 100644 index 000000000000..a8bf14239bd7 --- /dev/null +++ b/sound/soc/codecs/audio-iio-aux.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC glue to use IIO devices as audio components +// +// Copyright 2023 CS GROUP France +// +// Author: Herve Codina <herve.codina@bootlin.com> + +#include <linux/iio/consumer.h> +#include <linux/minmax.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string_helpers.h> + +#include <sound/soc.h> +#include <sound/tlv.h> + +struct audio_iio_aux_chan { + struct iio_channel *iio_chan; + const char *name; + int max; + int min; + bool is_invert_range; +}; + +struct audio_iio_aux { + struct device *dev; + struct audio_iio_aux_chan *chans; + unsigned int num_chans; +}; + +static int audio_iio_aux_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = chan->max - chan->min; + uinfo->type = (uinfo->value.integer.max == 1) ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + return 0; +} + +static int audio_iio_aux_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + int max = chan->max; + int min = chan->min; + bool invert_range = chan->is_invert_range; + int ret; + int val; + + ret = iio_read_channel_raw(chan->iio_chan, &val); + if (ret < 0) + return ret; + + ucontrol->value.integer.value[0] = val - min; + if (invert_range) + ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; + + return 0; +} + +static int audio_iio_aux_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value; + int max = chan->max; + int min = chan->min; + bool invert_range = chan->is_invert_range; + int val; + int ret; + int tmp; + + val = ucontrol->value.integer.value[0]; + if (val < 0) + return -EINVAL; + if (val > max - min) + return -EINVAL; + + val = val + min; + if (invert_range) + val = max - val; + + ret = iio_read_channel_raw(chan->iio_chan, &tmp); + if (ret < 0) + return ret; + + if (tmp == val) + return 0; + + ret = iio_write_channel_raw(chan->iio_chan, val); + if (ret) + return ret; + + return 1; /* The value changed */ +} + +static int audio_iio_aux_add_controls(struct snd_soc_component *component, + struct audio_iio_aux_chan *chan) +{ + struct snd_kcontrol_new control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = chan->name, + .info = audio_iio_aux_info_volsw, + .get = audio_iio_aux_get_volsw, + .put = audio_iio_aux_put_volsw, + .private_value = (unsigned long)chan, + }; + + return snd_soc_add_component_controls(component, &control, 1); +} + +/* + * These data could be on stack but they are pretty big. + * As ASoC internally copy them and protect them against concurrent accesses + * (snd_soc_bind_card() protects using client_mutex), keep them in the global + * data area. + */ +static struct snd_soc_dapm_widget widgets[3]; +static struct snd_soc_dapm_route routes[2]; + +/* Be sure sizes are correct (need 3 widgets and 2 routes) */ +static_assert(ARRAY_SIZE(widgets) >= 3, "3 widgets are needed"); +static_assert(ARRAY_SIZE(routes) >= 2, "2 routes are needed"); + +static int audio_iio_aux_add_dapms(struct snd_soc_component *component, + struct audio_iio_aux_chan *chan) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + char *output_name; + char *input_name; + char *pga_name; + int ret; + + input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name); + if (!input_name) + return -ENOMEM; + + output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name); + if (!output_name) { + ret = -ENOMEM; + goto out_free_input_name; + } + + pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name); + if (!pga_name) { + ret = -ENOMEM; + goto out_free_output_name; + } + + widgets[0] = SND_SOC_DAPM_INPUT(input_name); + widgets[1] = SND_SOC_DAPM_OUTPUT(output_name); + widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0); + ret = snd_soc_dapm_new_controls(dapm, widgets, 3); + if (ret) + goto out_free_pga_name; + + routes[0].sink = pga_name; + routes[0].control = NULL; + routes[0].source = input_name; + routes[1].sink = output_name; + routes[1].control = NULL; + routes[1].source = pga_name; + ret = snd_soc_dapm_add_routes(dapm, routes, 2); + + /* Allocated names are no more needed (duplicated in ASoC internals) */ + +out_free_pga_name: + kfree(pga_name); +out_free_output_name: + kfree(output_name); +out_free_input_name: + kfree(input_name); + return ret; +} + +static int audio_iio_aux_component_probe(struct snd_soc_component *component) +{ + struct audio_iio_aux *iio_aux = snd_soc_component_get_drvdata(component); + struct audio_iio_aux_chan *chan; + int ret; + int i; + + for (i = 0; i < iio_aux->num_chans; i++) { + chan = iio_aux->chans + i; + + ret = iio_read_max_channel_raw(chan->iio_chan, &chan->max); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot get max raw value\n", + i, chan->name); + + ret = iio_read_min_channel_raw(chan->iio_chan, &chan->min); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot get min raw value\n", + i, chan->name); + + if (chan->min > chan->max) { + /* + * This should never happen but to avoid any check + * later, just swap values here to ensure that the + * minimum value is lower than the maximum value. + */ + dev_dbg(component->dev, "chan[%d] %s: Swap min and max\n", + i, chan->name); + swap(chan->min, chan->max); + } + + /* Set initial value */ + ret = iio_write_channel_raw(chan->iio_chan, + chan->is_invert_range ? chan->max : chan->min); + if (ret) + return dev_err_probe(component->dev, ret, + "chan[%d] %s: Cannot set initial value\n", + i, chan->name); + + ret = audio_iio_aux_add_controls(component, chan); + if (ret) + return ret; + + ret = audio_iio_aux_add_dapms(component, chan); + if (ret) + return ret; + + dev_dbg(component->dev, "chan[%d]: Added %s (min=%d, max=%d, invert=%s)\n", + i, chan->name, chan->min, chan->max, + str_on_off(chan->is_invert_range)); + } + + return 0; +} + +static const struct snd_soc_component_driver audio_iio_aux_component_driver = { + .probe = audio_iio_aux_component_probe, +}; + +static int audio_iio_aux_probe(struct platform_device *pdev) +{ + struct audio_iio_aux_chan *iio_aux_chan; + struct device *dev = &pdev->dev; + struct audio_iio_aux *iio_aux; + const char **names; + u32 *invert_ranges; + int count; + int ret; + int i; + + iio_aux = devm_kzalloc(dev, sizeof(*iio_aux), GFP_KERNEL); + if (!iio_aux) + return -ENOMEM; + + iio_aux->dev = dev; + + count = device_property_string_array_count(dev, "io-channel-names"); + if (count < 0) + return dev_err_probe(dev, count, "failed to count io-channel-names\n"); + + iio_aux->num_chans = count; + + iio_aux->chans = devm_kmalloc_array(dev, iio_aux->num_chans, + sizeof(*iio_aux->chans), GFP_KERNEL); + if (!iio_aux->chans) + return -ENOMEM; + + names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL); + if (!names) + return -ENOMEM; + + invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL); + if (!invert_ranges) { + ret = -ENOMEM; + goto out_free_names; + } + + ret = device_property_read_string_array(dev, "io-channel-names", + names, iio_aux->num_chans); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to read io-channel-names\n"); + goto out_free_invert_ranges; + } + + /* + * snd-control-invert-range is optional and can contain fewer items + * than the number of channels. Unset values default to 0. + */ + count = device_property_count_u32(dev, "snd-control-invert-range"); + if (count > 0) { + count = min_t(unsigned int, count, iio_aux->num_chans); + ret = device_property_read_u32_array(dev, "snd-control-invert-range", + invert_ranges, count); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n"); + goto out_free_invert_ranges; + } + } + + for (i = 0; i < iio_aux->num_chans; i++) { + iio_aux_chan = iio_aux->chans + i; + iio_aux_chan->name = names[i]; + iio_aux_chan->is_invert_range = invert_ranges[i]; + + iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name); + if (IS_ERR(iio_aux_chan->iio_chan)) { + ret = PTR_ERR(iio_aux_chan->iio_chan); + dev_err_probe(dev, ret, "get IIO channel '%s' failed\n", + iio_aux_chan->name); + goto out_free_invert_ranges; + } + } + + platform_set_drvdata(pdev, iio_aux); + + ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver, + NULL, 0); +out_free_invert_ranges: + kfree(invert_ranges); +out_free_names: + kfree(names); + return ret; +} + +static const struct of_device_id audio_iio_aux_ids[] = { + { .compatible = "audio-iio-aux" }, + { } +}; +MODULE_DEVICE_TABLE(of, audio_iio_aux_ids); + +static struct platform_driver audio_iio_aux_driver = { + .driver = { + .name = "audio-iio-aux", + .of_match_table = audio_iio_aux_ids, + }, + .probe = audio_iio_aux_probe, +}; +module_platform_driver(audio_iio_aux_driver); + +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); +MODULE_DESCRIPTION("IIO ALSA SoC aux driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c new file mode 100644 index 000000000000..6e2266b71386 --- /dev/null +++ b/sound/soc/codecs/aw88261.c @@ -0,0 +1,1300 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.c -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang <zhangjianming@awinic.com> +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#include <linux/i2c.h> +#include <linux/firmware.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw88261.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h" + +static const struct regmap_config aw88261_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88261_REG_MAX - 1, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int real_value, volume; + unsigned int reg_value; + + volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL); + real_value = DB_TO_REG_VAL(volume); + + regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, ®_value); + + real_value = (real_value | (reg_value & AW88261_VOL_START_MASK)); + + dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value); + + regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value); +} + +static void aw88261_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) { + aw88261_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, + aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88261_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88261_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) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88261_MUTE_VOL) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + if (flag) + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG, + ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE); +} + +static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + if (pwd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE); +} + +static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + if (amppd) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE); +} + +static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw88261_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE); + aw88261_dev_fade_in(aw_dev); + } +} + +static void aw88261_dev_clear_int_status(struct aw_device *aw_dev) +{ + unsigned int int_status; + + /* read int status and clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + /* make sure int status is clear */ + regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status); + + dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status); +} + +static int aw88261_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return ret; +} + +static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return ret; + } + } + + return -EPERM; +} + +static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88261_CCO_MUX_MASK); + if (reg_val == AW88261_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, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88261_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88261_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return ret; +} + +static int aw88261_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, ®_val); + if (ret) + return ret; + + check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) + & AW88261_BIT_SYSST_CHECK; + if (check_val != AW88261_BIT_SYSST_CHECK) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, AW88261_BIT_SYSST_CHECK); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + if (uls_hmute) + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, + ~AW88261_ULS_HMUTE_MASK, + AW88261_ULS_HMUTE_DISABLE_VALUE); +} + +static void aw88261_reg_force_set(struct aw88261 *aw88261) +{ + if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) { + /* set FORCE_PWM */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG, + AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE); + /* set BOOST_OS_WIDTH */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG, + AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE); + /* set BURST_LOOPR */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG, + AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE); + /* set RSQN_DLY */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG, + AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE); + /* set BURST_SSMODE */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG, + AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE); + /* set BST_BURST */ + regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG, + AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE); + } else { + dev_dbg(aw88261->aw_pa->dev, "needn't set reg value"); + } +} + +static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk) +{ + u16 reg_icalk, reg_icalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, ®_val); + if (ret) + return ret; + + reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, ®_val); + if (ret) + return ret; + + reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK); + + reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT); + + if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK)) + reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG; + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk) +{ + u16 reg_vcalk, reg_vcalkl; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + + reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + + reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK); + + reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT); + + if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK) + reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG); + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw88261_dev_set_vcalb(struct aw_device *aw_dev) +{ + int16_t icalk_val, vcalk_val; + int icalk, vcalk, vcalb; + u32 reg_val; + int ret; + + ret = aw88261_dev_get_icalk(aw_dev, &icalk_val); + if (ret) + return ret; + + ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val); + if (ret) + return ret; + + icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val; + vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val; + if (!vcalk) + return -EINVAL; + + vcalb = AW88261_VCAL_FACTOR * icalk / vcalk; + reg_val = (unsigned int)vcalb; + + dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x", + icalk, vcalk, vcalb, reg_val); + ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val); + + return ret; +} + +static int aw88261_dev_reg_update(struct aw88261 *aw88261, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int read_val, efcheck_val, 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 == AW88261_SYSCTRL_REG) { + aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK); + ret = regmap_read(aw_dev->regmap, reg_addr, &read_val); + if (ret) + break; + + read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) | + (~AW88261_HMUTE_MASK); + reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK); + reg_val |= read_val; + + /* enable uls hmute */ + reg_val &= AW88261_ULS_HMUTE_MASK; + reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE; + } + + if (reg_addr == AW88261_DBGCTRL_REG) { + efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK); + if (efcheck_val == AW88261_OR_VALUE) + aw88261->efuse_check = AW88261_EF_OR_CHECK; + else + aw88261->efuse_check = AW88261_EF_AND_CHECK; + } + + /* i2stxen */ + if (reg_addr == AW88261_I2SCTRL3_REG) { + /* close tx */ + reg_val &= AW88261_I2STXEN_MASK; + reg_val |= AW88261_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88261_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88261_VOL_MASK)) >> + AW88261_VOL_START_BIT; + aw_dev->volume_desc.init_volume = + REG_VAL_TO_DB(read_vol); + } + + if (reg_addr == AW88261_VSNTM1_REG) + continue; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + break; + } + + ret = aw88261_dev_set_vcalb(aw_dev); + if (ret) + return ret; + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + + /* keep min volume */ + aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume); + + return ret; +} + +static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) +{ + 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 NULL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return prof_info->prof_name_list[prof_desc->id]; +} + +static int aw88261_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 aw88261_dev_fw_update(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index); + if (!prof_name) { + dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88261_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 = aw88261_dev_reg_update(aw88261, 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 ret; +} + +static int aw88261_dev_start(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (aw_dev->status == AW88261_DEV_PW_ON) { + dev_info(aw_dev->dev, "already power on"); + return 0; + } + + /* power on */ + aw88261_dev_pwd(aw_dev, false); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + + ret = aw88261_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw88261_dev_amppd(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 50); + + /* check i2s status */ + ret = aw88261_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + /* enable tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, true); + + if (aw88261->amppd_st) + aw88261_dev_amppd(aw_dev, true); + + aw88261_reg_force_set(aw88261); + + /* close uls mute */ + aw88261_dev_uls_hmute(aw_dev, false); + + /* close mute */ + if (!aw88261->mute_st) + aw88261_dev_mute(aw_dev, false); + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + aw_dev->status = AW88261_DEV_PW_ON; + + return 0; + +sysst_check_fail: + aw88261_dev_i2s_tx_enable(aw_dev, false); + aw88261_dev_clear_int_status(aw_dev); + aw88261_dev_amppd(aw_dev, true); +pll_check_fail: + aw88261_dev_pwd(aw_dev, true); + aw_dev->status = AW88261_DEV_PW_OFF; + + return ret; +} + +static int aw88261_dev_stop(struct aw_device *aw_dev) +{ + if (aw_dev->status == AW88261_DEV_PW_OFF) { + dev_info(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88261_DEV_PW_OFF; + + /* clear inturrupt */ + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + /* set mute */ + aw88261_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw88261_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + /* enable amppd */ + aw88261_dev_amppd(aw_dev, true); + + /* set power down */ + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_reg_update(struct aw88261 *aw88261, bool force) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + int ret; + + if (force) { + ret = regmap_write(aw_dev->regmap, + AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } else { + if (aw_dev->prof_cur != aw_dev->prof_index) { + ret = aw88261_dev_fw_update(aw88261); + if (ret) + return ret; + } else { + ret = 0; + } + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static void aw88261_start_pa(struct aw88261 *aw88261) +{ + int ret, i; + + for (i = 0; i < AW88261_START_RETRIES; i++) { + ret = aw88261_reg_update(aw88261, aw88261->phase_sync); + if (ret) { + dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i); + continue; + } + ret = aw88261_dev_start(aw88261); + if (ret) { + dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i); + continue; + } else { + dev_info(aw88261->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88261_startup_work(struct work_struct *work) +{ + struct aw88261 *aw88261 = + container_of(work, struct aw88261, start_work.work); + + mutex_lock(&aw88261->lock); + aw88261_start_pa(aw88261); + mutex_unlock(&aw88261->lock); +} + +static void aw88261_start(struct aw88261 *aw88261, bool sync_start) +{ + if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK) + return; + + if (aw88261->aw_pa->status == AW88261_DEV_PW_ON) + return; + + if (sync_start == AW88261_SYNC_START) + aw88261_start_pa(aw88261); + else + queue_delayed_work(system_wq, + &aw88261->start_work, + AW88261_START_WORK_DELAY_MS); +} + +static struct snd_soc_dai_driver aw88261_dai[] = { + { + .name = "aw88261-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88261_RATES, + .formats = AW88261_FORMATS, + }, + }, +}; + +static int aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->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 aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->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 aw88261_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 aw88261_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + const char *prof_name; + char *name; + int count; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88261->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; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + + prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count); + if (!prof_name) { + strscpy(uinfo->value.enumerated.name, "null", + strlen("null") + 1); + return 0; + } + + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88261_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index; + + return 0; +} + +static int aw88261_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + int ret; + + /* pa stop or stopping just set profile */ + mutex_lock(&aw88261->lock); + ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88261->lock); + return 0; + } + + if (aw88261->aw_pa->status) { + aw88261_dev_stop(aw88261->aw_pa); + aw88261_start(aw88261, AW88261_SYNC_START); + } + + mutex_unlock(&aw88261->lock); + + return 1; +} + +static int aw88261_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88261_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88261->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; + aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume); + + return 1; + } + + return 0; +} + +static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step; + + return 0; +} + +static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88261 *aw88261 = 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 (aw88261->aw_pa->fade_step != value) { + aw88261->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new aw88261_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG, + 6, AW88261_MUTE_VOL, 0, aw88261_volume_get, + aw88261_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0, + aw88261_get_fade_step, aw88261_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_in_time, aw88261_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_out_time, aw88261_set_fade_out_time), + AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info, + aw88261_profile_get, aw88261_profile_set), +}; + +static int aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88261->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88261_start(aw88261, AW88261_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88261_dev_stop(aw88261->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88261->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0, + aw88261_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 aw88261_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88261_frcset_check(struct aw88261 *aw88261) +{ + unsigned int reg_val; + u16 temh, teml, tem; + int ret; + + ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, ®_val); + if (ret) + return ret; + temh = ((u16)reg_val & (~AW88261_TEMH_MASK)); + + ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, ®_val); + if (ret) + return ret; + teml = ((u16)reg_val & (~AW88261_TEML_MASK)); + + if (aw88261->efuse_check == AW88261_EF_OR_CHECK) + tem = (temh | teml); + else + tem = (temh & teml); + + if (tem == AW88261_DEFAULT_CFG) + aw88261->frcset_en = AW88261_FRCSET_ENABLE; + else + aw88261->frcset_en = AW88261_FRCSET_DISABLE; + + dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d", + tem, aw88261->frcset_en); + + return ret; +} + +static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88261->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, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE); + if (ret) + return ret; + + aw_dev->fade_in_time = AW88261_500_US; + aw_dev->fade_out_time = AW88261_500_US; + aw_dev->prof_cur = AW88261_INIT_PROFILE; + aw_dev->prof_index = AW88261_INIT_PROFILE; + + ret = aw88261_dev_fw_update(aw88261); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + ret = aw88261_frcset_check(aw88261); + if (ret) { + dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret); + return ret; + } + + aw88261_dev_clear_int_status(aw_dev); + + aw88261_dev_uls_hmute(aw_dev, true); + + aw88261_dev_mute(aw_dev, true); + + aw88261_dev_i2s_tx_enable(aw_dev, false); + + usleep_range(AW88261_1000_US, AW88261_1000_US + 100); + + aw88261_dev_amppd(aw_dev, true); + + aw88261_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88261_request_firmware_file(struct aw88261 *aw88261) +{ + const struct firmware *cont = NULL; + int ret; + + aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "load [%s] failed!", AW88261_ACF_FILE); + + dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n", + AW88261_ACF_FILE, cont ? cont->size : 0); + + aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88261->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88261->aw_cfg->len = (int)cont->size; + memcpy(aw88261->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg); + if (ret) { + dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE); + return ret; + } + + mutex_lock(&aw88261->lock); + /* aw device init */ + ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); + if (ret) + dev_err(aw88261->aw_pa->dev, "dev init failed"); + mutex_unlock(&aw88261->lock); + + return ret; +} + +static int aw88261_codec_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work); + + ret = aw88261_request_firmware_file(aw88261); + if (ret) + return dev_err_probe(aw88261->aw_pa->dev, ret, + "aw88261_request_firmware_file failed\n"); + + /* add widgets */ + ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets, + ARRAY_SIZE(aw88261_dapm_widgets)); + if (ret) + return ret; + + /* add route */ + ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map, + ARRAY_SIZE(aw88261_audio_map)); + if (ret) + return ret; + + ret = snd_soc_add_component_controls(component, aw88261_controls, + ARRAY_SIZE(aw88261_controls)); + + return ret; +} + +static void aw88261_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88261->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88261 = { + .probe = aw88261_codec_probe, + .remove = aw88261_codec_remove, +}; + +static void aw88261_hw_reset(struct aw88261 *aw88261) +{ + gpiod_set_value_cansleep(aw88261->reset_gpio, 0); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); + gpiod_set_value_cansleep(aw88261->reset_gpio, 1); + usleep_range(AW88261_1000_US, AW88261_1000_US + 10); +} + +static void aw88261_parse_channel_dt(struct aw88261 *aw88261) +{ + struct aw_device *aw_dev = aw88261->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW88261_DEV_DEFAULT_CH; + u32 sync_enable = false; + + of_property_read_u32(np, "sound-channel", &channel_value); + of_property_read_u32(np, "sync-flag", &sync_enable); + + aw_dev->channel = channel_value; + aw88261->phase_sync = sync_enable; +} + +static int aw88261_init(struct aw88261 **aw88261, 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, AW88261_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88261_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + + dev_info(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + (*aw88261)->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW88261_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = 0; + aw_dev->fw_status = AW88261_DEV_FW_FAILED; + aw_dev->fade_step = AW88261_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE; + aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL; + aw88261_parse_channel_dt(*aw88261); + + return ret; +} + +static int aw88261_i2c_probe(struct i2c_client *i2c) +{ + struct aw88261 *aw88261; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, ret, "check_functionality failed"); + + aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL); + if (!aw88261) + return -ENOMEM; + + mutex_init(&aw88261->lock); + + i2c_set_clientdata(i2c, aw88261); + + aw88261->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(aw88261->reset_gpio)) + dev_info(&i2c->dev, "reset gpio not defined\n"); + else + aw88261_hw_reset(aw88261); + + aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config); + if (IS_ERR(aw88261->regmap)) { + ret = PTR_ERR(aw88261->regmap); + return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret); + } + + /* aw pa init */ + ret = aw88261_init(&aw88261, i2c, aw88261->regmap); + if (ret) + return ret; + + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88261, + aw88261_dai, ARRAY_SIZE(aw88261_dai)); + if (ret) + dev_err(&i2c->dev, "failed to register aw88261: %d", ret); + + return ret; +} + +static const struct i2c_device_id aw88261_i2c_id[] = { + { AW88261_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id); + +static struct i2c_driver aw88261_i2c_driver = { + .driver = { + .name = AW88261_I2C_NAME, + }, + .probe = aw88261_i2c_probe, + .id_table = aw88261_i2c_id, +}; +module_i2c_driver(aw88261_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h new file mode 100644 index 000000000000..4f3dbf438510 --- /dev/null +++ b/sound/soc/codecs/aw88261.h @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88261.h -- AW88261 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Jimmy Zhang <zhangjianming@awinic.com> +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#ifndef __AW88261_H__ +#define __AW88261_H__ + +#define AW88261_ID_REG (0x00) +#define AW88261_SYSST_REG (0x01) +#define AW88261_SYSINT_REG (0x02) +#define AW88261_SYSINTM_REG (0x03) +#define AW88261_SYSCTRL_REG (0x04) +#define AW88261_SYSCTRL2_REG (0x05) +#define AW88261_I2SCTRL1_REG (0x06) +#define AW88261_I2SCTRL2_REG (0x07) +#define AW88261_I2SCTRL3_REG (0x08) +#define AW88261_DACCFG1_REG (0x09) +#define AW88261_DACCFG2_REG (0x0A) +#define AW88261_DACCFG3_REG (0x0B) +#define AW88261_DACCFG4_REG (0x0C) +#define AW88261_DACCFG5_REG (0x0D) +#define AW88261_DACCFG6_REG (0x0E) +#define AW88261_DACCFG7_REG (0x0F) +#define AW88261_DACCFG8_REG (0x10) +#define AW88261_PWMCTRL1_REG (0x11) +#define AW88261_PWMCTRL2_REG (0x12) +#define AW88261_I2SCFG1_REG (0x13) +#define AW88261_DBGCTRL_REG (0x14) +#define AW88261_DACCFG9_REG (0x15) +#define AW88261_DACCFG10_REG (0x16) +#define AW88261_DACST_REG (0x20) +#define AW88261_VBAT_REG (0x21) +#define AW88261_TEMP_REG (0x22) +#define AW88261_PVDD_REG (0x23) +#define AW88261_ISNDAT_REG (0x24) +#define AW88261_VSNDAT_REG (0x25) +#define AW88261_I2SINT_REG (0x26) +#define AW88261_I2SCAPCNT_REG (0x27) +#define AW88261_ANASTA1_REG (0x28) +#define AW88261_ANASTA2_REG (0x29) +#define AW88261_ANASTA3_REG (0x2A) +#define AW88261_TESTDET_REG (0x2B) +#define AW88261_DSMCFG1_REG (0x30) +#define AW88261_DSMCFG2_REG (0x31) +#define AW88261_DSMCFG3_REG (0x32) +#define AW88261_DSMCFG4_REG (0x33) +#define AW88261_DSMCFG5_REG (0x34) +#define AW88261_DSMCFG6_REG (0x35) +#define AW88261_DSMCFG7_REG (0x36) +#define AW88261_DSMCFG8_REG (0x37) +#define AW88261_TESTIN_REG (0x38) +#define AW88261_TESTOUT_REG (0x39) +#define AW88261_SADCCTRL1_REG (0x3A) +#define AW88261_SADCCTRL2_REG (0x3B) +#define AW88261_SADCCTRL3_REG (0x3C) +#define AW88261_SADCCTRL4_REG (0x3D) +#define AW88261_SADCCTRL5_REG (0x3E) +#define AW88261_SADCCTRL6_REG (0x3F) +#define AW88261_SADCCTRL7_REG (0x40) +#define AW88261_VSNTM1_REG (0x50) +#define AW88261_VSNTM2_REG (0x51) +#define AW88261_ISNCTRL1_REG (0x52) +#define AW88261_ISNCTRL2_REG (0x53) +#define AW88261_PLLCTRL1_REG (0x54) +#define AW88261_PLLCTRL2_REG (0x55) +#define AW88261_PLLCTRL3_REG (0x56) +#define AW88261_CDACTRL1_REG (0x57) +#define AW88261_CDACTRL2_REG (0x58) +#define AW88261_DITHERCFG1_REG (0x59) +#define AW88261_DITHERCFG2_REG (0x5A) +#define AW88261_DITHERCFG3_REG (0x5B) +#define AW88261_CPCTRL_REG (0x5C) +#define AW88261_BSTCTRL1_REG (0x60) +#define AW88261_BSTCTRL2_REG (0x61) +#define AW88261_BSTCTRL3_REG (0x62) +#define AW88261_BSTCTRL4_REG (0x63) +#define AW88261_BSTCTRL5_REG (0x64) +#define AW88261_BSTCTRL6_REG (0x65) +#define AW88261_BSTCTRL7_REG (0x66) +#define AW88261_BSTCTRL8_REG (0x67) +#define AW88261_BSTCTRL9_REG (0x68) +#define AW88261_TM_REG (0x6F) +#define AW88261_TESTCTRL1_REG (0x70) +#define AW88261_TESTCTRL2_REG (0x71) +#define AW88261_EFCTRL1_REG (0x72) +#define AW88261_EFCTRL2_REG (0x73) +#define AW88261_EFWH_REG (0x74) +#define AW88261_EFWM2_REG (0x75) +#define AW88261_EFWM1_REG (0x76) +#define AW88261_EFWL_REG (0x77) +#define AW88261_EFRH4_REG (0x78) +#define AW88261_EFRH3_REG (0x79) +#define AW88261_EFRH2_REG (0x7A) +#define AW88261_EFRH1_REG (0x7B) +#define AW88261_EFRL4_REG (0x7C) +#define AW88261_EFRL3_REG (0x7D) +#define AW88261_EFRL2_REG (0x7E) +#define AW88261_EFRL1_REG (0x7F) + +#define AW88261_REG_MAX (0x80) +#define AW88261_EF_DBMD_MASK (0xfff7) +#define AW88261_OR_VALUE (0x0008) + +#define AW88261_TEMH_MASK (0x83ff) +#define AW88261_TEML_MASK (0x83ff) +#define AW88261_DEFAULT_CFG (0x0000) + +#define AW88261_ICALK_SHIFT (0) +#define AW88261_ICALKL_SHIFT (0) +#define AW88261_VCALK_SHIFT (0) +#define AW88261_VCALKL_SHIFT (0) + +#define AW88261_AMPPD_START_BIT (1) +#define AW88261_AMPPD_BITS_LEN (1) +#define AW88261_AMPPD_MASK \ + (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT)) + +#define AW88261_UVLS_START_BIT (14) +#define AW88261_UVLS_NORMAL (0) +#define AW88261_UVLS_NORMAL_VALUE \ + (AW88261_UVLS_NORMAL << AW88261_UVLS_START_BIT) + +#define AW88261_BSTOCS_START_BIT (11) +#define AW88261_BSTOCS_OVER_CURRENT (1) +#define AW88261_BSTOCS_OVER_CURRENT_VALUE \ + (AW88261_BSTOCS_OVER_CURRENT << AW88261_BSTOCS_START_BIT) + +#define AW88261_BSTS_START_BIT (9) +#define AW88261_BSTS_FINISHED (1) +#define AW88261_BSTS_FINISHED_VALUE \ + (AW88261_BSTS_FINISHED << AW88261_BSTS_START_BIT) + +#define AW88261_SWS_START_BIT (8) +#define AW88261_SWS_SWITCHING (1) +#define AW88261_SWS_SWITCHING_VALUE \ + (AW88261_SWS_SWITCHING << AW88261_SWS_START_BIT) + +#define AW88261_NOCLKS_START_BIT (5) +#define AW88261_NOCLKS_NO_CLOCK (1) +#define AW88261_NOCLKS_NO_CLOCK_VALUE \ + (AW88261_NOCLKS_NO_CLOCK << AW88261_NOCLKS_START_BIT) + +#define AW88261_CLKS_START_BIT (4) +#define AW88261_CLKS_STABLE (1) +#define AW88261_CLKS_STABLE_VALUE \ + (AW88261_CLKS_STABLE << AW88261_CLKS_START_BIT) + +#define AW88261_OCDS_START_BIT (3) +#define AW88261_OCDS_OC (1) +#define AW88261_OCDS_OC_VALUE \ + (AW88261_OCDS_OC << AW88261_OCDS_START_BIT) + +#define AW88261_OTHS_START_BIT (1) +#define AW88261_OTHS_OT (1) +#define AW88261_OTHS_OT_VALUE \ + (AW88261_OTHS_OT << AW88261_OTHS_START_BIT) + +#define AW88261_PLLS_START_BIT (0) +#define AW88261_PLLS_LOCKED (1) +#define AW88261_PLLS_LOCKED_VALUE \ + (AW88261_PLLS_LOCKED << AW88261_PLLS_START_BIT) + +#define AW88261_BIT_PLL_CHECK \ + (AW88261_CLKS_STABLE_VALUE | \ + AW88261_PLLS_LOCKED_VALUE) + +#define AW88261_BIT_SYSST_CHECK_MASK \ + (~(AW88261_UVLS_NORMAL_VALUE | \ + AW88261_BSTOCS_OVER_CURRENT_VALUE | \ + AW88261_BSTS_FINISHED_VALUE | \ + AW88261_SWS_SWITCHING_VALUE | \ + AW88261_NOCLKS_NO_CLOCK_VALUE | \ + AW88261_CLKS_STABLE_VALUE | \ + AW88261_OCDS_OC_VALUE | \ + AW88261_OTHS_OT_VALUE | \ + AW88261_PLLS_LOCKED_VALUE)) + +#define AW88261_BIT_SYSST_CHECK \ + (AW88261_BSTS_FINISHED_VALUE | \ + AW88261_SWS_SWITCHING_VALUE | \ + AW88261_CLKS_STABLE_VALUE | \ + AW88261_PLLS_LOCKED_VALUE) + +#define AW88261_ULS_HMUTE_START_BIT (14) +#define AW88261_ULS_HMUTE_BITS_LEN (1) +#define AW88261_ULS_HMUTE_MASK \ + (~(((1<<AW88261_ULS_HMUTE_BITS_LEN)-1) << AW88261_ULS_HMUTE_START_BIT)) + +#define AW88261_ULS_HMUTE_DISABLE (0) +#define AW88261_ULS_HMUTE_DISABLE_VALUE \ + (AW88261_ULS_HMUTE_DISABLE << AW88261_ULS_HMUTE_START_BIT) + +#define AW88261_ULS_HMUTE_ENABLE (1) +#define AW88261_ULS_HMUTE_ENABLE_VALUE \ + (AW88261_ULS_HMUTE_ENABLE << AW88261_ULS_HMUTE_START_BIT) + +#define AW88261_HMUTE_START_BIT (8) +#define AW88261_HMUTE_BITS_LEN (1) +#define AW88261_HMUTE_MASK \ + (~(((1<<AW88261_HMUTE_BITS_LEN)-1) << AW88261_HMUTE_START_BIT)) + +#define AW88261_HMUTE_DISABLE (0) +#define AW88261_HMUTE_DISABLE_VALUE \ + (AW88261_HMUTE_DISABLE << AW88261_HMUTE_START_BIT) + +#define AW88261_HMUTE_ENABLE (1) +#define AW88261_HMUTE_ENABLE_VALUE \ + (AW88261_HMUTE_ENABLE << AW88261_HMUTE_START_BIT) + +#define AW88261_AMPPD_START_BIT (1) +#define AW88261_AMPPD_BITS_LEN (1) +#define AW88261_AMPPD_MASK \ + (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT)) + +#define AW88261_AMPPD_WORKING (0) +#define AW88261_AMPPD_WORKING_VALUE \ + (AW88261_AMPPD_WORKING << AW88261_AMPPD_START_BIT) + +#define AW88261_AMPPD_POWER_DOWN (1) +#define AW88261_AMPPD_POWER_DOWN_VALUE \ + (AW88261_AMPPD_POWER_DOWN << AW88261_AMPPD_START_BIT) + +#define AW88261_PWDN_START_BIT (0) +#define AW88261_PWDN_BITS_LEN (1) +#define AW88261_PWDN_MASK \ + (~(((1<<AW88261_PWDN_BITS_LEN)-1) << AW88261_PWDN_START_BIT)) + +#define AW88261_PWDN_WORKING (0) +#define AW88261_PWDN_WORKING_VALUE \ + (AW88261_PWDN_WORKING << AW88261_PWDN_START_BIT) + +#define AW88261_PWDN_POWER_DOWN (1) +#define AW88261_PWDN_POWER_DOWN_VALUE \ + (AW88261_PWDN_POWER_DOWN << AW88261_PWDN_START_BIT) + +#define AW88261_MUTE_VOL (90 * 8) +#define AW88261_VOLUME_STEP_DB (6 * 8) + +#define AW88261_VOL_6DB_START (6) + +#define AW88261_VOL_START_BIT (0) +#define AW88261_VOL_BITS_LEN (10) +#define AW88261_VOL_MASK \ + (~(((1<<AW88261_VOL_BITS_LEN)-1) << AW88261_VOL_START_BIT)) + +#define AW88261_VOL_DEFAULT_VALUE (0) + +#define AW88261_I2STXEN_START_BIT (6) +#define AW88261_I2STXEN_BITS_LEN (1) +#define AW88261_I2STXEN_MASK \ + (~(((1<<AW88261_I2STXEN_BITS_LEN)-1) << AW88261_I2STXEN_START_BIT)) + +#define AW88261_I2STXEN_DISABLE (0) +#define AW88261_I2STXEN_DISABLE_VALUE \ + (AW88261_I2STXEN_DISABLE << AW88261_I2STXEN_START_BIT) + +#define AW88261_I2STXEN_ENABLE (1) +#define AW88261_I2STXEN_ENABLE_VALUE \ + (AW88261_I2STXEN_ENABLE << AW88261_I2STXEN_START_BIT) + +#define AW88261_CCO_MUX_START_BIT (14) +#define AW88261_CCO_MUX_BITS_LEN (1) +#define AW88261_CCO_MUX_MASK \ + (~(((1<<AW88261_CCO_MUX_BITS_LEN)-1) << AW88261_CCO_MUX_START_BIT)) + +#define AW88261_CCO_MUX_DIVIDED (0) +#define AW88261_CCO_MUX_DIVIDED_VALUE \ + (AW88261_CCO_MUX_DIVIDED << AW88261_CCO_MUX_START_BIT) + +#define AW88261_CCO_MUX_BYPASS (1) +#define AW88261_CCO_MUX_BYPASS_VALUE \ + (AW88261_CCO_MUX_BYPASS << AW88261_CCO_MUX_START_BIT) + +#define AW88261_EF_VSN_GESLP_H_START_BIT (0) +#define AW88261_EF_VSN_GESLP_H_BITS_LEN (10) +#define AW88261_EF_VSN_GESLP_H_MASK \ + (~(((1<<AW88261_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_H_START_BIT)) + +#define AW88261_EF_VSN_GESLP_L_START_BIT (0) +#define AW88261_EF_VSN_GESLP_L_BITS_LEN (10) +#define AW88261_EF_VSN_GESLP_L_MASK \ + (~(((1<<AW88261_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_L_START_BIT)) + +#define AW88261_FORCE_PWM_START_BIT (12) +#define AW88261_FORCE_PWM_BITS_LEN (1) +#define AW88261_FORCE_PWM_MASK \ + (~(((1<<AW88261_FORCE_PWM_BITS_LEN)-1) << AW88261_FORCE_PWM_START_BIT)) + +#define AW88261_FORCE_PWM_FORCEMINUS_PWM (1) +#define AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE \ + (AW88261_FORCE_PWM_FORCEMINUS_PWM << AW88261_FORCE_PWM_START_BIT) + +#define AW88261_BST_OS_WIDTH_START_BIT (0) +#define AW88261_BST_OS_WIDTH_BITS_LEN (3) +#define AW88261_BST_OS_WIDTH_MASK \ + (~(((1<<AW88261_BST_OS_WIDTH_BITS_LEN)-1) << AW88261_BST_OS_WIDTH_START_BIT)) + +#define AW88261_BST_OS_WIDTH_50NS (4) +#define AW88261_BST_OS_WIDTH_50NS_VALUE \ + (AW88261_BST_OS_WIDTH_50NS << AW88261_BST_OS_WIDTH_START_BIT) + +/* BST_LOOPR bit 1:0 (BSTCTRL6 0x65) */ +#define AW88261_BST_LOOPR_START_BIT (0) +#define AW88261_BST_LOOPR_BITS_LEN (2) +#define AW88261_BST_LOOPR_MASK \ + (~(((1<<AW88261_BST_LOOPR_BITS_LEN)-1) << AW88261_BST_LOOPR_START_BIT)) + +#define AW88261_BST_LOOPR_340K (2) +#define AW88261_BST_LOOPR_340K_VALUE \ + (AW88261_BST_LOOPR_340K << AW88261_BST_LOOPR_START_BIT) + +/* RSQN_DLY bit 15:14 (BSTCTRL7 0x66) */ +#define AW88261_RSQN_DLY_START_BIT (14) +#define AW88261_RSQN_DLY_BITS_LEN (2) +#define AW88261_RSQN_DLY_MASK \ + (~(((1<<AW88261_RSQN_DLY_BITS_LEN)-1) << AW88261_RSQN_DLY_START_BIT)) + +#define AW88261_RSQN_DLY_35NS (2) +#define AW88261_RSQN_DLY_35NS_VALUE \ + (AW88261_RSQN_DLY_35NS << AW88261_RSQN_DLY_START_BIT) + +/* BURST_SSMODE bit 3 (BSTCTRL8 0x67) */ +#define AW88261_BURST_SSMODE_START_BIT (3) +#define AW88261_BURST_SSMODE_BITS_LEN (1) +#define AW88261_BURST_SSMODE_MASK \ + (~(((1<<AW88261_BURST_SSMODE_BITS_LEN)-1) << AW88261_BURST_SSMODE_START_BIT)) + +#define AW88261_BURST_SSMODE_FAST (0) +#define AW88261_BURST_SSMODE_FAST_VALUE \ + (AW88261_BURST_SSMODE_FAST << AW88261_BURST_SSMODE_START_BIT) + +/* BST_BURST bit 9:7 (BSTCTRL9 0x68) */ +#define AW88261_BST_BURST_START_BIT (7) +#define AW88261_BST_BURST_BITS_LEN (3) +#define AW88261_BST_BURST_MASK \ + (~(((1<<AW88261_BST_BURST_BITS_LEN)-1) << AW88261_BST_BURST_START_BIT)) + +#define AW88261_BST_BURST_30MA (2) +#define AW88261_BST_BURST_30MA_VALUE \ + (AW88261_BST_BURST_30MA << AW88261_BST_BURST_START_BIT) + +#define AW88261_EF_VSN_GESLP_SIGN_MASK (~0x0200) +#define AW88261_EF_VSN_GESLP_NEG (~0xfc00) + +#define AW88261_EF_ISN_GESLP_SIGN_MASK (~0x0200) +#define AW88261_EF_ISN_GESLP_NEG (~0xfc00) + +#define AW88261_EF_ISN_GESLP_H_START_BIT (0) +#define AW88261_EF_ISN_GESLP_H_BITS_LEN (10) +#define AW88261_EF_ISN_GESLP_H_MASK \ + (~(((1<<AW88261_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_H_START_BIT)) + +#define AW88261_EF_ISN_GESLP_L_START_BIT (0) +#define AW88261_EF_ISN_GESLP_L_BITS_LEN (10) +#define AW88261_EF_ISN_GESLP_L_MASK \ + (~(((1<<AW88261_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_L_START_BIT)) + +#define AW88261_CABL_BASE_VALUE (1000) +#define AW88261_ICABLK_FACTOR (1) +#define AW88261_VCABLK_FACTOR (1) + +#define AW88261_VCAL_FACTOR (1<<13) + +#define AW88261_START_RETRIES (5) +#define AW88261_START_WORK_DELAY_MS (0) + +#define AW88261_I2C_NAME "aw88261_smartpa" + +#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_96000) +#define AW88261_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define FADE_TIME_MAX 100000 +#define FADE_TIME_MIN 0 + +#define AW88261_DEV_DEFAULT_CH (0) +#define AW88261_ACF_FILE "aw88261_acf.bin" +#define AW88261_DEV_SYSST_CHECK_MAX (10) +#define AW88261_SOFT_RESET_VALUE (0x55aa) +#define AW88261_REG_TO_DB (0x3f) +#define AW88261_VOL_START_MASK (0xfc00) +#define AW88261_INIT_PROFILE (0) + +#define REG_VAL_TO_DB(value) ((((value) >> AW88261_VOL_6DB_START) * \ + AW88261_VOLUME_STEP_DB) + \ + ((value) & AW88261_REG_TO_DB)) +#define DB_TO_REG_VAL(value) ((((value) / AW88261_VOLUME_STEP_DB) << \ + AW88261_VOL_6DB_START) + \ + ((value) % AW88261_VOLUME_STEP_DB)) + +#define AW88261_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 { + AW88261_SYNC_START = 0, + AW88261_ASYNC_START, +}; + +enum aw88261_id { + AW88261_CHIP_ID = 0x2113, +}; + +enum { + AW88261_500_US = 500, + AW88261_1000_US = 1000, + AW88261_2000_US = 2000, +}; + +enum { + AW88261_DEV_PW_OFF = 0, + AW88261_DEV_PW_ON, +}; + +enum { + AW88261_DEV_FW_FAILED = 0, + AW88261_DEV_FW_OK, +}; + +enum { + AW88261_EF_AND_CHECK = 0, + AW88261_EF_OR_CHECK, +}; + +enum { + AW88261_FRCSET_DISABLE = 0, + AW88261_FRCSET_ENABLE, +}; + +struct aw88261 { + struct aw_device *aw_pa; + struct mutex lock; + struct gpio_desc *reset_gpio; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + int efuse_check; + int frcset_en; + unsigned int mute_st; + unsigned int amppd_st; + + unsigned char phase_sync; +}; + +#endif diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 05bcf49da857..8ee1baa03269 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -11,6 +11,7 @@ #include <linux/i2c.h> #include "aw88395_lib.h" #include "aw88395_device.h" +#include "aw88395_reg.h" #define AW88395_CRC8_POLYNOMIAL 0x8C DECLARE_CRC8_TABLE(aw_crc8_table); @@ -429,6 +430,53 @@ parse_bin_failed: return ret; } +static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, + uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc) +{ + struct aw_bin *aw_bin; + int ret; + + aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL); + if (!aw_bin) + return -ENOMEM; + + aw_bin->info.len = data_len; + memcpy(aw_bin->info.data, data, data_len); + + ret = aw_parsing_bin_file(aw_dev, aw_bin); + if (ret < 0) { + dev_err(aw_dev->dev, "parse bin failed"); + goto parse_bin_failed; + } + + if ((aw_bin->all_bin_parse_num != 1) || + (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) { + dev_err(aw_dev->dev, "bin num or type error"); + goto parse_bin_failed; + } + + if (aw_bin->header_info[0].valid_data_len % 4) { + dev_err(aw_dev->dev, "bin data len get error!"); + goto parse_bin_failed; + } + + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = + data + aw_bin->header_info[0].valid_data_addr; + prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = + aw_bin->header_info[0].valid_data_len; + prof_desc->prof_st = AW88395_PROFILE_OK; + + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + + return 0; + +parse_bin_failed: + devm_kfree(aw_dev->dev, aw_bin); + aw_bin = NULL; + return ret; +} + static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr, struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc) { @@ -447,6 +495,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg return aw_dev_prof_parse_multi_bin( aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, cfg_dde->data_size, scene_prof_desc); + case ACF_SEC_TYPE_HDR_REG: + return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset, + cfg_dde->data_size, scene_prof_desc); default: dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type); break; @@ -527,7 +578,49 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, return 0; } -static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, + struct aw_all_prof_info all_prof_info) +{ + struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_info *prof_info = &aw_dev->prof_info; + int num = 0; + int i; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) + prof_info->count++; + } + + dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count); + + if (!prof_info->count) { + dev_err(aw_dev->dev, "no profile data"); + return -EPERM; + } + + prof_info->prof_desc = devm_kcalloc(aw_dev->dev, + prof_info->count, sizeof(struct aw_prof_desc), + GFP_KERNEL); + if (!prof_info->prof_desc) + return -ENOMEM; + + for (i = 0; i < AW88395_PROFILE_MAX; i++) { + if (prof_desc[i].prof_st == AW88395_PROFILE_OK) { + if (num >= prof_info->count) { + dev_err(aw_dev->dev, "overflow count[%d]", + prof_info->count); + return -EINVAL; + } + prof_info->prof_desc[num] = prof_desc[i]; + prof_info->prof_desc[num].id = i; + num++; + } + } + + return 0; +} + +static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; @@ -606,9 +699,22 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, goto exit; } - ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); - if (ret < 0) - goto exit; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + case AW88261_CHIP_ID: + ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + if (ret < 0) + goto exit; + break; + default: + dev_err(aw_dev->dev, "valid prof unsupported"); + ret = -EINVAL; + break; + } aw_dev->prof_info.prof_name_list = profile_name; @@ -679,16 +785,37 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, @@ -699,15 +826,35 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; + int ret; - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; + switch (aw_dev->chip_id) { + case AW88395_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + case AW88261_CHIP_ID: + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; + } + ret = 0; + break; + default: + dev_err(aw_dev->dev, "unsupported device"); + ret = -EINVAL; + break; } - return 0; + return ret; } static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev, @@ -756,6 +903,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev, prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; (*cur_scene_id)++; break; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_parse_reg_bin_with_hdr(aw_dev, + (uint8_t *)prof_hdr + cfg_dde->data_offset, + cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]); + if (ret < 0) { + dev_err(aw_dev->dev, "parse reg bin with hdr failed"); + return ret; + } + prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str; + prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile; + (*cur_scene_id)++; + break; default: dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type); return -EINVAL; diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index e64f24e97150..e7a7c02efaf3 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -96,6 +96,7 @@ enum aw88395_id { AW88395_CHIP_ID = 0x2049, + AW88261_CHIP_ID = 0x2113, }; #define AW88395_REG_MAX (0x7D) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index 04ba7f25012e..20084c7d3acb 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1312,7 +1312,7 @@ static struct regmap_config cs35l36_regmap = { .precious_reg = cs35l36_precious_reg, .volatile_reg = cs35l36_volatile_reg, .readable_reg = cs35l36_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static irqreturn_t cs35l36_irq(int irq, void *data) diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 1e4205295a0d..ac7cc492bcb0 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -743,7 +743,7 @@ struct regmap_config cs35l41_regmap_i2c = { .volatile_reg = cs35l41_volatile_reg, .readable_reg = cs35l41_readable_reg, .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c); @@ -760,7 +760,7 @@ struct regmap_config cs35l41_regmap_spi = { .volatile_reg = cs35l41_volatile_reg, .readable_reg = cs35l41_readable_reg, .precious_reg = cs35l41_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs35l41_regmap_spi); diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c index 066f83c0c7ac..621af1785979 100644 --- a/sound/soc/codecs/cs35l45-tables.c +++ b/sound/soc/codecs/cs35l45-tables.c @@ -255,7 +255,7 @@ const struct regmap_config cs35l45_i2c_regmap = { .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), .volatile_reg = cs35l45_volatile_reg, .readable_reg = cs35l45_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45); @@ -271,7 +271,7 @@ const struct regmap_config cs35l45_spi_regmap = { .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults), .volatile_reg = cs35l45_volatile_reg, .readable_reg = cs35l45_readable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45); diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index ed2a41943d97..9f4f2f4f23f5 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -26,14 +26,14 @@ static int cs35l56_i2c_probe(struct i2c_client *client) if (!cs35l56) return -ENOMEM; - cs35l56->dev = dev; - cs35l56->can_hibernate = true; + cs35l56->base.dev = dev; + cs35l56->base.can_hibernate = true; i2c_set_clientdata(client, cs35l56); - cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); - return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n"); + cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n"); } ret = cs35l56_common_probe(cs35l56); @@ -42,7 +42,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client) ret = cs35l56_init(cs35l56); if (ret == 0) - ret = cs35l56_irq_request(cs35l56, client->irq); + ret = cs35l56_irq_request(&cs35l56->base, client->irq); if (ret < 0) cs35l56_remove(cs35l56); @@ -62,10 +62,19 @@ static const struct i2c_device_id cs35l56_id_i2c[] = { }; MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct i2c_driver cs35l56_i2c_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_i2c, .probe = cs35l56_i2c_probe, diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 2cde78605ba9..b433266b7844 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -166,13 +166,13 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); int ret; - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); - regcache_cache_only(cs35l56->regmap, false); + regcache_cache_only(cs35l56->base.regmap, false); ret = cs35l56_init(cs35l56); if (ret < 0) { - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); goto out; } @@ -180,15 +180,15 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) * cs35l56_init can return with !init_done if it triggered * a soft reset. */ - if (cs35l56->init_done) { + if (cs35l56->base.init_done) { /* Enable SoundWire interrupts */ sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); } out: - pm_runtime_mark_last_busy(cs35l56->dev); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, @@ -198,7 +198,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, /* SoundWire core holds our pm_runtime when calling this function. */ - dev_dbg(cs35l56->dev, "int control_port=%#x\n", status->control_port); + dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port); if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0) return 0; @@ -207,7 +207,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, * Prevent bus manager suspending and possibly issuing a * bus-reset before the queued work has run. */ - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); /* * Mask and clear until it has been handled. The read of GEN_INT_STAT_1 @@ -230,14 +230,14 @@ static void cs35l56_sdw_irq_work(struct work_struct *work) struct cs35l56_private, sdw_irq_work); - cs35l56_irq(-1, cs35l56); + cs35l56_irq(-1, &cs35l56->base); /* unmask interrupts */ if (!cs35l56->sdw_irq_no_unmask) sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) @@ -246,7 +246,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) struct sdw_slave_prop *prop = &peripheral->prop; struct sdw_dpn_prop *ports; - ports = devm_kcalloc(cs35l56->dev, 2, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -279,17 +279,17 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral, switch (status) { case SDW_SLAVE_ATTACHED: - dev_dbg(cs35l56->dev, "%s: ATTACHED\n", __func__); + dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__); if (cs35l56->sdw_attached) break; - if (!cs35l56->init_done || cs35l56->soft_resetting) + if (!cs35l56->base.init_done || cs35l56->soft_resetting) cs35l56_sdw_init(peripheral); cs35l56->sdw_attached = true; break; case SDW_SLAVE_UNATTACHED: - dev_dbg(cs35l56->dev, "%s: UNATTACHED\n", __func__); + dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__); cs35l56->sdw_attached = false; break; default: @@ -305,7 +305,7 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, unsigned int curr_scale_reg, next_scale_reg; int curr_scale, next_scale, ret; - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; if (peripheral->bus->params.curr_bank) { @@ -324,13 +324,13 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, */ curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg); if (curr_scale < 0) { - dev_err(cs35l56->dev, "Failed to read current clock scale: %d\n", curr_scale); + dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale); return curr_scale; } next_scale = sdw_read_no_pm(peripheral, next_scale_reg); if (next_scale < 0) { - dev_err(cs35l56->dev, "Failed to read next clock scale: %d\n", next_scale); + dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale); return next_scale; } @@ -338,7 +338,8 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, next_scale = cs35l56->old_sdw_clock_scale; ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale); if (ret < 0) { - dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", + ret); return ret; } } @@ -346,11 +347,11 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56, cs35l56->old_sdw_clock_scale = curr_scale; ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE); if (ret < 0) { - dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret); + dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret); return ret; } - dev_dbg(cs35l56->dev, "Next bus scale: %#x\n", next_scale); + dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale); return 0; } @@ -362,9 +363,10 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral, int sclk; sclk = params->curr_dr_freq / 2; - dev_dbg(cs35l56->dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row); + dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n", + __func__, sclk, params->col, params->row); - if (cs35l56->rev < 0xb0) + if (cs35l56->base.rev < 0xb0) return cs35l56_a1_kick_divider(cs35l56, peripheral); return 0; @@ -376,7 +378,7 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral, { struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - dev_dbg(cs35l56->dev, "%s: mode:%d type:%d\n", __func__, mode, type); + dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type); return 0; } @@ -397,10 +399,10 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs if (peripheral->unattach_request) { /* Cannot access registers until bus is re-initialized. */ - dev_dbg(cs35l56->dev, "Wait for initialization_complete\n"); + dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n"); if (!wait_for_completion_timeout(&peripheral->initialization_complete, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "initialization_complete timed out\n"); + dev_err(cs35l56->base.dev, "initialization_complete timed out\n"); return -ETIMEDOUT; } @@ -419,10 +421,10 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; - return cs35l56_runtime_suspend(dev); + return cs35l56_runtime_suspend_common(&cs35l56->base); } static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) @@ -432,14 +434,14 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) dev_dbg(dev, "Runtime resume\n"); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; ret = cs35l56_sdw_handle_unattach(cs35l56); if (ret < 0) return ret; - ret = cs35l56_runtime_resume_common(cs35l56); + ret = cs35l56_runtime_resume_common(&cs35l56->base, true); if (ret) return ret; @@ -454,7 +456,7 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return 0; /* @@ -493,21 +495,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi if (!cs35l56) return -ENOMEM; - cs35l56->dev = dev; + cs35l56->base.dev = dev; cs35l56->sdw_peripheral = peripheral; INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work); dev_set_drvdata(dev, cs35l56); - cs35l56->regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw, + cs35l56->base.regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw, peripheral, &cs35l56_regmap_sdw); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); return dev_err_probe(dev, ret, "Failed to allocate register map\n"); } /* Start in cache-only until device is enumerated */ - regcache_cache_only(cs35l56->regmap, true); + regcache_cache_only(cs35l56->base.regmap, true); ret = cs35l56_common_probe(cs35l56); if (ret != 0) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 60da8c75b7b9..ae373f335ea8 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -11,6 +11,20 @@ #include "cs35l56.h" +static const struct reg_sequence cs35l56_patch[] = { + /* These are not reset by a soft-reset, so patch to defaults. */ + { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, + { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, + { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, +}; + +int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) +{ + return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch, + ARRAY_SIZE(cs35l56_patch)); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); + static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_ASP1_ENABLES1, 0x00000000 }, { CS35L56_ASP1_CONTROL1, 0x00000028 }, @@ -35,9 +49,9 @@ static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_IRQ1_MASK_8, 0xfc000fff }, { CS35L56_IRQ1_MASK_18, 0x1f7df0ff }, { CS35L56_IRQ1_MASK_20, 0x15c00000 }, - /* CS35L56_MAIN_RENDER_USER_MUTE - soft register, no default */ - /* CS35L56_MAIN_RENDER_USER_VOLUME - soft register, no default */ - /* CS35L56_MAIN_POSTURE_NUMBER - soft register, no default */ + { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 }, + { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 }, + { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 }, }; static bool cs35l56_is_dsp_memory(unsigned int reg) @@ -181,33 +195,463 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } -static const u32 cs35l56_firmware_registers[] = { - CS35L56_MAIN_RENDER_USER_MUTE, - CS35L56_MAIN_RENDER_USER_VOLUME, - CS35L56_MAIN_POSTURE_NUMBER, +int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) +{ + unsigned int val; + int ret; + + regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); + ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + val, (val == 0), + CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); + if (ret) { + dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); + +int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) +{ + int ret; + unsigned int reg; + unsigned int val; + + ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN); + if (ret) + return ret; + + if (cs35l56_base->rev < CS35L56_REVID_B0) + reg = CS35L56_DSP1_PM_CUR_STATE_A1; + else + reg = CS35L56_DSP1_PM_CUR_STATE; + + ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, + val, (val == CS35L56_HALO_STATE_SHUTDOWN), + CS35L56_HALO_STATE_POLL_US, + CS35L56_HALO_STATE_TIMEOUT_US); + if (ret < 0) + dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", + val, ret); + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED); + +int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) +{ + unsigned int reg; + unsigned int val; + int ret; + + if (cs35l56_base->rev < CS35L56_REVID_B0) + reg = CS35L56_DSP1_HALO_STATE_A1; + else + reg = CS35L56_DSP1_HALO_STATE; + + ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg, + val, + (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), + CS35L56_HALO_STATE_POLL_US, + CS35L56_HALO_STATE_TIMEOUT_US); + + if ((ret < 0) && (ret != -ETIMEDOUT)) { + dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret); + return ret; + } + + if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) { + dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED); + +void cs35l56_wait_control_port_ready(void) +{ + /* Wait for control port to be ready (datasheet tIRS). */ + usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED); + +void cs35l56_wait_min_reset_pulse(void) +{ + /* Satisfy minimum reset pulse width spec */ + usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED); + +static const struct reg_sequence cs35l56_system_reset_seq[] = { + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), }; -void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap) +void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) +{ + /* + * Must enter cache-only first so there can't be any more register + * accesses other than the controlled system reset sequence below. + */ + regcache_cache_only(cs35l56_base->regmap, true); + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_system_reset_seq, + ARRAY_SIZE(cs35l56_system_reset_seq)); + + /* On SoundWire the registers won't be accessible until it re-enumerates. */ + if (is_soundwire) + return; + + cs35l56_wait_control_port_ready(); + regcache_cache_only(cs35l56_base->regmap, false); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); + +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) +{ + int ret; + + if (!irq) + return 0; + + ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, + "cs35l56", cs35l56_base); + if (!ret) + cs35l56_base->irq = irq; + else + dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED); + +irqreturn_t cs35l56_irq(int irq, void *data) +{ + struct cs35l56_base *cs35l56_base = data; + unsigned int status1 = 0, status8 = 0, status20 = 0; + unsigned int mask1, mask8, mask20; + unsigned int val; + int rv; + + irqreturn_t ret = IRQ_NONE; + + if (!cs35l56_base->init_done) + return IRQ_NONE; + + mutex_lock(&cs35l56_base->irq_lock); + + rv = pm_runtime_resume_and_get(cs35l56_base->dev); + if (rv < 0) { + dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); + goto err_unlock; + } + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); + if ((val & CS35L56_IRQ1_STS_MASK) == 0) { + dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); + goto err; + } + + /* Ack interrupts */ + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1); + status1 &= ~mask1; + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1); + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8); + status8 &= ~mask8; + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8); + + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20); + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20); + status20 &= ~mask20; + /* We don't want EINT20 but they default to unmasked: force mask */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + + dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8); + + /* Check to see if unmasked bits are active */ + if (!status1 && !status8 && !status20) + goto err; + + if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) + dev_crit(cs35l56_base->dev, "Amp short error\n"); + + if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) + dev_crit(cs35l56_base->dev, "Overtemp error\n"); + + ret = IRQ_HANDLED; + +err: + pm_runtime_put(cs35l56_base->dev); +err_unlock: + mutex_unlock(&cs35l56_base->irq_lock); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED); + +int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) +{ + unsigned int val; + int ret; + + /* Nothing to re-patch if we haven't done any patching yet. */ + if (!cs35l56_base->fw_patched) + return false; + + /* + * If we have control of RESET we will have asserted it so the firmware + * will need re-patching. + */ + if (cs35l56_base->reset_gpio) + return true; + + /* + * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so + * can't be used here to test for memory retention. + * Assume that tuning must be re-loaded. + */ + if (cs35l56_base->secured) + return true; + + ret = pm_runtime_resume_and_get(cs35l56_base->dev); + if (ret) { + dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret); + return ret; + } + + ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val); + if (ret) + dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + else + ret = !!(val & CS35L56_FIRMWARE_MISSING); + + pm_runtime_put_autosuspend(cs35l56_base->dev); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED); + +static const struct reg_sequence cs35l56_hibernate_seq[] = { + /* This must be the last register access */ + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW), +}; + +static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { + REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), +}; + +int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base) { - int i; unsigned int val; + int ret; + + if (!cs35l56_base->init_done) + return 0; - for (i = 0; i < ARRAY_SIZE(cs35l56_firmware_registers); i++) { - regmap_read(regmap, cs35l56_firmware_registers[i], &val); - dev_dbg(dev, "%s: %d: %#x: %#x\n", __func__, - i, cs35l56_firmware_registers[i], val); + /* Firmware must have entered a power-save state */ + ret = regmap_read_poll_timeout(cs35l56_base->regmap, + CS35L56_TRANSDUCER_ACTUAL_PS, + val, (val >= CS35L56_PS3), + CS35L56_PS3_POLL_US, + CS35L56_PS3_TIMEOUT_US); + if (ret) + dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n", ret); + + /* Clear BOOT_DONE so it can be used to detect a reboot */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); + + if (!cs35l56_base->can_hibernate) { + regcache_cache_only(cs35l56_base->regmap, true); + dev_dbg(cs35l56_base->dev, "Suspended: no hibernate"); + + return 0; } + + /* + * Enable auto-hibernate. If it is woken by some other wake source + * it will automatically return to hibernate. + */ + cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); + + /* + * Must enter cache-only first so there can't be any more register + * accesses other than the controlled hibernate sequence below. + */ + regcache_cache_only(cs35l56_base->regmap, true); + + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_hibernate_seq, + ARRAY_SIZE(cs35l56_hibernate_seq)); + + dev_dbg(cs35l56_base->dev, "Suspended: hibernate"); + + return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_reread_firmware_registers, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED); + +int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire) +{ + unsigned int val; + int ret; + + if (!cs35l56_base->init_done) + return 0; + + if (!cs35l56_base->can_hibernate) + goto out_sync; + + if (!is_soundwire) { + /* + * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. + * Must be done before releasing cache-only. + */ + regmap_multi_reg_write_bypassed(cs35l56_base->regmap, + cs35l56_hibernate_wake_seq, + ARRAY_SIZE(cs35l56_hibernate_wake_seq)); -const struct cs_dsp_region cs35l56_dsp1_regions[] = { + cs35l56_wait_control_port_ready(); + } + +out_sync: + regcache_cache_only(cs35l56_base->regmap, false); + + ret = cs35l56_wait_for_firmware_boot(cs35l56_base); + if (ret) { + dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret); + goto err; + } + + ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + if (ret) + goto err; + + /* BOOT_DONE will be 1 if the amp reset */ + regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, &val); + if (val & CS35L56_OTP_BOOT_DONE_MASK) { + dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n"); + regcache_mark_dirty(cs35l56_base->regmap); + } + + regcache_sync(cs35l56_base->regmap); + + dev_dbg(cs35l56_base->dev, "Resumed"); + + return 0; + +err: + regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + CS35L56_MBOX_CMD_HIBERNATE_NOW); + + regcache_cache_only(cs35l56_base->regmap, true); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED); + +static const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, { .type = WMFW_HALO_YM_PACKED, .base = CS35L56_DSP1_YMEM_PACKED_0 }, { .type = WMFW_ADSP2_XM, .base = CS35L56_DSP1_XMEM_UNPACKED24_0 }, { .type = WMFW_ADSP2_YM, .base = CS35L56_DSP1_YMEM_UNPACKED24_0 }, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_dsp1_regions, SND_SOC_CS35L56_SHARED); + +void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp) +{ + cs_dsp->num = 1; + cs_dsp->type = WMFW_HALO; + cs_dsp->rev = 0; + cs_dsp->dev = cs35l56_base->dev; + cs_dsp->regmap = cs35l56_base->regmap; + cs_dsp->base = CS35L56_DSP1_CORE_BASE; + cs_dsp->base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; + cs_dsp->mem = cs35l56_dsp1_regions; + cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); + cs_dsp->no_core_startstop = true; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED); + +int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) +{ + int ret; + unsigned int devid, revid, otpid, secured; + + /* + * If the system is not using a reset_gpio then issue a + * dummy read to force a wakeup. + */ + if (!cs35l56_base->reset_gpio) + regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); + + cs35l56_wait_control_port_ready(); + + /* + * The HALO_STATE register is in different locations on Ax and B0 + * devices so the REVID needs to be determined before waiting for the + * firmware to boot. + */ + ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get Revision ID failed\n"); + return ret; + } + cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); + + ret = cs35l56_wait_for_firmware_boot(cs35l56_base); + if (ret) + return ret; + + ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get Device ID failed\n"); + return ret; + } + devid &= CS35L56_DEVID_MASK; + + switch (devid) { + case 0x35A56: + break; + default: + dev_err(cs35l56_base->dev, "Unknown device %x\n", devid); + return ret; + } + + ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured); + if (ret) { + dev_err(cs35l56_base->dev, "Get Secure status failed\n"); + return ret; + } + + /* When any bus is restricted treat the device as secured */ + if (secured & CS35L56_RESTRICTED_MASK) + cs35l56_base->secured = true; + + ret = regmap_read(cs35l56_base->regmap, CS35L56_OTPID, &otpid); + if (ret < 0) { + dev_err(cs35l56_base->dev, "Get OTP ID failed\n"); + return ret; + } + + dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", + cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid); + + /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ + regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); + regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, + CS35L56_AMP_SHORT_ERR_EINT1_MASK, + 0); + regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, + CS35L56_TEMP_ERR_EINT1_MASK, + 0); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED); static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { [0x0C] = 128000, @@ -319,7 +763,7 @@ struct regmap_config cs35l56_regmap_i2c = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); @@ -336,7 +780,7 @@ struct regmap_config cs35l56_regmap_spi = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); @@ -352,7 +796,7 @@ struct regmap_config cs35l56_regmap_sdw = { .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED); diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index 996aab10500e..9962703915e1 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -25,13 +25,13 @@ static int cs35l56_spi_probe(struct spi_device *spi) return -ENOMEM; spi_set_drvdata(spi, cs35l56); - cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config); - if (IS_ERR(cs35l56->regmap)) { - ret = PTR_ERR(cs35l56->regmap); + cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config); + if (IS_ERR(cs35l56->base.regmap)) { + ret = PTR_ERR(cs35l56->base.regmap); return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n"); } - cs35l56->dev = &spi->dev; + cs35l56->base.dev = &spi->dev; ret = cs35l56_common_probe(cs35l56); if (ret != 0) @@ -39,7 +39,7 @@ static int cs35l56_spi_probe(struct spi_device *spi) ret = cs35l56_init(cs35l56); if (ret == 0) - ret = cs35l56_irq_request(cs35l56, spi->irq); + ret = cs35l56_irq_request(&cs35l56->base, spi->irq); if (ret < 0) cs35l56_remove(cs35l56); @@ -59,10 +59,19 @@ static const struct spi_device_id cs35l56_id_spi[] = { }; MODULE_DEVICE_TABLE(spi, cs35l56_id_spi); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs35l56_asoc_acpi_match[] = { + { "CSC355C", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match); +#endif + static struct spi_driver cs35l56_spi_driver = { .driver = { .name = "cs35l56", .pm = &cs35l56_pm_ops_i2c_spi, + .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match), }, .id_table = cs35l56_id_spi, .probe = cs35l56_spi_probe, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index c03f9d3c9a13..600b79c62ec4 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -5,7 +5,6 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. -#include <linux/acpi.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/delay.h> @@ -34,23 +33,6 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command) -{ - unsigned int val; - int ret; - - regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command); - ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, - val, (val == 0), - CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US); - if (ret) { - dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret); - return ret; - } - - return 0; -} - static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56) { /* Wait for patching to complete */ @@ -174,25 +156,25 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w, unsigned int val; int ret; - dev_dbg(cs35l56->dev, "play: %d\n", event); + dev_dbg(cs35l56->base.dev, "play: %d\n", event); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Don't wait for ACK, we check in POST_PMU that it completed */ - return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, + return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_AUDIO_PLAY); case SND_SOC_DAPM_POST_PMU: /* Wait for firmware to enter PS0 power state */ - ret = regmap_read_poll_timeout(cs35l56->regmap, + ret = regmap_read_poll_timeout(cs35l56->base.regmap, CS35L56_TRANSDUCER_ACTUAL_PS, val, (val == CS35L56_PS0), CS35L56_PS0_POLL_US, CS35L56_PS0_TIMEOUT_US); if (ret) - dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret); + dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret); return ret; case SND_SOC_DAPM_POST_PMD: - return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE); + return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE); default: return 0; } @@ -310,109 +292,23 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component); - dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event); + dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event); return wm_adsp_event(w, kcontrol, event); } -irqreturn_t cs35l56_irq(int irq, void *data) -{ - struct cs35l56_private *cs35l56 = data; - unsigned int status1 = 0, status8 = 0, status20 = 0; - unsigned int mask1, mask8, mask20; - unsigned int val; - int rv; - - irqreturn_t ret = IRQ_NONE; - - if (!cs35l56->init_done) - return IRQ_NONE; - - mutex_lock(&cs35l56->irq_lock); - - rv = pm_runtime_resume_and_get(cs35l56->dev); - if (rv < 0) { - dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv); - goto err_unlock; - } - - regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val); - if ((val & CS35L56_IRQ1_STS_MASK) == 0) { - dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n"); - goto err; - } - - /* Ack interrupts */ - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1); - status1 &= ~mask1; - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1); - - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8); - status8 &= ~mask8; - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8); - - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20); - regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20); - status20 &= ~mask20; - /* We don't want EINT20 but they default to unmasked: force mask */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - - dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8); - - /* Check to see if unmasked bits are active */ - if (!status1 && !status8 && !status20) - goto err; - - if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) - dev_crit(cs35l56->dev, "Amp short error\n"); - - if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) - dev_crit(cs35l56->dev, "Overtemp error\n"); - - ret = IRQ_HANDLED; - -err: - pm_runtime_put(cs35l56->dev); -err_unlock: - mutex_unlock(&cs35l56->irq_lock); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE); - -int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq) -{ - int ret; - - if (!irq) - return 0; - - ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq, - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, - "cs35l56", cs35l56); - if (!ret) - cs35l56->irq = irq; - else - dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE); - static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component); unsigned int val; - dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt); + dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt); switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBC_CFC: break; default: - dev_err(cs35l56->dev, "Unsupported clock source mode\n"); + dev_err(cs35l56->base.dev, "Unsupported clock source mode\n"); return -EINVAL; } @@ -426,7 +322,7 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f cs35l56->tdm_mode = false; break; default: - dev_err(cs35l56->dev, "Unsupported DAI format\n"); + dev_err(cs35l56->base.dev, "Unsupported DAI format\n"); return -EINVAL; } @@ -443,40 +339,29 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f case SND_SOC_DAIFMT_NB_NF: break; default: - dev_err(cs35l56->dev, "Invalid clock invert\n"); + dev_err(cs35l56->base.dev, "Invalid clock invert\n"); return -EINVAL; } - regmap_update_bits(cs35l56->regmap, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_FMT_MASK | CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK, val); /* Hi-Z DOUT in unused slots and when all TX are disabled */ - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3, CS35L56_ASP1_DOUT_HIZ_CTRL_MASK, CS35L56_ASP_UNUSED_HIZ_OFF_HIZ); return 0; } -static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, - unsigned int reg, unsigned long mask) +static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask) { - unsigned int reg_val, channel_shift; + unsigned int channel_shift; int bit_num; - /* Init all slots to 63 */ - switch (reg) { - case CS35L56_ASP1_FRAME_CONTROL1: - reg_val = 0x3f3f3f3f; - break; - case CS35L56_ASP1_FRAME_CONTROL5: - reg_val = 0x3f3f3f; - break; - } - /* Enable consecutive TX1..TXn for each of the slots set in mask */ channel_shift = 0; for_each_set_bit(bit_num, &mask, 32) { @@ -485,7 +370,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56, channel_shift += 8; } - regmap_write(cs35l56->regmap, reg, reg_val); + return reg_val; } static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, @@ -494,20 +379,20 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); if ((slots == 0) || (slot_width == 0)) { - dev_dbg(cs35l56->dev, "tdm config cleared\n"); + dev_dbg(cs35l56->base.dev, "tdm config cleared\n"); cs35l56->asp_slot_width = 0; cs35l56->asp_slot_count = 0; return 0; } if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) { - dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width); + dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width); return -EINVAL; } /* More than 32 slots would give an unsupportable BCLK frequency */ if (slots > 32) { - dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots); + dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots); return -EINVAL; } @@ -521,10 +406,13 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx if (rx_mask == 0) rx_mask = 0xf; // ASPTX1..TX4 in slots 0..3 - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask); - cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask); + /* Default unused slots to 63 */ + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1, + cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask)); + regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5, + cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask)); - dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n", + dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n", cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask); return 0; @@ -544,7 +432,8 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, else asp_width = asp_wl; - dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate); + dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d", + __func__, asp_wl, asp_width, rate); if (!cs35l56->sysclk_set) { unsigned int slots = cs35l56->asp_slot_count; @@ -562,26 +451,26 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, bclk_freq = asp_width * slots * rate; freq_id = cs35l56_get_bclk_freq_id(bclk_freq); if (freq_id < 0) { - dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq); + dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq); return -EINVAL; } - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1, CS35L56_ASP_BCLK_FREQ_MASK, freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT); } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_RX_WIDTH_MASK, asp_width << CS35L56_ASP_RX_WIDTH_SHIFT); - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5, CS35L56_ASP_RX_WL_MASK, asp_wl); } else { - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2, CS35L56_ASP_TX_WIDTH_MASK, asp_width << CS35L56_ASP_TX_WIDTH_SHIFT); - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1, CS35L56_ASP_TX_WL_MASK, asp_wl); } @@ -603,7 +492,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai, if (freq_id < 0) return freq_id; - regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1, + regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1, CS35L56_ASP_BCLK_FREQ_MASK, freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT); cs35l56->sysclk_set = true; @@ -646,9 +535,9 @@ static int cs35l56_sdw_dai_hw_params(struct snd_pcm_substream *substream, struct sdw_port_config pconfig; int ret; - dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params)); + dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params)); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return -ENODEV; if (!sdw_stream) @@ -761,85 +650,31 @@ static struct snd_soc_dai_driver cs35l56_dai[] = { } }; -static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56) -{ - unsigned int reg; - unsigned int val; - int ret; - - if (cs35l56->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_HALO_STATE_A1; - else - reg = CS35L56_DSP1_HALO_STATE; - - ret = regmap_read_poll_timeout(cs35l56->regmap, reg, - val, - (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE), - CS35L56_HALO_STATE_POLL_US, - CS35L56_HALO_STATE_TIMEOUT_US); - - if ((ret < 0) && (ret != -ETIMEDOUT)) { - dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret); - return ret; - } - - if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) { - dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val); - return -EIO; - } - - return 0; -} - -static inline void cs35l56_wait_min_reset_pulse(void) -{ - /* Satisfy minimum reset pulse width spec */ - usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US); -} - -static const struct reg_sequence cs35l56_system_reset_seq[] = { - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET), -}; - -static void cs35l56_system_reset(struct cs35l56_private *cs35l56) -{ - cs35l56->soft_resetting = true; - - /* - * Must enter cache-only first so there can't be any more register - * accesses other than the controlled system reset sequence below. - */ - regcache_cache_only(cs35l56->regmap, true); - regmap_multi_reg_write_bypassed(cs35l56->regmap, - cs35l56_system_reset_seq, - ARRAY_SIZE(cs35l56_system_reset_seq)); - - /* On SoundWire the registers won't be accessible until it re-enumerates. */ - if (cs35l56->sdw_peripheral) - return; - - usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400); - regcache_cache_only(cs35l56->regmap, false); -} - static void cs35l56_secure_patch(struct cs35l56_private *cs35l56) { int ret; /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + ret = wm_adsp_power_up(&cs35l56->dsp, true); if (ret) - dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); + dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); else - cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT); + cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT); } static void cs35l56_patch(struct cs35l56_private *cs35l56) { - unsigned int reg; - unsigned int val; + unsigned int firmware_missing; int ret; + ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing); + if (ret) { + dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret); + return; + } + + firmware_missing &= CS35L56_FIRMWARE_MISSING; + /* * Disable SoundWire interrupts to prevent race with IRQ work. * Setting sdw_irq_no_unmask prevents the handler re-enabling @@ -854,35 +689,27 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) flush_work(&cs35l56->sdw_irq_work); } - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN); + ret = cs35l56_firmware_shutdown(&cs35l56->base); if (ret) goto err; - if (cs35l56->rev < CS35L56_REVID_B0) - reg = CS35L56_DSP1_PM_CUR_STATE_A1; - else - reg = CS35L56_DSP1_PM_CUR_STATE; - - ret = regmap_read_poll_timeout(cs35l56->regmap, reg, - val, (val == CS35L56_HALO_STATE_SHUTDOWN), - CS35L56_HALO_STATE_POLL_US, - CS35L56_HALO_STATE_TIMEOUT_US); - if (ret < 0) - dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n", - val, ret); - - /* Use wm_adsp to load and apply the firmware patch and coefficient files */ - ret = wm_adsp_power_up(&cs35l56->dsp); + /* + * Use wm_adsp to load and apply the firmware patch and coefficient files, + * but only if firmware is missing. If firmware is already patched just + * power-up wm_adsp without downloading firmware. + */ + ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing); if (ret) { - dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); + dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret); goto err; } - mutex_lock(&cs35l56->irq_lock); + mutex_lock(&cs35l56->base.irq_lock); init_completion(&cs35l56->init_completion); - cs35l56_system_reset(cs35l56); + cs35l56->soft_resetting = true; + cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* @@ -892,18 +719,20 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56) */ if (!wait_for_completion_timeout(&cs35l56->init_completion, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__); + dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n", + __func__); goto err_unlock; } } else if (cs35l56_init(cs35l56)) { goto err_unlock; } - regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING); - cs35l56->fw_patched = true; + regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, + CS35L56_FIRMWARE_MISSING); + cs35l56->base.fw_patched = true; err_unlock: - mutex_unlock(&cs35l56->irq_lock); + mutex_unlock(&cs35l56->base.irq_lock); err: /* Re-enable SoundWire interrupts */ if (cs35l56->sdw_peripheral) { @@ -919,10 +748,10 @@ static void cs35l56_dsp_work(struct work_struct *work) struct cs35l56_private, dsp_work); - if (!cs35l56->init_done) + if (!cs35l56->base.init_done) return; - pm_runtime_get_sync(cs35l56->dev); + pm_runtime_get_sync(cs35l56->base.dev); /* * When the device is running in secure mode the firmware files can @@ -930,13 +759,13 @@ static void cs35l56_dsp_work(struct work_struct *work) * shutdown the firmware to apply them and can use the lower cost * reinit sequence instead. */ - if (cs35l56->secured) + if (cs35l56->base.secured) cs35l56_secure_patch(cs35l56); else cs35l56_patch(cs35l56); - pm_runtime_mark_last_busy(cs35l56->dev); - pm_runtime_put_autosuspend(cs35l56->dev); + pm_runtime_mark_last_busy(cs35l56->base.dev); + pm_runtime_put_autosuspend(cs35l56->base.dev); } static int cs35l56_component_probe(struct snd_soc_component *component) @@ -948,16 +777,16 @@ static int cs35l56_component_probe(struct snd_soc_component *component) if (!wait_for_completion_timeout(&cs35l56->init_completion, msecs_to_jiffies(5000))) { - dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__); + dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__); return -ENODEV; } cs35l56->component = component; wm_adsp2_component_probe(&cs35l56->dsp, component); - debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done); - debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate); - debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched); + debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done); + debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate); + debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched); queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); @@ -1009,171 +838,18 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l56 = { .suspend_bias_off = 1, /* see cs35l56_system_resume() */ }; -static const struct reg_sequence cs35l56_hibernate_seq[] = { - /* This must be the last register access */ - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW), -}; - -static const struct reg_sequence cs35l56_hibernate_wake_seq[] = { - REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP), -}; - -int cs35l56_runtime_suspend(struct device *dev) +static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - unsigned int val; - int ret; - - if (!cs35l56->init_done) - return 0; - - /* Firmware must have entered a power-save state */ - ret = regmap_read_poll_timeout(cs35l56->regmap, - CS35L56_TRANSDUCER_ACTUAL_PS, - val, (val >= CS35L56_PS3), - CS35L56_PS3_POLL_US, - CS35L56_PS3_TIMEOUT_US); - if (ret) - dev_warn(cs35l56->dev, "PS3 wait failed: %d\n", ret); - - /* Clear BOOT_DONE so it can be used to detect a reboot */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK); - - if (!cs35l56->can_hibernate) { - regcache_cache_only(cs35l56->regmap, true); - dev_dbg(dev, "Suspended: no hibernate"); - return 0; - } - - /* - * Enable auto-hibernate. If it is woken by some other wake source - * it will automatically return to hibernate. - */ - cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE); - - /* - * Must enter cache-only first so there can't be any more register - * accesses other than the controlled hibernate sequence below. - */ - regcache_cache_only(cs35l56->regmap, true); - - regmap_multi_reg_write_bypassed(cs35l56->regmap, - cs35l56_hibernate_seq, - ARRAY_SIZE(cs35l56_hibernate_seq)); - - dev_dbg(dev, "Suspended: hibernate"); - - return 0; + return cs35l56_runtime_suspend_common(&cs35l56->base); } -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE); static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev) { struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - if (!cs35l56->init_done) - return 0; - - return cs35l56_runtime_resume_common(cs35l56); -} - -int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56) -{ - unsigned int val; - int ret; - - if (!cs35l56->can_hibernate) - goto out_sync; - - if (!cs35l56->sdw_peripheral) { - /* - * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C. - * Must be done before releasing cache-only. - */ - regmap_multi_reg_write_bypassed(cs35l56->regmap, - cs35l56_hibernate_wake_seq, - ARRAY_SIZE(cs35l56_hibernate_wake_seq)); - - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); - } - -out_sync: - regcache_cache_only(cs35l56->regmap, false); - - ret = cs35l56_wait_for_firmware_boot(cs35l56); - if (ret) { - dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret); - goto err; - } - - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); - if (ret) - goto err; - - /* BOOT_DONE will be 1 if the amp reset */ - regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_4, &val); - if (val & CS35L56_OTP_BOOT_DONE_MASK) { - dev_dbg(cs35l56->dev, "Registers reset in suspend\n"); - regcache_mark_dirty(cs35l56->regmap); - } - - regcache_sync(cs35l56->regmap); - - dev_dbg(cs35l56->dev, "Resumed"); - - return 0; - -err: - regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, - CS35L56_MBOX_CMD_HIBERNATE_NOW); - - regcache_cache_only(cs35l56->regmap, true); - - return ret; -} -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE); - -static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56) -{ - unsigned int val; - int ret; - - /* Nothing to re-patch if we haven't done any patching yet. */ - if (!cs35l56->fw_patched) - return false; - - /* - * If we have control of RESET we will have asserted it so the firmware - * will need re-patching. - */ - if (cs35l56->reset_gpio) - return true; - - /* - * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so - * can't be used here to test for memory retention. - * Assume that tuning must be re-loaded. - */ - if (cs35l56->secured) - return true; - - ret = pm_runtime_resume_and_get(cs35l56->dev); - if (ret) { - dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret); - return ret; - } - - ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val); - if (ret) - dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret); - else - ret = !!(val & CS35L56_FIRMWARE_MISSING); - - pm_runtime_put_autosuspend(cs35l56->dev); - - return ret; + return cs35l56_runtime_resume_common(&cs35l56->base, false); } int cs35l56_system_suspend(struct device *dev) @@ -1191,8 +867,8 @@ int cs35l56_system_suspend(struct device *dev) * clear it. Prevent this race by temporarily disabling the parent irq * until we reach _no_irq. */ - if (cs35l56->irq) - disable_irq(cs35l56->irq); + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); return pm_runtime_force_suspend(dev); } @@ -1209,8 +885,8 @@ int cs35l56_system_suspend_late(struct device *dev) * RESET is usually shared by all amps so it must not be asserted until * all driver instances have done their suspend() stage. */ - if (cs35l56->reset_gpio) { - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); } @@ -1227,8 +903,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev) dev_dbg(dev, "system_suspend_no_irq\n"); /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */ - if (cs35l56->irq) - enable_irq(cs35l56->irq); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); return 0; } @@ -1247,8 +923,8 @@ int cs35l56_system_resume_no_irq(struct device *dev) * clear it, until it has fully resumed. Prevent this race by temporarily * disabling the parent irq until we complete resume(). */ - if (cs35l56->irq) - disable_irq(cs35l56->irq); + if (cs35l56->base.irq) + disable_irq(cs35l56->base.irq); return 0; } @@ -1262,8 +938,8 @@ int cs35l56_system_resume_early(struct device *dev) dev_dbg(dev, "system_resume_early\n"); /* Ensure a spec-compliant RESET pulse. */ - if (cs35l56->reset_gpio) { - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + if (cs35l56->base.reset_gpio) { + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); } @@ -1275,7 +951,7 @@ int cs35l56_system_resume_early(struct device *dev) } /* Release shared RESET before drivers start resume(). */ - gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); return 0; } @@ -1288,10 +964,16 @@ int cs35l56_system_resume(struct device *dev) dev_dbg(dev, "system_resume\n"); + /* + * We might have done a hard reset or the CS35L56 was power-cycled + * so wait for control port to be ready. + */ + cs35l56_wait_control_port_ready(); + /* Undo pm_runtime_force_suspend() before re-enabling the irq */ ret = pm_runtime_force_resume(dev); - if (cs35l56->irq) - enable_irq(cs35l56->irq); + if (cs35l56->base.irq) + enable_irq(cs35l56->base.irq); if (ret) return ret; @@ -1300,12 +982,13 @@ int cs35l56_system_resume(struct device *dev) if (!cs35l56->component) return 0; - ret = cs35l56_is_fw_reload_needed(cs35l56); - dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret); + ret = cs35l56_is_fw_reload_needed(&cs35l56->base); + dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); if (ret < 1) return ret; - cs35l56->fw_patched = false; + cs35l56->base.fw_patched = false; + wm_adsp_power_down(&cs35l56->dsp); queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work); /* @@ -1329,51 +1012,38 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work); dsp = &cs35l56->dsp; + cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp); dsp->part = "cs35l56"; - dsp->cs_dsp.num = 1; - dsp->cs_dsp.type = WMFW_HALO; - dsp->cs_dsp.rev = 0; dsp->fw = 12; - dsp->cs_dsp.dev = cs35l56->dev; - dsp->cs_dsp.regmap = cs35l56->regmap; - dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE; - dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID; - dsp->cs_dsp.mem = cs35l56_dsp1_regions; - dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); - dsp->cs_dsp.no_core_startstop = true; dsp->wmfw_optional = true; - dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name); + dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name); ret = wm_halo_init(dsp); if (ret != 0) { - dev_err(cs35l56->dev, "wm_halo_init failed\n"); + dev_err(cs35l56->base.dev, "wm_halo_init failed\n"); return ret; } return 0; } -static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56) +static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) { - acpi_handle handle = ACPI_HANDLE(cs35l56->dev); - const char *sub; + struct device *dev = cs35l56->base.dev; + const char *prop; + int ret; - /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */ - if (!handle) + ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop); + /* If bad sw node property, return 0 and fallback to legacy firmware path */ + if (ret < 0) return 0; - sub = acpi_get_subsystem_id(handle); - if (IS_ERR(sub)) { - /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */ - if (PTR_ERR(sub) == -ENODATA) - return 0; - else - return PTR_ERR(sub); - } + cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL); + if (cs35l56->dsp.system_name == NULL) + return -ENOMEM; - cs35l56->dsp.system_name = sub; - dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name); + dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name); return 0; } @@ -1383,62 +1053,65 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) int ret; init_completion(&cs35l56->init_completion); - mutex_init(&cs35l56->irq_lock); + mutex_init(&cs35l56->base.irq_lock); - dev_set_drvdata(cs35l56->dev, cs35l56); + dev_set_drvdata(cs35l56->base.dev, cs35l56); cs35l56_fill_supply_names(cs35l56->supplies); - ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies), + ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); if (ret != 0) - return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n"); /* Reset could be controlled by the BIOS or shared by multiple amps */ - cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs35l56->reset_gpio)) { - ret = PTR_ERR(cs35l56->reset_gpio); + cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(cs35l56->base.reset_gpio)) { + ret = PTR_ERR(cs35l56->base.reset_gpio); /* * If RESET is shared the first amp to probe will grab the reset * line and reset all the amps */ if (ret != -EBUSY) - return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n"); - dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n"); - cs35l56->reset_gpio = NULL; + dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n"); + cs35l56->base.reset_gpio = NULL; } ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); if (ret != 0) - return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n"); + return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n"); - if (cs35l56->reset_gpio) { + if (cs35l56->base.reset_gpio) { + /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */ + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); cs35l56_wait_min_reset_pulse(); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1); } - ret = cs35l56_acpi_get_name(cs35l56); + ret = cs35l56_get_firmware_uid(cs35l56); if (ret != 0) goto err; ret = cs35l56_dsp_init(cs35l56); if (ret < 0) { - dev_err_probe(cs35l56->dev, ret, "DSP init failed\n"); + dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n"); goto err; } - ret = devm_snd_soc_register_component(cs35l56->dev, + ret = devm_snd_soc_register_component(cs35l56->base.dev, &soc_component_dev_cs35l56, cs35l56_dai, ARRAY_SIZE(cs35l56_dai)); if (ret < 0) { - dev_err_probe(cs35l56->dev, ret, "Register codec failed\n"); + dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n"); goto err; } return 0; err: - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); return ret; @@ -1448,7 +1121,6 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE); int cs35l56_init(struct cs35l56_private *cs35l56) { int ret; - unsigned int devid, revid, otpid, secured; /* * Check whether the actions associated with soft reset or one time @@ -1457,96 +1129,31 @@ int cs35l56_init(struct cs35l56_private *cs35l56) if (cs35l56->soft_resetting) goto post_soft_reset; - if (cs35l56->init_done) + if (cs35l56->base.init_done) return 0; - pm_runtime_set_autosuspend_delay(cs35l56->dev, 100); - pm_runtime_use_autosuspend(cs35l56->dev); - pm_runtime_set_active(cs35l56->dev); - pm_runtime_enable(cs35l56->dev); - - /* - * If the system is not using a reset_gpio then issue a - * dummy read to force a wakeup. - */ - if (!cs35l56->reset_gpio) - regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid); - - /* Wait for control port to be ready (datasheet tIRS). */ - usleep_range(CS35L56_CONTROL_PORT_READY_US, - CS35L56_CONTROL_PORT_READY_US + 400); - - /* - * The HALO_STATE register is in different locations on Ax and B0 - * devices so the REVID needs to be determined before waiting for the - * firmware to boot. - */ - ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid); - if (ret < 0) { - dev_err(cs35l56->dev, "Get Revision ID failed\n"); - return ret; - } - cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK); - - ret = cs35l56_wait_for_firmware_boot(cs35l56); - if (ret) - return ret; - - ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid); - if (ret < 0) { - dev_err(cs35l56->dev, "Get Device ID failed\n"); - return ret; - } - devid &= CS35L56_DEVID_MASK; + pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100); + pm_runtime_use_autosuspend(cs35l56->base.dev); + pm_runtime_set_active(cs35l56->base.dev); + pm_runtime_enable(cs35l56->base.dev); - switch (devid) { - case 0x35A56: - break; - default: - dev_err(cs35l56->dev, "Unknown device %x\n", devid); - return ret; - } - - ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured); - if (ret) { - dev_err(cs35l56->dev, "Get Secure status failed\n"); - return ret; - } - - /* When any bus is restricted treat the device as secured */ - if (secured & CS35L56_RESTRICTED_MASK) - cs35l56->secured = true; - - ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid); - if (ret < 0) { - dev_err(cs35l56->dev, "Get OTP ID failed\n"); + ret = cs35l56_hw_init(&cs35l56->base); + if (ret < 0) return ret; - } - - dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n", - cs35l56->secured ? "s" : "", cs35l56->rev, otpid); /* Populate the DSP information with the revision and security state */ - cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x", - cs35l56->secured ? "s" : "", cs35l56->rev); + cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x", + cs35l56->base.secured ? "s" : "", cs35l56->base.rev); if (!cs35l56->dsp.part) return -ENOMEM; - /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ - regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff); - regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1, - CS35L56_AMP_SHORT_ERR_EINT1_MASK, - 0); - regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8, - CS35L56_TEMP_ERR_EINT1_MASK, - 0); - - if (!cs35l56->reset_gpio) { - dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n"); - cs35l56_system_reset(cs35l56); + if (!cs35l56->base.reset_gpio) { + dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n"); + cs35l56->soft_resetting = true; + cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral); if (cs35l56->sdw_peripheral) { /* Keep alive while we wait for re-enumeration */ - pm_runtime_get_noresume(cs35l56->dev); + pm_runtime_get_noresume(cs35l56->base.dev); return 0; } } @@ -1556,29 +1163,30 @@ post_soft_reset: cs35l56->soft_resetting = false; /* Done re-enumerating after one-time init so release the keep-alive */ - if (cs35l56->sdw_peripheral && !cs35l56->init_done) - pm_runtime_put_noidle(cs35l56->dev); + if (cs35l56->sdw_peripheral && !cs35l56->base.init_done) + pm_runtime_put_noidle(cs35l56->base.dev); - regcache_mark_dirty(cs35l56->regmap); - ret = cs35l56_wait_for_firmware_boot(cs35l56); + regcache_mark_dirty(cs35l56->base.regmap); + ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) return ret; - dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n"); + dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n"); } /* Disable auto-hibernate so that runtime_pm has control */ - ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); + ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE); if (ret) return ret; - /* Populate soft registers in the regmap cache */ - cs35l56_reread_firmware_registers(cs35l56->dev, cs35l56->regmap); + ret = cs35l56_set_patch(&cs35l56->base); + if (ret) + return ret; /* Registers could be dirty after soft reset or SoundWire enumeration */ - regcache_sync(cs35l56->regmap); + regcache_sync(cs35l56->base.regmap); - cs35l56->init_done = true; + cs35l56->base.init_done = true; complete(&cs35l56->init_completion); return 0; @@ -1587,32 +1195,30 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE); void cs35l56_remove(struct cs35l56_private *cs35l56) { - cs35l56->init_done = false; + cs35l56->base.init_done = false; /* * WAKE IRQs unmask if CS35L56 hibernates so free the handler to * prevent it racing with remove(). */ - if (cs35l56->irq) - devm_free_irq(cs35l56->dev, cs35l56->irq, cs35l56); + if (cs35l56->base.irq) + devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base); flush_workqueue(cs35l56->dsp_wq); destroy_workqueue(cs35l56->dsp_wq); - pm_runtime_suspend(cs35l56->dev); - pm_runtime_disable(cs35l56->dev); - - regcache_cache_only(cs35l56->regmap, true); + pm_runtime_suspend(cs35l56->base.dev); + pm_runtime_disable(cs35l56->base.dev); - kfree(cs35l56->dsp.system_name); + regcache_cache_only(cs35l56->base.regmap, true); - gpiod_set_value_cansleep(cs35l56->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); } EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE); const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = { - SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL) + SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL) SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume) LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early) NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq) diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 1f7894662fcb..8159c3e217d9 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -32,26 +32,17 @@ struct sdw_slave; struct cs35l56_private { struct wm_adsp dsp; /* must be first member */ + struct cs35l56_base base; struct work_struct dsp_work; struct workqueue_struct *dsp_wq; - struct mutex irq_lock; struct snd_soc_component *component; - struct device *dev; - struct regmap *regmap; struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES]; - int irq; struct sdw_slave *sdw_peripheral; - u8 rev; struct work_struct sdw_irq_work; - bool secured; bool sdw_irq_no_unmask; bool soft_resetting; - bool init_done; bool sdw_attached; - bool fw_patched; - bool can_hibernate; struct completion init_completion; - struct gpio_desc *reset_gpio; u32 rx_mask; u32 tx_mask; @@ -64,8 +55,6 @@ struct cs35l56_private { extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; -int cs35l56_runtime_suspend(struct device *dev); -int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56); int cs35l56_system_suspend(struct device *dev); int cs35l56_system_suspend_late(struct device *dev); int cs35l56_system_suspend_no_irq(struct device *dev); @@ -73,7 +62,7 @@ int cs35l56_system_resume_no_irq(struct device *dev); int cs35l56_system_resume_early(struct device *dev); int cs35l56_system_resume(struct device *dev); irqreturn_t cs35l56_irq(int irq, void *data); -int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq); +int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); int cs35l56_common_probe(struct cs35l56_private *cs35l56); int cs35l56_init(struct cs35l56_private *cs35l56); void cs35l56_remove(struct cs35l56_private *cs35l56); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 0cfc5ab36a13..1ed1e60d8e53 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -564,7 +564,7 @@ static const struct regmap_config cs4265_regmap = { .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults), .readable_reg = cs4265_readable_register, .volatile_reg = cs4265_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs4265_i2c_probe(struct i2c_client *i2c_client) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ab32f15e3b44..3df567214952 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -636,7 +636,7 @@ static const struct regmap_config cs4270_regmap = { .max_register = CS4270_LASTREG, .reg_defaults = cs4270_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .write_flag_mask = CS4270_I2C_INCR, .readable_reg = cs4270_reg_is_readable, diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index e7db7bcd0296..5ed2ef83dcdb 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -19,7 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); -const struct of_device_id cs42l51_of_match[] = { +static const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", }, { } }; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index a7079ae0ca09..e4827b8c2bde 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -703,7 +703,7 @@ const struct regmap_config cs42l51_regmap = { .volatile_reg = cs42l51_volatile_reg, .writeable_reg = cs42l51_writeable_reg, .max_register = CS42L51_CHARGE_FREQ, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs42l51_regmap); diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 1f1ded0ff0ac..4fc8a6ae8d92 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1084,7 +1084,7 @@ static const struct regmap_config cs42l52_regmap = { .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults), .readable_reg = cs42l52_readable_register, .volatile_reg = cs42l52_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs42l52_i2c_probe(struct i2c_client *i2c_client) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 4c646e8d72aa..1714857594fb 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1125,7 +1125,7 @@ static const struct regmap_config cs42l56_regmap = { .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults), .readable_reg = cs42l56_readable_register, .volatile_reg = cs42l56_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs42l56_handle_of_data(struct i2c_client *i2c_client, diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 4558ec38a7ac..9c44b6283b8f 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -458,7 +458,7 @@ const struct regmap_config cs42xx8_regmap_config = { .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg), .volatile_reg = cs42xx8_volatile_register, .writeable_reg = cs42xx8_writeable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_GPL(cs42xx8_regmap_config); diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 8365dd0ebe2a..ef08e51901b5 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -271,7 +271,7 @@ static const struct regmap_config cs4349_regmap = { .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, .writeable_reg = cs4349_writeable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int cs4349_i2c_probe(struct i2c_client *client) diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index a6538dab6639..1245e1a4f2a5 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l15_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l15_dai[] = { { .name = "cs47l15-aif1", @@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l15_dai_ops, }, { .name = "cs47l15-dsp-trace", diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index a07b621d463e..cfa1d34f6ebd 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id, #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops cs47l24_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l24_dai[] = { { .name = "cs47l24-aif1", @@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-voicectrl", @@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .rates = CS47L24_RATES, .formats = CS47L24_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l24_dai_ops, }, { .name = "cs47l24-dsp-trace", diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index c05c80c16c84..a953f2ede1ee 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l35_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l35_dai[] = { { .name = "cs47l35-aif1", @@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-voicectrl", @@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l35_dai_ops, }, { .name = "cs47l35-dsp-trace", diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index dd7997a53e70..827685481859 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l85_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l85_dai[] = { { .name = "cs47l85-aif1", @@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-voicectrl", @@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l85_dai_ops, }, { .name = "cs47l85-dsp-trace", diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index cdd5e7e20b5d..2c9a5372cf51 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l90_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l90_dai[] = { { .name = "cs47l90-aif1", @@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-voicectrl", @@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = &snd_soc_new_compress, + .ops = &cs47l90_dai_ops, }, { .name = "cs47l90-dsp-trace", diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index bc4d311d4778..352deeaff1ca 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, } } +static const struct snd_soc_dai_ops cs47l92_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver cs47l92_dai[] = { { .name = "cs47l92-aif1", @@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = { .rates = MADERA_RATES, .formats = MADERA_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &cs47l92_dai_ops, }, { .name = "cs47l92-dsp-trace", diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 082231088a26..f8b128084015 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops cx2072x_dai_ops2 = { + .probe = cx2072x_dsp_dai_probe, + .set_sysclk = cx2072x_set_dai_sysclk, + .set_fmt = cx2072x_set_dai_fmt, + .hw_params = cx2072x_hw_params, + .set_bclk_ratio = cx2072x_set_dai_bclk_ratio, +}; + #define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { @@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { { /* plabayck only, return echo reference to Conexant DSP chip */ .name = "cx2072x-dsp", .id = CX2072X_DAI_DSP, - .probe = cx2072x_dsp_dai_probe, .playback = { .stream_name = "DSP Playback", .channels_min = 2, @@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .rates = CX2072X_RATES_DSP, .formats = CX2072X_FORMATS, }, - .ops = &cx2072x_dai_ops, + .ops = &cx2072x_dai_ops2, }, { /* plabayck only, return echo reference through I2S TX */ .name = "cx2072x-aec", diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 65e497b455d3..a8f347f1affb 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -27,9 +27,9 @@ * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK). */ -#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6 +#define NR_SUPPORTED_MCLK_LRCK_RATIOS ARRAY_SIZE(supported_mclk_lrck_ratios) static const unsigned int supported_mclk_lrck_ratios[] = { - 256, 384, 400, 512, 768, 1024 + 256, 384, 400, 500, 512, 768, 1024 }; struct es8316_priv { @@ -494,6 +494,7 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, bclk_divider /= 20; break; case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: wordlen = ES8316_SERDATA2_LEN_24; bclk_divider /= 24; break; diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 7cb5b57ae655..6c263086c44d 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -38,6 +38,11 @@ struct es8326_priv { u8 interrupt_clk; bool jd_inverted; unsigned int sysclk; + + bool calibrated; + int version; + int hp; + int jack_remove_retry; }; static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -121,33 +126,12 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { /* Analog Power Supply*/ SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1), SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1), - SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0), SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), - /* Headphone Charge Pump and Output */ - SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER, - 3, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER, - 2, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER, - 1, 1, NULL, 0), - SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER, - 0, 1, NULL, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, - ES8326_HPOR_SHIFT, 7, 7, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, - 0, 7, 7, 0), - SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), }; @@ -166,52 +150,35 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"I2S OUT", NULL, "ADC L"}, {"I2S OUT", NULL, "ADC R"}, - {"I2S OUT", NULL, "Analog Power"}, - {"I2S OUT", NULL, "ADC Vref"}, - {"I2S OUT", NULL, "Vref Power"}, - {"I2S OUT", NULL, "IBias Power"}, - {"I2S IN", NULL, "Analog Power"}, - {"I2S IN", NULL, "DAC Vref"}, - {"I2S IN", NULL, "Vref Power"}, - {"I2S IN", NULL, "IBias Power"}, - {"Right DAC", NULL, "I2S IN"}, {"Left DAC", NULL, "I2S IN"}, {"LHPMIX", NULL, "Left DAC"}, {"RHPMIX", NULL, "Right DAC"}, - {"HPOR", NULL, "HPOR Cal"}, - {"HPOL", NULL, "HPOL Cal"}, - {"HPOR", NULL, "HPOR Supply"}, - {"HPOL", NULL, "HPOL Supply"}, - {"HPOL", NULL, "Headphone Charge Pump"}, - {"HPOR", NULL, "Headphone Charge Pump"}, - {"HPOL", NULL, "Headphone Driver Bias"}, - {"HPOR", NULL, "Headphone Driver Bias"}, - {"HPOL", NULL, "Headphone LDO"}, - {"HPOR", NULL, "Headphone LDO"}, - {"HPOL", NULL, "Headphone Reference"}, - {"HPOR", NULL, "Headphone Reference"}, - {"HPOL", NULL, "LHPMIX"}, {"HPOR", NULL, "RHPMIX"}, }; -static const struct regmap_range es8326_volatile_ranges[] = { - regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT), -}; - -static const struct regmap_access_table es8326_volatile_table = { - .yes_ranges = es8326_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges), -}; +static bool es8326_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ES8326_HPL_OFFSET_INI: + case ES8326_HPR_OFFSET_INI: + case ES8326_HPDET_STA: + case ES8326_CTIA_OMTP_STA: + case ES8326_CSM_MUTE_STA: + return true; + default: + return false; + } +} static const struct regmap_config es8326_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, - .volatile_table = &es8326_volatile_table, + .volatile_reg = es8326_volatile_register, .cache_type = REGCACHE_RBTREE, }; @@ -419,6 +386,38 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); + unsigned int offset_l, offset_r; + + if (mute) { + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ES8326_MUTE); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xf0); + } else { + if (!es8326->calibrated) { + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL); + msleep(30); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); + es8326->calibrated = true; + } + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, + ES8326_MUTE_MASK, ~(ES8326_MUTE)); + } + return 0; +} + static int es8326_set_bias_level(struct snd_soc_component *codec, enum snd_soc_bias_level level) { @@ -430,15 +429,17 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, ret = clk_prepare_enable(es8326->mclk); if (ret) return ret; - regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45); + + regmap_write(es8326->regmap, ES8326_RESET, 0x9f); + msleep(20); + regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); - regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); break; case SND_SOC_BIAS_PREPARE: @@ -447,15 +448,10 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, break; case SND_SOC_BIAS_OFF: clk_disable_unprepare(es8326->mclk); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11); - regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF); - regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8); + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08); + regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); - regmap_write(es8326->regmap, ES8326_RESET, - ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); break; } @@ -469,6 +465,8 @@ static const struct snd_soc_dai_ops es8326_ops = { .hw_params = es8326_pcm_hw_params, .set_fmt = es8326_set_dai_fmt, .set_sysclk = es8326_set_dai_sysclk, + .mute_stream = es8326_mute, + .no_capture_mute = 1, }; static struct snd_soc_dai_driver es8326_dai = { @@ -532,13 +530,14 @@ static void es8326_jack_button_handler(struct work_struct *work) return; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); switch (iface) { case 0x93: /* pause button detected */ cur_button = SND_JACK_BTN_0; break; case 0x6f: + case 0x4b: /* button volume up */ cur_button = SND_JACK_BTN_1; break; @@ -547,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work) cur_button = SND_JACK_BTN_2; break; case 0x1e: + case 0xe2: /* button released or not pressed */ cur_button = 0; break; @@ -556,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work) if ((prev_button == cur_button) && (cur_button != 0)) { press_count++; - if (press_count > 10) { - /* report a press every 500ms */ + if (press_count > 3) { + /* report a press every 120ms */ snd_soc_jack_report(es8326->jack, cur_button, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); press_count = 0; } button_to_report = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else if (prev_button != cur_button) { /* mismatch, detect again */ prev_button = cur_button; queue_delayed_work(system_wq, &es8326->button_press_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(35)); } else { /* released or no pressed */ if (button_to_report != 0) { @@ -591,34 +591,98 @@ static void es8326_jack_detect_handler(struct work_struct *work) unsigned int iface; mutex_lock(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HP_DETECT); + iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); + + if (es8326->jack_remove_retry == 1) { + if (iface & ES8326_HPINSERT_FLAG) + es8326->jack_remove_retry = 2; + else + es8326->jack_remove_retry = 0; + + dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n", + es8326->jack_remove_retry); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + ~es8326->jack_pol : es8326->jack_pol)); + goto exit; + } + if ((iface & ES8326_HPINSERT_FLAG) == 0) { /* Jack unplugged or spurious IRQ */ - dev_dbg(comp->dev, "No headset detected"); + dev_dbg(comp->dev, "No headset detected\n"); + es8326_disable_micbias(es8326->component); if (es8326->jack->status & SND_JACK_HEADPHONE) { + dev_dbg(comp->dev, "Report hp remove event\n"); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); - snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src); - es8326_disable_micbias(comp); + /* mute adc when mic path switch */ + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); + es8326->hp = 0; + } + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + /* + * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event + */ + if (es8326->jack_remove_retry == 0) { + es8326->jack_remove_retry = 1; + dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", + es8326->jack_remove_retry); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? + es8326->jack_pol : ~es8326->jack_pol)); + + } else { + es8326->jack_remove_retry = 0; } } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) { + es8326->jack_remove_retry = 0; + if (es8326->hp == 0) { + dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n"); + /* + * set auto-check mode, then restart jack_detect_work after 100ms. + * Don't report jack status. + */ + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + usleep_range(50000, 70000); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); + queue_delayed_work(system_wq, &es8326->jack_detect_work, + msecs_to_jiffies(100)); + es8326->hp = 1; + goto exit; + } if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ + dev_dbg(comp->dev, "button pressed\n"); queue_delayed_work(system_wq, &es8326->button_press_work, 10); + goto exit; + } + if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { + dev_dbg(comp->dev, "Headphone detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADPHONE, SND_JACK_HEADSET); } else { - if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) { - dev_dbg(comp->dev, "Headset detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADSET, SND_JACK_HEADSET); - snd_soc_component_write(comp, - ES8326_ADC1_SRC, es8326->mic1_src); - } else { - dev_dbg(comp->dev, "Headphone detected"); - snd_soc_jack_report(es8326->jack, - SND_JACK_HEADPHONE, SND_JACK_HEADSET); - } + dev_dbg(comp->dev, "Headset detected\n"); + snd_soc_jack_report(es8326->jack, + SND_JACK_HEADSET, SND_JACK_HEADSET); + + regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x08); + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, + 0x80, 0x80); + regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00); + regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00); + regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, + 0x08, 0x00); + usleep_range(10000, 15000); } } +exit: mutex_unlock(&es8326->lock); } @@ -637,51 +701,138 @@ static irqreturn_t es8326_irq(int irq, void *dev_id) msecs_to_jiffies(10)); else queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(300)); + msecs_to_jiffies(600)); out: return IRQ_HANDLED; } -static int es8326_resume(struct snd_soc_component *component) +static int es8326_calibrate(struct snd_soc_component *component) { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); unsigned int reg; + unsigned int offset_l, offset_r; + + regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); + es8326->version = reg; + + 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, 0x01); + regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30); + regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed); + regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1); + regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33); + regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_RESET, 0xc0); + usleep_range(15000, 20000); + + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, ®); + if ((reg & 0xf0) != 0x40) + msleep(50); + + regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d); + msleep(200); + regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF); + regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l); + regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r); + regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l); + regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); + + es8326->calibrated = true; + } + + return 0; +} + +static int es8326_resume(struct snd_soc_component *component) +{ + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); regcache_cache_only(es8326->regmap, false); regcache_sync(es8326->regmap); + /* reset internal clock state */ + regmap_write(es8326->regmap, ES8326_RESET, 0x1f); + regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); + usleep_range(10000, 15000); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + /* set headphone default type and detect pin */ + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + + /* set internal oscillator as clock source of headpone cp */ + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84); regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); - /* Two channel ADC */ - regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02); + /* clock manager reset release */ + regmap_write(es8326->regmap, ES8326_RESET, 0x17); + /* set headphone detection as half scan mode */ + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08); + regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00); + + /* enable headphone driver */ + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb); + usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); + regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); - regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8); - regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88); - regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4); + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81); + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00); + /* calibrate for B version */ + es8326_calibrate(component); + /* turn off headphone out */ + regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00); + /* set ADC and DAC in low power mode */ + regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); + + /* force micbias on */ + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f); regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); - regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22); - regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src); - regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); - regmap_write(es8326->regmap, ES8326_HP_DET, - ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src); - regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); + /* select vdda as micbias source */ + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23); + /* set dac dsmclip = 1 */ + regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08); + regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15); + + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + regmap_write(es8326->regmap, ES8326_INTOUT_IO, + es8326->interrupt_clk); + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT); + + regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); - snd_soc_component_update_bits(component, ES8326_PGAGAIN, - ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); + regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK, + ES8326_MIC1_SEL); - regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); - if ((reg & ES8326_VERSION_B) == 1) { - regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD); - regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); - regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F); - /* enable button detect */ - regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0); - } + regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, + ES8326_MUTE); - es8326_irq(es8326->irq, es8326); + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 | + ((es8326->version == ES8326_VERSION_B) ? + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : + (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); + + es8326->jack_remove_retry = 0; + es8326->hp = 0; return 0; } @@ -691,11 +842,15 @@ static int es8326_suspend(struct snd_soc_component *component) cancel_delayed_work_sync(&es8326->jack_detect_work); es8326_disable_micbias(component); - + es8326->calibrated = false; regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF); regcache_cache_only(es8326->regmap, true); regcache_mark_dirty(es8326->regmap); + /* reset register value to default */ + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01); + usleep_range(1000, 3000); + regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00); return 0; } @@ -725,7 +880,7 @@ static int es8326_probe(struct snd_soc_component *component) ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); if (ret != 0) { dev_dbg(component->dev, "jack-pol return %d", ret); - es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; + es8326->jack_pol = ES8326_HP_TYPE_AUTO; } dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); @@ -756,7 +911,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, mutex_lock(&es8326->lock); if (es8326->jd_inverted) - snd_soc_component_update_bits(component, ES8326_HP_DET, + snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); es8326->jack = jack; diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h index 8e5ffe5ee10d..90a08351d6ac 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -9,8 +9,6 @@ #ifndef _ES8326_H #define _ES8326_H -#define CONFIG_HHTECH_MINIPMP 1 - /* ES8326 register space */ #define ES8326_RESET 0x00 #define ES8326_CLK_CTL 0x01 @@ -75,15 +73,19 @@ #define ES8326_DRC_RECOVERY 0x53 #define ES8326_DRC_WINSIZE 0x54 #define ES8326_HPJACK_TIMER 0x56 -#define ES8326_HP_DET 0x57 +#define ES8326_HPDET_TYPE 0x57 #define ES8326_INT_SOURCE 0x58 #define ES8326_INTOUT_IO 0x59 #define ES8326_SDINOUT1_IO 0x5A #define ES8326_SDINOUT23_IO 0x5B #define ES8326_JACK_PULSE 0x5C +#define ES8326_HP_MISC 0xF7 +#define ES8326_CTIA_OMTP_STA 0xF8 #define ES8326_PULLUP_CTL 0xF9 -#define ES8326_HP_DETECT 0xFB +#define ES8326_CSM_I2C_STA 0xFA +#define ES8326_HPDET_STA 0xFB +#define ES8326_CSM_MUTE_STA 0xFC #define ES8326_CHIP_ID1 0xFD #define ES8326_CHIP_ID2 0xFE #define ES8326_CHIP_VERSION 0xFF @@ -94,6 +96,8 @@ #define ES8326_PWRUP_SEQ_EN (1 << 5) #define ES8326_CODEC_RESET (0x0f << 0) #define ES8326_CSM_OFF (0 << 7) +#define ES8326_MUTE_MASK (3 << 0) +#define ES8326_MUTE (3 << 0) /* ES8326_CLK_CTL */ #define ES8326_CLK_ON (0x7f << 0) @@ -122,7 +126,9 @@ #define ES8326_MIC2_SEL (1 << 5) /* ES8326_HP_CAL */ -#define ES8326_HPOR_SHIFT 4 +#define ES8326_HP_OFF 0 +#define ES8326_HP_FORCE_CAL ((1 << 7) | (1 << 3)) +#define ES8326_HP_ON ((7 << 4) | (7 << 0)) /* ES8326_ADC1_SRC */ #define ES8326_ADC1_SHIFT 0 @@ -144,7 +150,7 @@ #define ES8326_ADC3_SHIFT 0 #define ES8326_ADC4_SHIFT 3 -/* ES8326_HP_DET */ +/* ES8326_HPDET_TYPE */ #define ES8326_HP_DET_SRC_PIN27 (1 << 5) #define ES8326_HP_DET_SRC_PIN9 (1 << 4) #define ES8326_HP_DET_JACK_POL (1 << 3) @@ -154,6 +160,13 @@ #define ES8326_HP_TYPE_AUTO (1 << 0) #define ES8326_HP_TYPE_AUTO_INV (0 << 0) +/* ES8326_INT_SOURCE */ +#define ES8326_INT_SRC_DAC_MOZ (1 << 0) +#define ES8326_INT_SRC_ADC_MOZ (1 << 1) +#define ES8326_INT_SRC_BUTTON (1 << 2) +#define ES8326_INT_SRC_PIN9 (1 << 3) +#define ES8326_INT_SRC_PIN27 (1 << 4) + /* ES8326_SDINOUT1_IO */ #define ES8326_IO_INPUT (0 << 0) #define ES8326_IO_SDIN_SLOT0 (1 << 0) @@ -172,11 +185,12 @@ #define ES8326_SDINOUT2_SHIFT 4 #define ES8326_SDINOUT3_SHIFT 0 -/* ES8326_HP_DETECT */ +/* ES8326_HPDET_STA */ #define ES8326_HPINSERT_FLAG (1 << 1) #define ES8326_HPBUTTON_FLAG (1 << 0) /* ES8326_CHIP_VERSION 0xFF */ -#define ES8326_VERSION_B (1 << 0) +#define ES8326_VERSION (1 << 0) +#define ES8326_VERSION_B (3 << 0) #endif diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d21f69f05342..13689e718d36 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -723,24 +723,6 @@ static u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_AC97; -static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - .auto_selectable_formats = &hdmi_codec_formats, - .num_auto_selectable_formats = 1, -}; - -static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .mute_stream = hdmi_codec_mute, -}; - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ @@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .probe = hdmi_dai_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .set_fmt = hdmi_codec_i2s_set_fmt, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, +}; + +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .probe = hdmi_dai_spdif_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, +}; + static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_spdif_probe, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 7c25acf6ff0d..d1cea93bdb59 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -301,7 +301,7 @@ static const struct regmap_config jz4740_codec_regmap_config = { .reg_defaults = jz4740_codec_reg_defaults, .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int jz4740_codec_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 685ca95ef4a9..29197d34ec09 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3537,25 +3537,25 @@ static int rx_macro_probe(struct platform_device *pdev) rx->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(rx->macro)) - return PTR_ERR(rx->macro); + return dev_err_probe(dev, PTR_ERR(rx->macro), "unable to get macro clock\n"); rx->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(rx->dcodec)) - return PTR_ERR(rx->dcodec); + return dev_err_probe(dev, PTR_ERR(rx->dcodec), "unable to get dcodec clock\n"); rx->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(rx->mclk)) - return PTR_ERR(rx->mclk); + return dev_err_probe(dev, PTR_ERR(rx->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { rx->npl = devm_clk_get(dev, "npl"); if (IS_ERR(rx->npl)) - return PTR_ERR(rx->npl); + return dev_err_probe(dev, PTR_ERR(rx->npl), "unable to get npl clock\n"); } rx->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(rx->fsgen)) - return PTR_ERR(rx->fsgen); + return dev_err_probe(dev, PTR_ERR(rx->fsgen), "unable to get fsgen clock\n"); rx->pds = lpass_macro_pds_init(dev); if (IS_ERR(rx->pds)) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index de978c3d70b7..3e33418898e8 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1967,25 +1967,25 @@ static int tx_macro_probe(struct platform_device *pdev) tx->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(tx->macro)) - return PTR_ERR(tx->macro); + return dev_err_probe(dev, PTR_ERR(tx->macro), "unable to get macro clock\n"); tx->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(tx->dcodec)) - return PTR_ERR(tx->dcodec); + return dev_err_probe(dev, PTR_ERR(tx->dcodec), "unable to get dcodec clock\n"); tx->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(tx->mclk)) - return PTR_ERR(tx->mclk); + return dev_err_probe(dev, PTR_ERR(tx->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { tx->npl = devm_clk_get(dev, "npl"); if (IS_ERR(tx->npl)) - return PTR_ERR(tx->npl); + return dev_err_probe(dev, PTR_ERR(tx->npl), "unable to get npl clock\n"); } tx->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(tx->fsgen)) - return PTR_ERR(tx->fsgen); + return dev_err_probe(dev, PTR_ERR(tx->fsgen), "unable to get fsgen clock\n"); tx->pds = lpass_macro_pds_init(dev); if (IS_ERR(tx->pds)) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 74724448da50..b71ef03c4aef 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1457,15 +1457,15 @@ static int va_macro_probe(struct platform_device *pdev) va->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(va->macro)) - return PTR_ERR(va->macro); + return dev_err_probe(dev, PTR_ERR(va->macro), "unable to get macro clock\n"); va->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(va->dcodec)) - return PTR_ERR(va->dcodec); + return dev_err_probe(dev, PTR_ERR(va->dcodec), "unable to get dcodec clock\n"); va->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(va->mclk)) - return PTR_ERR(va->mclk); + return dev_err_probe(dev, PTR_ERR(va->mclk), "unable to get mclk clock\n"); va->pds = lpass_macro_pds_init(dev); if (IS_ERR(va->pds)) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 8ba7dc89daaa..ec6859ec0d38 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2396,25 +2396,25 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa->macro = devm_clk_get_optional(dev, "macro"); if (IS_ERR(wsa->macro)) - return PTR_ERR(wsa->macro); + return dev_err_probe(dev, PTR_ERR(wsa->macro), "unable to get macro clock\n"); wsa->dcodec = devm_clk_get_optional(dev, "dcodec"); if (IS_ERR(wsa->dcodec)) - return PTR_ERR(wsa->dcodec); + return dev_err_probe(dev, PTR_ERR(wsa->dcodec), "unable to get dcodec clock\n"); wsa->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(wsa->mclk)) - return PTR_ERR(wsa->mclk); + return dev_err_probe(dev, PTR_ERR(wsa->mclk), "unable to get mclk clock\n"); if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) { wsa->npl = devm_clk_get(dev, "npl"); if (IS_ERR(wsa->npl)) - return PTR_ERR(wsa->npl); + return dev_err_probe(dev, PTR_ERR(wsa->npl), "unable to get npl clock\n"); } wsa->fsgen = devm_clk_get(dev, "fsgen"); if (IS_ERR(wsa->fsgen)) - return PTR_ERR(wsa->fsgen); + return dev_err_probe(dev, PTR_ERR(wsa->fsgen), "unable to get fsgen clock\n"); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index b5c69bba0e48..a2cca3436c68 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -160,35 +160,24 @@ static int max98363_io_init(struct sdw_slave *slave) struct max98363_priv *max98363 = dev_get_drvdata(dev); int ret, reg; - if (max98363->first_hw_init) { - regcache_cache_only(max98363->regmap, false); + regcache_cache_only(max98363->regmap, false); + if (max98363->first_hw_init) regcache_cache_bypass(max98363->regmap, true); - } /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98363->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98363->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, ®); - if (!ret) { + if (!ret) dev_info(dev, "Revision ID: %X\n", reg); - return ret; - } + else + goto out; if (max98363->first_hw_init) { regcache_cache_bypass(max98363->regmap, false); @@ -198,10 +187,11 @@ static int max98363_io_init(struct sdw_slave *slave) max98363->first_hw_init = true; max98363->hw_init = true; +out: pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); - return 0; + return ret; } #define MAX98363_RATES SNDRV_PCM_RATE_8000_192000 @@ -409,6 +399,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) max98363->regmap = regmap; max98363->slave = slave; + regcache_cache_only(max98363->regmap, true); + max98363->hw_init = false; max98363->first_hw_init = false; @@ -416,10 +408,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363, max98363_dai, ARRAY_SIZE(max98363_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + return 0; } static int max98363_sdw_probe(struct sdw_slave *slave, diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index df92242af960..b5cb951af570 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -361,28 +361,17 @@ static int max98373_io_init(struct sdw_slave *slave) struct device *dev = &slave->dev; struct max98373_priv *max98373 = dev_get_drvdata(dev); - if (max98373->first_hw_init) { - regcache_cache_only(max98373->regmap, false); + regcache_cache_only(max98373->regmap, false); + if (max98373->first_hw_init) regcache_cache_bypass(max98373->regmap, true); - } /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!max98373->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - + if (!max98373->first_hw_init) /* update count of parent 'active' children */ pm_runtime_set_active(dev); - /* make sure the device does not suspend immediately */ - pm_runtime_mark_last_busy(dev); - - pm_runtime_enable(dev); - } - pm_runtime_get_noresume(dev); /* Software Reset */ @@ -753,6 +742,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) max98373->regmap = regmap; max98373->slave = slave; + regcache_cache_only(max98373->regmap, true); + max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg); max98373->cache = devm_kcalloc(dev, max98373->cache_num, sizeof(*max98373->cache), @@ -773,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw, max98373_sdw_dai, ARRAY_SIZE(max98373_sdw_dai)); - if (ret < 0) + if (ret < 0) { dev_err(dev, "Failed to register codec: %d\n", ret); + return ret; + } - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } static int max98373_update_status(struct sdw_slave *slave, @@ -834,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave, static int max98373_sdw_remove(struct sdw_slave *slave) { - struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev); - - if (max98373->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index bdc508e23e59..922ce0dc4e60 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); goto err_out; } - if (of_property_read_bool(i2c->dev.of_node, "interleave-mode")) + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") || + of_property_read_bool(i2c->dev.of_node, "interleave-mode")) max98926->interleave_mode = true; if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 0aaf2e6ae78d..776f23d38ac5 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -162,10 +162,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MASK, - mode); + regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MASK, mode); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: @@ -178,10 +176,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, - invert); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert); /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -207,36 +203,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) if (!use_pdm) { /* pcm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_FORMAT_MASK, - format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_FORMAT_MASK, + format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 0); } else { /* pdm channel configuration */ - regmap_update_bits(max98927->regmap, - MAX98927_R0035_PDM_RX_CTRL, - MAX98927_PDM_RX_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R003B_SPK_SRC_SEL, - MAX98927_SPK_SRC_MASK, 3); + regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 3); - regmap_update_bits(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0); + regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + 0); } return 0; } @@ -283,9 +274,9 @@ static int max98927_set_clock(struct max98927_priv *max98927, return -EINVAL; } regmap_update_bits(max98927->regmap, - MAX98927_R0021_PCM_MASTER_MODE, - MAX98927_PCM_MASTER_MODE_MCLK_MASK, - i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); + MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MCLK_MASK, + i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); } if (!max98927->tdm_mode) { @@ -298,9 +289,8 @@ static int max98927_set_clock(struct max98927_priv *max98927, } regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - value); + MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, value); } return 0; } @@ -333,9 +323,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, max98927->ch_size = snd_pcm_format_width(params_format(params)); - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); dev_dbg(component->dev, "format supported %d", params_format(params)); @@ -375,27 +364,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, goto err; } /* set DAI_SR to correct LRCLK frequency */ - regmap_update_bits(max98927->regmap, - MAX98927_R0023_PCM_SR_SETUP1, - MAX98927_PCM_SR_SET1_SR_MASK, - sampling_rate); - regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_SR_MASK, - sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); + regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1, + MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate); + regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_SR_MASK, + sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); /* set sampling rate of IV */ if (max98927->interleave_mode && sampling_rate > MAX98927_PCM_SR_SET1_SR_16000) regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate - 3); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate - 3); else regmap_update_bits(max98927->regmap, - MAX98927_R0024_PCM_SR_SETUP2, - MAX98927_PCM_SR_SET2_IVADC_SR_MASK, - sampling_rate); + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate); return max98927_set_clock(max98927, params); err: return -EINVAL; @@ -420,10 +406,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0022_PCM_CLK_SETUP, - MAX98927_PCM_CLK_SETUP_BSEL_MASK, - bsel); + regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel); /* Channel size configuration */ switch (slot_width) { @@ -442,33 +426,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - regmap_update_bits(max98927->regmap, - MAX98927_R0020_PCM_MODE_CFG, - MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); /* Rx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R0018_PCM_RX_EN_A, - rx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0019_PCM_RX_EN_B, - (rx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A, + rx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B, + (rx_mask & 0xFF00) >> 8); /* Tx slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - (tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + (tx_mask & 0xFF00) >> 8); /* Tx slot Hi-Z configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - ~tx_mask & 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - (~tx_mask & 0xFF00) >> 8); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + ~tx_mask & 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + (~tx_mask & 0xFF00) >> 8); return 0; } @@ -506,20 +483,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 1); - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 1); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 1); break; case SND_SOC_DAPM_POST_PMD: - regmap_update_bits(max98927->regmap, - MAX98927_R00FF_GLOBAL_SHDN, - MAX98927_GLOBAL_EN_MASK, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R003A_AMP_EN, - MAX98927_AMP_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 0); break; default: return 0; @@ -532,8 +505,8 @@ static const char * const max98927_switch_text[] = { static const struct soc_enum dai_sel_enum = SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, - 3, max98927_switch_text); + MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3, + max98927_switch_text); static const struct snd_kcontrol_new max98927_dai_controls = SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); @@ -543,17 +516,17 @@ static const struct snd_kcontrol_new max98927_vi_control = static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN, - 0, 0, max98927_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + 0, 0, max98927_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, - &max98927_dai_controls), + &max98927_dai_controls), SND_SOC_DAPM_OUTPUT("BE_OUT"), SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 0, 0), + MAX98927_R003E_MEAS_EN, 0, 0), SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, - MAX98927_R003E_MEAS_EN, 1, 0), + MAX98927_R003E_MEAS_EN, 1, 0), SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, - &max98927_vi_control), + &max98927_vi_control), SND_SOC_DAPM_SIGGEN("VMON"), SND_SOC_DAPM_SIGGEN("IMON"), }; @@ -623,20 +596,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit, max98927_current_limit_text); static const struct snd_kcontrol_new max98927_snd_controls[] = { - SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, - 0, 6, 0, - max98927_spk_tlv), + SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0, + max98927_spk_tlv), SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL, - 0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0, - max98927_digital_tlv), + 0, (1 << MAX98927_AMP_VOL_WIDTH) - 1, 0, + max98927_digital_tlv), SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN, - MAX98927_BROWNOUT_DSP_SHIFT, 1, 0), + MAX98927_BROWNOUT_DSP_SHIFT, 1, 0), SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG, - MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0), - SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL, - MAX98927_DRE_EN_SHIFT, 1, 0), + MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0), + SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL, MAX98927_DRE_EN_SHIFT, + 1, 0), SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL, - MAX98927_AMP_VOL_SEL_SHIFT, 1, 0), + MAX98927_AMP_VOL_SEL_SHIFT, 1, 0), SOC_ENUM("Boost Output Voltage", max98927_boost_voltage), SOC_ENUM("Current Limit", max98927_current_limit), }; @@ -682,117 +654,82 @@ static int max98927_probe(struct snd_soc_component *component) max98927->component = component; /* Software Reset */ - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); /* IV default slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 0xFF); - regmap_write(max98927->regmap, - MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, - 0x80); - regmap_write(max98927->regmap, - MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, - 0x1); + regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF); + regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF); + regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, + 0x80); + regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, + 0x1); /* Set inital volume (+13dB) */ - regmap_write(max98927->regmap, - MAX98927_R0036_AMP_VOL_CTRL, - 0x38); - regmap_write(max98927->regmap, - MAX98927_R003C_SPK_GAIN, - 0x05); + regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38); + regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05); /* Enable DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R0037_AMP_DSP_CFG, - 0x03); + regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03); /* Enable IMON VMON DC blocker */ - regmap_write(max98927->regmap, - MAX98927_R003F_MEAS_DSP_CFG, - 0xF7); + regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7); /* Boost Output Voltage & Current limit */ - regmap_write(max98927->regmap, - MAX98927_R0040_BOOST_CTRL0, - 0x1C); - regmap_write(max98927->regmap, - MAX98927_R0042_BOOST_CTRL1, - 0x3E); + regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C); + regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E); /* Measurement ADC config */ - regmap_write(max98927->regmap, - MAX98927_R0043_MEAS_ADC_CFG, - 0x04); - regmap_write(max98927->regmap, - MAX98927_R0044_MEAS_ADC_BASE_MSB, - 0x00); - regmap_write(max98927->regmap, - MAX98927_R0045_MEAS_ADC_BASE_LSB, - 0x24); + regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04); + regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00); + regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24); /* Brownout Level */ - regmap_write(max98927->regmap, - MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, - 0x06); + regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, + 0x06); /* Envelope Tracking configuration */ - regmap_write(max98927->regmap, - MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, - 0x08); - regmap_write(max98927->regmap, - MAX98927_R0086_ENV_TRACK_CTRL, - 0x01); - regmap_write(max98927->regmap, - MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, - 0x10); + regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, + 0x08); + regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01); + regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, + 0x10); /* voltage, current slot configuration */ - regmap_write(max98927->regmap, - MAX98927_R001E_PCM_TX_CH_SRC_A, - (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT| - max98927->v_l_slot)&0xFF); + regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A, + (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF); if (max98927->v_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->v_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->v_l_slot, - 1 << max98927->v_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->v_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->v_l_slot, + 1 << max98927->v_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->v_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->v_l_slot - 8), - 1 << (max98927->v_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->v_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->v_l_slot - 8), + 1 << (max98927->v_l_slot - 8)); } if (max98927->i_l_slot < 8) { regmap_update_bits(max98927->regmap, - MAX98927_R001C_PCM_TX_HIZ_CTRL_A, - 1 << max98927->i_l_slot, 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001A_PCM_TX_EN_A, - 1 << max98927->i_l_slot, - 1 << max98927->i_l_slot); + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->i_l_slot, 0); + regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->i_l_slot, + 1 << max98927->i_l_slot); } else { regmap_update_bits(max98927->regmap, - MAX98927_R001D_PCM_TX_HIZ_CTRL_B, - 1 << (max98927->i_l_slot - 8), 0); - regmap_update_bits(max98927->regmap, - MAX98927_R001B_PCM_TX_EN_B, - 1 << (max98927->i_l_slot - 8), - 1 << (max98927->i_l_slot - 8)); + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->i_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->i_l_slot - 8), + 1 << (max98927->i_l_slot - 8)); } /* Set interleave mode */ if (max98927->interleave_mode) regmap_update_bits(max98927->regmap, - MAX98927_R001F_PCM_TX_CH_SRC_B, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK, - MAX98927_PCM_TX_CH_INTERLEAVE_MASK); + MAX98927_R001F_PCM_TX_CH_SRC_B, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK); return 0; } @@ -809,8 +746,8 @@ static int max98927_resume(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); - regmap_write(max98927->regmap, - MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, + MAX98927_SOFT_RESET); regcache_cache_only(max98927->regmap, false); regcache_sync(max98927->regmap); return 0; @@ -869,9 +806,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) int reg = 0; struct max98927_priv *max98927 = NULL; - max98927 = devm_kzalloc(&i2c->dev, - sizeof(*max98927), GFP_KERNEL); - + max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL); if (!max98927) { ret = -ENOMEM; return ret; @@ -879,14 +814,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, max98927); /* update interleave mode info */ - if (!of_property_read_u32(i2c->dev.of_node, - "interleave_mode", &value)) { - if (value > 0) - max98927->interleave_mode = true; - else - max98927->interleave_mode = false; - } else - max98927->interleave_mode = false; + if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) { + max98927->interleave_mode = true; + } else { + if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", + &value)) + if (value > 0) + max98927->interleave_mode = true; + } /* regmap initialization */ max98927->regmap @@ -897,9 +832,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c) "Failed to allocate regmap: %d\n", ret); return ret; } - - max98927->reset_gpio - = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH); + + max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(max98927->reset_gpio)) { ret = PTR_ERR(max98927->reset_gpio); return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin"); @@ -912,8 +847,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c) } /* Check Revision ID */ - ret = regmap_read(max98927->regmap, - MAX98927_R01FF_REV_ID, ®); + ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID); @@ -938,9 +872,8 @@ static void max98927_i2c_remove(struct i2c_client *i2c) { struct max98927_priv *max98927 = i2c_get_clientdata(i2c); - if (max98927->reset_gpio) { + if (max98927->reset_gpio) gpiod_set_value_cansleep(max98927->reset_gpio, 1); - } } static const struct i2c_device_id max98927_i2c_id[] = { diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index cec90cf920ff..9ca381812975 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -7,7 +7,6 @@ #include <linux/delay.h> #include <linux/regulator/consumer.h> #include <linux/types.h> -#include <linux/clk.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -1198,12 +1197,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(priv->mclk)) { - dev_err(dev, "failed to get mclk\n"); - return PTR_ERR(priv->mclk); - } - for (i = 0; i < ARRAY_SIZE(supply_names); i++) priv->supplies[i].supply = supply_names[i]; @@ -1214,55 +1207,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return ret; } - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(dev, "failed to enable mclk %d\n", ret); - return ret; - } - irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc switch irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc switch irq\n"); + return ret; + } if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn press irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc button press irq\n"); + return ret; + } irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mbhc btn release irq", priv); - if (ret) + if (ret) { dev_err(dev, "cannot request mbhc button release irq\n"); - + return ret; + } } dev_set_drvdata(dev, priv); @@ -1270,17 +1256,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); - -err_disable_clk: - clk_disable_unprepare(priv->mclk); - return ret; -} - -static void pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) -{ - struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(priv->mclk); } static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { @@ -1296,7 +1271,6 @@ static struct platform_driver pm8916_wcd_analog_spmi_driver = { .of_match_table = pm8916_wcd_analog_spmi_match_table, }, .probe = pm8916_wcd_analog_spmi_probe, - .remove_new = pm8916_wcd_analog_spmi_remove, }; module_platform_driver(pm8916_wcd_analog_spmi_driver); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 9e0e4ddf128e..5cb0de648bd3 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/int_log.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -38,7 +39,6 @@ #define NAU_FVCO_MIN 90000000 /* cross talk suppression detection */ -#define LOG10_MAGIC 646456993 #define GAIN_AUGMENT 22500 #define SIDETONE_BASE 207000 @@ -219,42 +219,6 @@ static const struct reg_sequence nau8825_regmap_patch[] = { { NAU8825_REG_MIC_BIAS, 0x0046 }, }; - -static const unsigned short logtable[256] = { - 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, - 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, - 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, - 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, - 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, - 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, - 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, - 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, - 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, - 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, - 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, - 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, - 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, - 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, - 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, - 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, - 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, - 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, - 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, - 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, - 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, - 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, - 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, - 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, - 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, - 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, - 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, - 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, - 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, - 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, - 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, - 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 -}; - /** * nau8825_sema_acquire - acquire the semaphore of nau88l25 * @nau8825: component to register the codec private data with @@ -368,65 +332,14 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, } /** - * nau8825_intlog10_dec3 - Computes log10 of a value - * the result is round off to 3 decimal. This function takes reference to - * dvb-math. The source code locates as the following. - * Linux/drivers/media/dvb-core/dvb_math.c + * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places. * @value: input for log10 * * return log10(value) * 1000 */ static u32 nau8825_intlog10_dec3(u32 value) { - u32 msb, logentry, significand, interpolation, log10val; - u64 log2val; - - /* first detect the msb (count begins at 0) */ - msb = fls(value) - 1; - /** - * now we use a logtable after the following method: - * - * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 - * where x = msb and therefore 1 <= y < 2 - * first y is determined by shifting the value left - * so that msb is bit 31 - * 0x00231f56 -> 0x8C7D5800 - * the result is y * 2^31 -> "significand" - * then the highest 9 bits are used for a table lookup - * the highest bit is discarded because it's always set - * the highest nine bits in our example are 100011000 - * so we would use the entry 0x18 - */ - significand = value << (31 - msb); - logentry = (significand >> 23) & 0xff; - /** - * last step we do is interpolation because of the - * limitations of the log table the error is that part of - * the significand which isn't used for lookup then we - * compute the ratio between the error and the next table entry - * and interpolate it between the log table entry used and the - * next one the biggest error possible is 0x7fffff - * (in our example it's 0x7D5800) - * needed value for next table entry is 0x800000 - * so the interpolation is - * (error / 0x800000) * (logtable_next - logtable_current) - * in the implementation the division is moved to the end for - * better accuracy there is also an overflow correction if - * logtable_next is 256 - */ - interpolation = ((significand & 0x7fffff) * - ((logtable[(logentry + 1) & 0xff] - - logtable[logentry]) & 0xffff)) >> 15; - - log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation); - /** - * log10(x) = log2(x) * log10(2) - */ - log10val = (log2val * LOG10_MAGIC) >> 31; - /** - * the result is round off to 3 decimal - */ - return log10val / ((1 << 24) / 1000); + return intlog10(value) / ((1 << 24) / 1000); } /** diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 42bac8150f62..d5285baad53a 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -13,11 +13,9 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/acpi.h> #include <linux/regmap.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/firmware.h> #include <sound/core.h> diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 38d9f69b08d6..99ec0f9a8362 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -12,7 +12,6 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/fs.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 06800dad8798..44e7fe3c32da 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -8,7 +8,6 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index b1e69fa290b2..919a1f25e584 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/firmware.h> -#include <linux/gpio.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c new file mode 100644 index 000000000000..7295f44c77eb --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -0,0 +1,824 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2023 Realtek Semiconductor Corp. +// +// +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/pm_runtime.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <sound/core.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 "rt1017-sdca-sdw.h" + +static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0x3206: + case 0xc000: + case 0xc001: + case 0xc022: + case 0xc030: + case 0xc104: + case 0xc10b: + case 0xc10c: + case 0xc110: + case 0xc112: + case 0xc300: + case 0xc301: + case 0xc318: + case 0xc325 ... 0xc328: + case 0xc331: + case 0xc340: + case 0xc350 ... 0xc351: + case 0xc500: + case 0xc502: + case 0xc504: + case 0xc507: + case 0xc509: + case 0xc510: + case 0xc512: + case 0xc518: + case 0xc51b: + case 0xc51d: + case 0xc520: + case 0xc540 ... 0xc542: + case 0xc550 ... 0xc552: + case 0xc600: + case 0xc602: + case 0xc612: + case 0xc622: + case 0xc632: + case 0xc642: + case 0xc651: + case 0xca00: + case 0xca09 ... 0xca0c: + case 0xca0e ... 0xca0f: + case 0xca10 ... 0xca11: + case 0xca16 ... 0xca17: + case 0xcb00: + case 0xcc00: + case 0xcc02: + case 0xd017: + case 0xd01a ... 0xd01c: + case 0xd101: + case 0xd20c: + case 0xd300: + case 0xd370: + case 0xd500: + case 0xd545 ... 0xd548: + case 0xd5a5 ... 0xd5a8: + case 0xd5aa ... 0xd5ad: + case 0xda04 ... 0xda07: + case 0xda09 ... 0xda0a: + case 0xda0c ... 0xda0f: + case 0xda11 ... 0xda14: + case 0xda16 ... 0xda19: + case 0xdab6 ... 0xdabb: + case 0xdb09 ... 0xdb0a: + case 0xdb14: + + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0): + return true; + default: + return false; + } +} + +static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f55: + case 0xc000: + case 0xc022: + case 0xc351: + case 0xc518: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29, + RT1017_SDCA_CTL_PROT_STAT, 0): + return true; + default: + return false; + } +} + +static const struct reg_sequence rt1017_blind_write[] = { + { 0xc001, 0x43 }, + { 0x2f55, 0x02 }, + { 0x3206, 0x80 }, + { 0x005f, 0x7f }, + { 0xd101, 0xa0 }, + { 0xc112, 0xc0 }, + { 0xc104, 0xaa }, + { 0xc110, 0x59 }, + { 0xc112, 0xc0 }, + { 0xc340, 0x80 }, + { 0xd017, 0x2c }, + { 0xd01a, 0xc8 }, + { 0xd01b, 0xcf }, + { 0xd01c, 0x0c }, + { 0xd20c, 0x14 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0x7f }, + { 0xdb14, 0x03 }, + { 0xcb00, 0x31 }, + { 0xc318, 0x44 }, + { 0xc325, 0xce }, + { 0xc326, 0x13 }, + { 0xc327, 0x5f }, + { 0xc328, 0xf3 }, + { 0xc350, 0xe1 }, + { 0xc351, 0x88 }, + { 0xc030, 0x14 }, + { 0xc331, 0xf2 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc651, 0xc0 }, + { 0xc550, 0xd0 }, + { 0xc612, 0x00 }, + { 0xc622, 0x00 }, + { 0xc632, 0x00 }, + { 0xc642, 0x00 }, + { 0xc602, 0xf0 }, + { 0xc600, 0xd0 }, + { 0xcc02, 0x78 }, + { 0xcc00, 0x90 }, + { 0xc300, 0x3f }, + { 0xc301, 0x1d }, + { 0xc10b, 0x2e }, + { 0xc10c, 0x36 }, + + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x6a }, + { 0xd5a7, 0xaa }, + { 0xd5a8, 0xaa }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x16 }, + { 0xd5ac, 0xdb }, + { 0xd5ad, 0x6d }, + { 0xd545, 0x09 }, + { 0xd546, 0x30 }, + { 0xd547, 0xf0 }, + { 0xd548, 0xf0 }, + { 0xd500, 0x20 }, + { 0xc504, 0x3f }, + { 0xc540, 0x00 }, + { 0xc541, 0x0a }, + { 0xc542, 0x1a }, + { 0xc512, 0x00 }, + { 0xc520, 0x40 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc500, 0x40 }, + { 0xc502, 0xde }, + { 0xc507, 0x05 }, + { 0xc509, 0x05 }, + { 0xc510, 0x40 }, + { 0xc518, 0xc0 }, + { 0xc500, 0xc0 }, + + { 0xda0c, 0x00 }, + { 0xda0d, 0x0b }, + { 0xda0e, 0x55 }, + { 0xda0f, 0x55 }, + { 0xda04, 0x00 }, + { 0xda05, 0x51 }, + { 0xda06, 0xeb }, + { 0xda07, 0x85 }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda11, 0x26 }, + { 0xda12, 0x66 }, + { 0xda13, 0x66 }, + { 0xda14, 0x66 }, + { 0xda16, 0x79 }, + { 0xda17, 0x99 }, + { 0xda18, 0x99 }, + { 0xda19, 0x99 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x07 }, + { 0xca0b, 0x89 }, + { 0xca0c, 0x61 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x03 }, + { 0xca10, 0xc4 }, + { 0xca11, 0xb0 }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x00 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x00 }, + { 0xd017, 0x0e }, + { 0xca00, 0xcd }, + { 0xc022, 0x84 }, +}; + +#define RT1017_MAX_REG_NUM 0x4108ffff + +static const struct regmap_config rt1017_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1017_sdca_readable_register, + .volatile_reg = rt1017_sdca_volatile_register, + .max_register = RT1017_MAX_REG_NUM, + .reg_defaults = rt1017_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1017_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists + * port = 1 for AMP playback + * port = 2 for IV capture + */ + prop->source_ports = BIT(2); /* BITMAP: 00000100 */ + prop->sink_ports = BIT(1); /* BITMAP: 00000010 */ + + 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 = 64; + + return 0; +} + +static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (rt1017->hw_init) + return 0; + + if (rt1017->first_hw_init) { + regcache_cache_only(rt1017->regmap, false); + regcache_cache_bypass(rt1017->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); + + /* sw reset */ + regmap_write(rt1017->regmap, 0xc000, 0x02); + + /* initial settings - blind write */ + regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write, + ARRAY_SIZE(rt1017_blind_write)); + + if (rt1017->first_hw_init) { + regcache_cache_bypass(rt1017->regmap, false); + regcache_mark_dirty(rt1017->regmap); + } else + rt1017->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt1017->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "hw_init complete\n"); + return 0; +} + +static int rt1017_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt1017->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1017_sdca_io_init(&slave->dev, slave); +} + +static const char * const rt1017_rx_data_ch_select[] = { + "Bypass", + "CN1", + "CN2", + "CN3", + "CN4", + "(1+2)/2", + "(1+3)/2", + "(1+4)/2", + "(2+3)/2", + "(2+4)/2", + "(3+4)/2", +}; + +static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), + 0, rt1017_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1017_sdca_controls[] = { + /* UDMPU Cluster Selection */ + SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1017_sto_dac = + SOC_DAPM_SINGLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1), + 0, 1, 1); + +static int rt1017_sdca_pde23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + default: + break; + } + return 0; +} + +static int rt1017_sdca_classd_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 rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1, + RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG); + regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10); + break; + default: + break; + } + + return 0; +} + +static int rt1017_sdca_feedback_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 rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0, + rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Digital Interface */ + SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac), + + /* Output Lines */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPO"), + + SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0, + rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("I Gen"), + SND_SOC_DAPM_SIGGEN("V Gen"), +}; + +static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = { + + { "DAC", "Switch", "DP1RX" }, + { "CLASS D", NULL, "DAC" }, + { "CLASS D", NULL, "PDE23" }, + { "SPO", NULL, "CLASS D" }, + + { "I Sense", NULL, "I Gen" }, + { "V Sense", NULL, "V Gen" }, + { "I Sense", NULL, "PDE23" }, + { "V Sense", NULL, "PDE23" }, + { "DP2TX", NULL, "I Sense" }, + { "DP2TX", NULL, "V Sense" }, +}; + +static struct sdw_slave_ops rt1017_sdca_slave_ops = { + .read_prop = rt1017_sdca_read_prop, + .update_status = rt1017_sdca_update_status, +}; + +static int rt1017_sdca_component_probe(struct snd_soc_component *component) +{ + int ret; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static void rt1017_sdca_component_remove(struct snd_soc_component *component) +{ + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt1017->regmap, true); +} + +static const struct snd_soc_component_driver soc_sdca_component_rt1017 = { + .probe = rt1017_sdca_component_probe, + .remove = rt1017_sdca_component_remove, + .controls = rt1017_sdca_controls, + .num_controls = ARRAY_SIZE(rt1017_sdca_controls), + .dapm_widgets = rt1017_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets), + .dapm_routes = rt1017_sdca_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes), + .endianness = 1, +}; + +static int rt1017_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 rt1017_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt1017_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 rt1017_sdca_priv *rt1017 = 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, ch_mask; + 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 (!rt1017->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + num_channels = params_channels(params); + ch_mask = (1 << num_channels) - 1; + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = num_channels; + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + port_config.ch_mask = ch_mask; + port_config.num = port; + + dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n", + params_rate(params), num_channels, snd_pcm_format_width(params_format(params)), + direction, ch_mask, port); + + retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT1017_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT1017_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT1017_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT1017_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt1017->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1017->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream); + return 0; +} + +static const struct snd_soc_dai_ops rt1017_sdca_ops = { + .hw_params = rt1017_sdca_pcm_hw_params, + .hw_free = rt1017_sdca_pcm_hw_free, + .set_stream = rt1017_sdca_set_sdw_stream, + .shutdown = rt1017_sdca_shutdown, +}; + +#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver rt1017_sdca_dai[] = { + { + .name = "rt1017-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 1, + .rates = RT1017_STEREO_RATES, + .formats = RT1017_FORMATS, + }, + .ops = &rt1017_sdca_ops, + }, +}; + +static int rt1017_sdca_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017; + int ret; + + rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL); + if (!rt1017) + return -ENOMEM; + + dev_set_drvdata(dev, rt1017); + rt1017->sdw_slave = slave; + rt1017->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1017->hw_init = false; + rt1017->first_hw_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_sdca_component_rt1017, + rt1017_sdca_dai, + ARRAY_SIZE(rt1017_sdca_dai)); + + return ret; +} + +static int rt1017_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt1017_sdca_init(&slave->dev, regmap, slave); +} + +static int rt1017_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev); + + if (rt1017->first_hw_init) + pm_runtime_disable(&slave->dev); + + return 0; +} + +static const struct sdw_device_id rt1017_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id); + +static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev) +{ + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + + if (!rt1017->hw_init) + return 0; + + regcache_cache_only(rt1017->regmap, true); + + return 0; +} + +#define RT1017_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1017->first_hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1017_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(rt1017->regmap, false); + regcache_sync(rt1017->regmap); + + return 0; +} + +static const struct dev_pm_ops rt1017_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt1017_sdca_sdw_driver = { + .driver = { + .name = "rt1017-sdca", + .owner = THIS_MODULE, + .pm = &rt1017_sdca_pm, + }, + .probe = rt1017_sdca_sdw_probe, + .remove = rt1017_sdca_sdw_remove, + .ops = &rt1017_sdca_slave_ops, + .id_table = rt1017_sdca_id, +}; +module_sdw_driver(rt1017_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW"); +MODULE_AUTHOR("Derek Fang <derek.fang@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h new file mode 100644 index 000000000000..4932b5dbe3c0 --- /dev/null +++ b/sound/soc/codecs/rt1017-sdca-sdw.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2023 Realtek Semiconductor Corp. + */ + +#ifndef __RT1017_SDW_H__ +#define __RT1017_SDW_H__ + +#include <linux/regmap.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> +#include <sound/soc.h> + +/* RT1017 SDCA Control - function number */ +#define FUNC_NUM_SMART_AMP 0x04 + +/* RT1017 SDCA entity */ +#define RT1017_SDCA_ENT_PDE23 0x31 +#define RT1017_SDCA_ENT_PDE22 0x33 +#define RT1017_SDCA_ENT_CS21 0x21 +#define RT1017_SDCA_ENT_SAPU29 0x29 +#define RT1017_SDCA_ENT_XU22 0x22 +#define RT1017_SDCA_ENT_FU 0x03 +#define RT1017_SDCA_ENT_UDMPU21 0x02 + +/* RT1017 SDCA control */ +#define RT1017_SDCA_CTL_FS_INDEX 0x10 +#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1017_SDCA_CTL_PROT_STAT 0x11 +#define RT1017_SDCA_CTL_BYPASS 0x01 +#define RT1017_SDCA_CTL_FU_MUTE 0x01 +#define RT1017_SDCA_CTL_FU_VOLUME 0x02 +#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10 + + +#define RT1017_CLASSD_INT_1 0xd300 +#define RT1017_PWM_TRIM_1 0xd370 + + +#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK (0x3 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE (0x2 << 2) +#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG (0x0 << 2) + +enum { + RT1017_SDCA_RATE_44100HZ = 0x8, + RT1017_SDCA_RATE_48000HZ = 0x9, + RT1017_SDCA_RATE_96000HZ = 0xb, + RT1017_SDCA_RATE_192000HZ = 0xd, +}; + +struct rt1017_sdca_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; +}; + +static const struct reg_default rt1017_sdca_reg_defaults[] = { + { 0x3206, 0x00 }, + { 0xc001, 0x43 }, + { 0xc030, 0x54 }, + { 0xc104, 0x8a }, + { 0xc10b, 0x2f }, + { 0xc10c, 0x2f }, + { 0xc110, 0x49 }, + { 0xc112, 0x10 }, + { 0xc300, 0xff }, + { 0xc301, 0xdd }, + { 0xc318, 0x40 }, + { 0xc325, 0x00 }, + { 0xc326, 0x00 }, + { 0xc327, 0x00 }, + { 0xc328, 0x02 }, + { 0xc331, 0xb2 }, + { 0xc340, 0x02 }, + { 0xc350, 0x21 }, + { 0xc500, 0x00 }, + { 0xc502, 0x00 }, + { 0xc504, 0x3f }, + { 0xc507, 0x1f }, + { 0xc509, 0x1f }, + { 0xc510, 0x40 }, + { 0xc512, 0x00 }, + { 0xc518, 0x02 }, + { 0xc51b, 0x7f }, + { 0xc51d, 0x0f }, + { 0xc520, 0x00 }, + { 0xc540, 0x80 }, + { 0xc541, 0x00 }, + { 0xc542, 0x0a }, + { 0xc550, 0x80 }, + { 0xc551, 0x0f }, + { 0xc552, 0xff }, + { 0xc600, 0x10 }, + { 0xc602, 0x83 }, + { 0xc612, 0x40 }, + { 0xc622, 0x40 }, + { 0xc632, 0x40 }, + { 0xc642, 0x40 }, + { 0xc651, 0x00 }, + { 0xca00, 0xc1 }, + { 0xca09, 0x00 }, + { 0xca0a, 0x51 }, + { 0xca0b, 0xeb }, + { 0xca0c, 0x85 }, + { 0xca0e, 0x00 }, + { 0xca0f, 0x10 }, + { 0xca10, 0x62 }, + { 0xca11, 0x4d }, + { 0xca16, 0x0f }, + { 0xca17, 0x00 }, + { 0xcb00, 0x10 }, + { 0xcc00, 0x10 }, + { 0xcc02, 0x0b }, + { 0xd017, 0x09 }, + { 0xd01a, 0x00 }, + { 0xd01b, 0x00 }, + { 0xd01c, 0x00 }, + { 0xd101, 0xa0 }, + { 0xd20c, 0x14 }, + { 0xd300, 0x0f }, + { 0xd370, 0x18 }, + { 0xd500, 0x00 }, + { 0xd545, 0x0b }, + { 0xd546, 0xf9 }, + { 0xd547, 0xb2 }, + { 0xd548, 0xa9 }, + { 0xd5a5, 0x00 }, + { 0xd5a6, 0x00 }, + { 0xd5a7, 0x00 }, + { 0xd5a8, 0x00 }, + { 0xd5aa, 0x00 }, + { 0xd5ab, 0x00 }, + { 0xd5ac, 0x00 }, + { 0xd5ad, 0x00 }, + { 0xda04, 0x03 }, + { 0xda05, 0x33 }, + { 0xda06, 0x33 }, + { 0xda07, 0x33 }, + { 0xda09, 0x5d }, + { 0xda0a, 0xc0 }, + { 0xda0c, 0x00 }, + { 0xda0d, 0x01 }, + { 0xda0e, 0x5d }, + { 0xda0f, 0x86 }, + { 0xda11, 0x20 }, + { 0xda12, 0x00 }, + { 0xda13, 0x00 }, + { 0xda14, 0x00 }, + { 0xda16, 0x7f }, + { 0xda17, 0xff }, + { 0xda18, 0xff }, + { 0xda19, 0xff }, + { 0xdab6, 0x00 }, + { 0xdab7, 0x01 }, + { 0xdab8, 0x00 }, + { 0xdab9, 0x01 }, + { 0xdaba, 0x00 }, + { 0xdabb, 0x01 }, + { 0xdb09, 0x0f }, + { 0xdb0a, 0xff }, + { 0xdb14, 0x00 }, + + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21, + RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, + RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22, + RT1017_SDCA_CTL_BYPASS, 0), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21, + RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22, + RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + +#endif /* __RT1017_SDW_H__ */ diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index fd55049920c1..ceb8baa6a20d 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -18,7 +18,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/firmware.h> -#include <linux/gpio.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 59895131e6e0..80888cbcf49c 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -12,10 +12,8 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/acpi.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/firmware.h> #include <sound/core.h> diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index f43520ca3187..63d4abf964d4 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -52,6 +52,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg) case 0x300a: case 0xc000: case 0xc710: + case 0xcf01: case 0xc860 ... 0xc863: case 0xc870 ... 0xc873: return true; @@ -213,35 +214,28 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); int ret = 0; - unsigned int tmp; + unsigned int tmp, hibernation_flag; if (rt1308->hw_init) return 0; - if (rt1308->first_hw_init) { - regcache_cache_only(rt1308->regmap, false); + regcache_cache_only(rt1308->regmap, false); + if (rt1308->first_hw_init) regcache_cache_bypass(rt1308->regmap, true); - } /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt1308->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt1308->first_hw_init) /* 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); + regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag); + if ((hibernation_flag != 0x00) && rt1308->first_hw_init) + goto _preset_ready_; + /* sw reset */ regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); @@ -282,6 +276,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc100, 0xd7); regmap_write(rt1308->regmap, 0xc101, 0xd7); + /* apply BQ params */ + rt1308_apply_bq_params(rt1308); + + regmap_write(rt1308->regmap, 0xcf01, 0x01); + +_preset_ready_: if (rt1308->first_hw_init) { regcache_cache_bypass(rt1308->regmap, false); regcache_mark_dirty(rt1308->regmap); @@ -626,6 +626,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component) rt1308->component = component; rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev); + if (!rt1308->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -688,6 +691,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, rt1308->sdw_slave = slave; rt1308->regmap = regmap; + regcache_cache_only(rt1308->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -699,10 +704,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1308, rt1308_sdw_dai, ARRAY_SIZE(rt1308_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1308_sdw_probe(struct sdw_slave *slave, @@ -715,17 +737,12 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt1308_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt1308_sdw_init(&slave->dev, regmap, slave); } static int rt1308_sdw_remove(struct sdw_slave *slave) { - struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); - - if (rt1308->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index 9d07756cda40..86afb429d423 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -11,10 +11,8 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> -#include <linux/of_gpio.h> #include <linux/acpi.h> #include <linux/platform_device.h> #include <linux/firmware.h> diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 721821d9e9af..47511f70119a 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -272,25 +272,16 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) if (rt1316->hw_init) return 0; + regcache_cache_only(rt1316->regmap, false); if (rt1316->first_hw_init) { - regcache_cache_only(rt1316->regmap, false); regcache_cache_bypass(rt1316->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only 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); @@ -424,6 +415,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum, SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0, rt1316_rx_data_ch_select); +static const char * const rt1316_dac_output_vol_select[] = { + "immediately", + "zero crossing", + "zero crossing with soft ramp", +}; + +static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum, + 0xc010, 6, rt1316_dac_output_vol_select); + static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* I2S Data Channel Selection */ @@ -442,6 +442,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = { /* IV mixer Control */ SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1), SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1), + + /* DAC Output Volume Control */ + SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum), }; static const struct snd_kcontrol_new rt1316_sto_dac = @@ -595,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component) rt1316->component = component; rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev); + if (!rt1316->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -662,6 +668,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, rt1316->sdw_slave = slave; rt1316->regmap = regmap; + regcache_cache_only(rt1316->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -673,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1316, rt1316_sdw_dai, ARRAY_SIZE(rt1316_sdw_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static int rt1316_sdw_probe(struct sdw_slave *slave, @@ -694,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, static int rt1316_sdw_remove(struct sdw_slave *slave) { - struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); - - if (rt1316->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 16d750102c8c..ff364bde4a08 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -408,25 +408,15 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave) if (rt1318->hw_init) return 0; + regcache_cache_only(rt1318->regmap, false); if (rt1318->first_hw_init) { - regcache_cache_only(rt1318->regmap, false); regcache_cache_bypass(rt1318->regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only 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); @@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component) rt1318->component = component; + if (!rt1318->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret); if (ret < 0 && ret != -EACCES) @@ -752,6 +745,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, rt1318->sdw_slave = slave; rt1318->regmap = regmap; + regcache_cache_only(rt1318->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -763,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap, &soc_component_sdw_rt1318, rt1318_sdw_dai, ARRAY_SIZE(rt1318_sdw_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -784,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave, static int rt1318_sdw_remove(struct sdw_slave *slave) { - struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev); - - if (rt1318->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 362663abcb89..3ee6d85268ba 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> -#include <linux/gpio.h> #include <linux/sched.h> #include <linux/uaccess.h> #include <linux/regulator/consumer.h> diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index b3aac2373357..43fc7814fdde 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -17,7 +17,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/firmware.h> -#include <linux/gpio.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index eceed8209787..15e1a62b9e57 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -12,11 +12,10 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> @@ -2571,7 +2570,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640_disable_jack_detect(component); return; } @@ -2626,7 +2625,7 @@ static void rt5640_enable_hda_jack_detect( NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640); if (ret) { - dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret); + dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret); rt5640->irq = -ENXIO; return; } @@ -2812,8 +2811,8 @@ static int rt5640_suspend(struct snd_soc_component *component) rt5640_reset(component); regcache_cache_only(rt5640->regmap, true); regcache_mark_dirty(rt5640->regmap); - if (gpio_is_valid(rt5640->ldo1_en)) - gpio_set_value_cansleep(rt5640->ldo1_en, 0); + if (rt5640->ldo1_en) + gpiod_set_value_cansleep(rt5640->ldo1_en, 0); return 0; } @@ -2822,8 +2821,8 @@ static int rt5640_resume(struct snd_soc_component *component) { struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(rt5640->ldo1_en)) { - gpio_set_value_cansleep(rt5640->ldo1_en, 1); + if (rt5640->ldo1_en) { + gpiod_set_value_cansleep(rt5640->ldo1_en, 1); msleep(400); } @@ -2986,22 +2985,6 @@ static const struct acpi_device_id rt5640_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); #endif -static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np) -{ - rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0); - /* - * LDO1_EN is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5640->ldo1_en) && - (rt5640->ldo1_en != -ENOENT)) - return rt5640->ldo1_en; - - return 0; -} - static int rt5640_i2c_probe(struct i2c_client *i2c) { struct rt5640_priv *rt5640; @@ -3015,12 +2998,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return -ENOMEM; i2c_set_clientdata(i2c, rt5640); - if (i2c->dev.of_node) { - ret = rt5640_parse_dt(rt5640, i2c->dev.of_node); - if (ret) - return ret; - } else - rt5640->ldo1_en = -EINVAL; + rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5640->ldo1_en)) + return PTR_ERR(rt5640->ldo1_en); + + if (rt5640->ldo1_en) { + gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN"); + msleep(400); + } rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); if (IS_ERR(rt5640->regmap)) { @@ -3030,18 +3017,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5640->ldo1_en)) { - ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en, - GPIOF_OUT_INIT_HIGH, - "RT5640 LDO1_EN"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n", - rt5640->ldo1_en, ret); - return ret; - } - msleep(400); - } - regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 9847a1ae01f4..94b9a502f7f9 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2138,7 +2138,7 @@ struct rt5640_priv { struct regmap *regmap; struct clk *mclk; - int ldo1_en; /* GPIO for LDO1_EN */ + struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */ int irq; int jd_gpio_irq; int sysclk; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a506d940a2ea..038d93e20883 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -14,7 +14,6 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/acpi.h> #include <linux/dmi.h> @@ -81,6 +80,7 @@ static const struct reg_sequence init_list[] = { static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, + {RT5645_PWR_ANLG1, 0x02}, }; static const struct reg_default rt5645_reg[] = { @@ -1697,6 +1697,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on) regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, + RT5645_PWR_HP_L | RT5645_PWR_HP_R); msleep(90); } else { /* depop parameters */ @@ -1744,7 +1747,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on) snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140); msleep(100); snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001); - + snd_soc_component_update_bits(component, RT5645_PWR_ANLG1, + RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0); } else { snd_soc_component_update_bits(component, RT5645_DEPOP_M1, RT5645_HP_SG_MASK | @@ -3151,7 +3155,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse unsigned int val; if (jack_insert) { - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206); /* for jack type detect */ snd_soc_dapm_force_enable_pin(dapm, "LDO2"); @@ -3196,6 +3200,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse if (rt5645->pdata.level_trigger_irq) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); + + regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); } else { /* jack out */ rt5645->jack_type = 0; @@ -3258,6 +3264,22 @@ int rt5645_set_jack_detect(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); +static int rt5645_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct snd_soc_jack *mic_jack = NULL; + struct snd_soc_jack *btn_jack = NULL; + int *type = (int *)data; + + if (*type & SND_JACK_MICROPHONE) + mic_jack = hs_jack; + if (*type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + btn_jack = hs_jack; + + return rt5645_set_jack_detect(component, hs_jack, mic_jack, btn_jack); +} + static void rt5645_jack_detect_work(struct work_struct *work) { struct rt5645_priv *rt5645 = @@ -3532,6 +3554,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = { .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets), .dapm_routes = rt5645_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes), + .set_jack = rt5645_component_set_jack, .use_pmdown_time = 1, .endianness = 1, }; @@ -3987,13 +4010,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c) regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080); - ret = regmap_register_patch(rt5645->regmap, init_list, + ret = regmap_multi_reg_write(rt5645->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); if (rt5645->codec_type == CODEC_TYPE_RT5650) { - ret = regmap_register_patch(rt5645->regmap, rt5650_init_list, + ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list, ARRAY_SIZE(rt5650_init_list)); if (ret != 0) dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n", @@ -4182,11 +4205,43 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c) regmap_write(rt5645->regmap, RT5645_RESET, 0); } +static int __maybe_unused rt5645_sys_suspend(struct device *dev) +{ + struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + + del_timer_sync(&rt5645->btn_check_timer); + cancel_delayed_work_sync(&rt5645->jack_detect_work); + cancel_delayed_work_sync(&rt5645->rcclock_work); + + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return 0; +} + +static int __maybe_unused rt5645_sys_resume(struct device *dev) +{ + struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + + regcache_cache_only(rt5645->regmap, false); + regcache_sync(rt5645->regmap); + + if (rt5645->hp_jack) { + rt5645->jack_type = 0; + rt5645_jack_detect_work(&rt5645->jack_detect_work.work); + } + return 0; +} + +static const struct dev_pm_ops rt5645_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume) +}; + static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), + .pm = &rt5645_pm, }, .probe = rt5645_i2c_probe, .remove = rt5645_i2c_remove, diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index df6f0d769bbd..a061028a16d8 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -16,7 +16,6 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index eade087b2d8b..0cecfd602415 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -11,11 +11,9 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/pm.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 83c367af91da..a39de4a7df00 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/mutex.h> #include <sound/core.h> @@ -4472,6 +4471,8 @@ static void rt5665_remove(struct snd_soc_component *component) struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component); regmap_write(rt5665->regmap, RT5665_RESET, 0); + + regulator_bulk_disable(ARRAY_SIZE(rt5665->supplies), rt5665->supplies); } #ifdef CONFIG_PM @@ -4657,9 +4658,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5665->pdata.jd_src); - rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -4793,10 +4791,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5665->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5665")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + + rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5665->gpiod_ldo1_en)) { + dev_err(&i2c->dev, "Failed gpio request ldo1_en\n"); + return PTR_ERR(rt5665->gpiod_ldo1_en); } /* Sleep for 300 ms miniumum */ diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index f04c810fd710..4623b3e62487 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/mutex.h> #include <sound/core.h> @@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = { struct rt5668_priv { struct snd_soc_component *component; struct rt5668_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES]; @@ -2393,9 +2393,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev) of_property_read_u32(dev->of_node, "realtek,jd-src", &rt5668->pdata.jd_src); - rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - return 0; } @@ -2497,10 +2494,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5668->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5668")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5668->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5668->ldo1_en); } /* Sleep for 300 ms miniumum */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ad14d18860fc..0e70a3ab42b5 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,23 +6,21 @@ * Author: Oder Chiou <oder_chiou@realtek.com> */ -#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/firmware.h> #include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irqdomain.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> +#include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/property.h> #include <linux/regmap.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> #include <linux/spi/spi.h> -#include <linux/firmware.h> -#include <linux/of_device.h> -#include <linux/property.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/irqdomain.h> #include <linux/workqueue.h> #include <sound/core.h> #include <sound/pcm.h> @@ -4717,50 +4715,34 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt5677_update_gpio_bits(struct rt5677_priv *rt5677, unsigned offset, int m, int v) +{ + unsigned int bank = offset / 5; + unsigned int shift = (offset % 5) * 3; + unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2; + + return regmap_update_bits(rt5677->regmap, reg, m << shift, v << shift); +} + #ifdef CONFIG_GPIOLIB static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO; + int m = RT5677_GPIOx_OUT_MASK; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1)); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT); - break; - - default: - break; - } + rt5677_update_gpio_bits(rt5677, offset, m, level); } static int rt5677_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO; + int m = RT5677_GPIOx_DIR_MASK | RT5677_GPIOx_OUT_MASK; + int v = RT5677_GPIOx_DIR_OUT | level; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x3 << (offset * 3 + 1), - (0x2 | !!value) << (offset * 3 + 1)); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK, - RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT); - break; - - default: - break; - } - - return 0; + return rt5677_update_gpio_bits(rt5677, offset, m, v); } static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -4778,26 +4760,14 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + int m = RT5677_GPIOx_DIR_MASK; + int v = RT5677_GPIOx_DIR_IN; - switch (offset) { - case RT5677_GPIO1 ... RT5677_GPIO5: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - 0x1 << (offset * 3 + 2), 0x0); - break; - - case RT5677_GPIO6: - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, - RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN); - break; - - default: - break; - } - - return 0; + return rt5677_update_gpio_bits(rt5677, offset, m, v); } -/** Configures the gpio as +/* + * Configures the GPIO as * 0 - floating * 1 - pull down * 2 - pull up @@ -5539,7 +5509,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); /* Ready to listen for interrupts */ - rt5677->domain = irq_domain_add_linear(i2c->dev.of_node, + rt5677->domain = irq_domain_create_linear(dev_fwnode(&i2c->dev), RT5677_IRQ_NUM, &rt5677_domain_ops, rt5677); if (!rt5677->domain) { dev_err(&i2c->dev, "Failed to create IRQ domain\n"); @@ -5559,6 +5529,7 @@ static int rt5677_init_irq(struct i2c_client *i2c) static int rt5677_i2c_probe(struct i2c_client *i2c) { + struct device *dev = &i2c->dev; struct rt5677_priv *rt5677; int ret; unsigned int val; @@ -5573,21 +5544,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work); i2c_set_clientdata(i2c, rt5677); - if (i2c->dev.of_node) { - const struct of_device_id *match_id; - - match_id = of_match_device(rt5677_of_match, &i2c->dev); - if (match_id) - rt5677->type = (enum rt5677_type)match_id->data; - } else if (ACPI_HANDLE(&i2c->dev)) { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev); - if (acpi_id) - rt5677->type = (enum rt5677_type)acpi_id->driver_data; - } else { + rt5677->type = (enum rt5677_type)(uintptr_t)device_get_match_data(dev); + if (rt5677->type == 0) return -EINVAL; - } rt5677_read_device_properties(rt5677, &i2c->dev); @@ -5673,9 +5632,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c) regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, RT5677_GPIO5_FUNC_MASK, RT5677_GPIO5_FUNC_DMIC); - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, - RT5677_GPIO5_DIR_MASK, - RT5677_GPIO5_DIR_OUT); + rt5677_update_gpio_bits(rt5677, RT5677_GPIO5, + RT5677_GPIOx_DIR_MASK, + RT5677_GPIOx_DIR_OUT); } if (rt5677->pdata.micbias1_vdd_3v3) @@ -5702,7 +5661,7 @@ static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = RT5677_DRV_NAME, .of_match_table = rt5677_of_match, - .acpi_match_table = ACPI_PTR(rt5677_acpi_match), + .acpi_match_table = rt5677_acpi_match, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 944ae02aafc2..d67ebae067d9 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1587,81 +1587,19 @@ #define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13) #define RT5677_FUNC_MODE_JTAG (0x1 << 13) -/* GPIO Control 2 (0xc1) */ -#define RT5677_GPIO5_DIR_MASK (0x1 << 14) -#define RT5677_GPIO5_DIR_SFT 14 -#define RT5677_GPIO5_DIR_IN (0x0 << 14) -#define RT5677_GPIO5_DIR_OUT (0x1 << 14) -#define RT5677_GPIO5_OUT_MASK (0x1 << 13) -#define RT5677_GPIO5_OUT_SFT 13 -#define RT5677_GPIO5_OUT_LO (0x0 << 13) -#define RT5677_GPIO5_OUT_HI (0x1 << 13) -#define RT5677_GPIO5_P_MASK (0x1 << 12) -#define RT5677_GPIO5_P_SFT 12 -#define RT5677_GPIO5_P_NOR (0x0 << 12) -#define RT5677_GPIO5_P_INV (0x1 << 12) -#define RT5677_GPIO4_DIR_MASK (0x1 << 11) -#define RT5677_GPIO4_DIR_SFT 11 -#define RT5677_GPIO4_DIR_IN (0x0 << 11) -#define RT5677_GPIO4_DIR_OUT (0x1 << 11) -#define RT5677_GPIO4_OUT_MASK (0x1 << 10) -#define RT5677_GPIO4_OUT_SFT 10 -#define RT5677_GPIO4_OUT_LO (0x0 << 10) -#define RT5677_GPIO4_OUT_HI (0x1 << 10) -#define RT5677_GPIO4_P_MASK (0x1 << 9) -#define RT5677_GPIO4_P_SFT 9 -#define RT5677_GPIO4_P_NOR (0x0 << 9) -#define RT5677_GPIO4_P_INV (0x1 << 9) -#define RT5677_GPIO3_DIR_MASK (0x1 << 8) -#define RT5677_GPIO3_DIR_SFT 8 -#define RT5677_GPIO3_DIR_IN (0x0 << 8) -#define RT5677_GPIO3_DIR_OUT (0x1 << 8) -#define RT5677_GPIO3_OUT_MASK (0x1 << 7) -#define RT5677_GPIO3_OUT_SFT 7 -#define RT5677_GPIO3_OUT_LO (0x0 << 7) -#define RT5677_GPIO3_OUT_HI (0x1 << 7) -#define RT5677_GPIO3_P_MASK (0x1 << 6) -#define RT5677_GPIO3_P_SFT 6 -#define RT5677_GPIO3_P_NOR (0x0 << 6) -#define RT5677_GPIO3_P_INV (0x1 << 6) -#define RT5677_GPIO2_DIR_MASK (0x1 << 5) -#define RT5677_GPIO2_DIR_SFT 5 -#define RT5677_GPIO2_DIR_IN (0x0 << 5) -#define RT5677_GPIO2_DIR_OUT (0x1 << 5) -#define RT5677_GPIO2_OUT_MASK (0x1 << 4) -#define RT5677_GPIO2_OUT_SFT 4 -#define RT5677_GPIO2_OUT_LO (0x0 << 4) -#define RT5677_GPIO2_OUT_HI (0x1 << 4) -#define RT5677_GPIO2_P_MASK (0x1 << 3) -#define RT5677_GPIO2_P_SFT 3 -#define RT5677_GPIO2_P_NOR (0x0 << 3) -#define RT5677_GPIO2_P_INV (0x1 << 3) -#define RT5677_GPIO1_DIR_MASK (0x1 << 2) -#define RT5677_GPIO1_DIR_SFT 2 -#define RT5677_GPIO1_DIR_IN (0x0 << 2) -#define RT5677_GPIO1_DIR_OUT (0x1 << 2) -#define RT5677_GPIO1_OUT_MASK (0x1 << 1) -#define RT5677_GPIO1_OUT_SFT 1 -#define RT5677_GPIO1_OUT_LO (0x0 << 1) -#define RT5677_GPIO1_OUT_HI (0x1 << 1) -#define RT5677_GPIO1_P_MASK (0x1 << 0) -#define RT5677_GPIO1_P_SFT 0 -#define RT5677_GPIO1_P_NOR (0x0 << 0) -#define RT5677_GPIO1_P_INV (0x1 << 0) - -/* GPIO Control 3 (0xc2) */ -#define RT5677_GPIO6_DIR_MASK (0x1 << 2) -#define RT5677_GPIO6_DIR_SFT 2 -#define RT5677_GPIO6_DIR_IN (0x0 << 2) -#define RT5677_GPIO6_DIR_OUT (0x1 << 2) -#define RT5677_GPIO6_OUT_MASK (0x1 << 1) -#define RT5677_GPIO6_OUT_SFT 1 -#define RT5677_GPIO6_OUT_LO (0x0 << 1) -#define RT5677_GPIO6_OUT_HI (0x1 << 1) -#define RT5677_GPIO6_P_MASK (0x1 << 0) -#define RT5677_GPIO6_P_SFT 0 -#define RT5677_GPIO6_P_NOR (0x0 << 0) -#define RT5677_GPIO6_P_INV (0x1 << 0) +/* GPIO Control 2 (0xc1) & 3 (0xc2) common bits */ +#define RT5677_GPIOx_DIR_MASK (0x1 << 2) +#define RT5677_GPIOx_DIR_SFT 2 +#define RT5677_GPIOx_DIR_IN (0x0 << 2) +#define RT5677_GPIOx_DIR_OUT (0x1 << 2) +#define RT5677_GPIOx_OUT_MASK (0x1 << 1) +#define RT5677_GPIOx_OUT_SFT 1 +#define RT5677_GPIOx_OUT_LO (0x0 << 1) +#define RT5677_GPIOx_OUT_HI (0x1 << 1) +#define RT5677_GPIOx_P_MASK (0x1 << 0) +#define RT5677_GPIOx_P_SFT 0 +#define RT5677_GPIOx_P_NOR (0x0 << 0) +#define RT5677_GPIOx_P_INV (0x1 << 0) /* General Control (0xfa) */ #define RT5677_IRQ_DEBOUNCE_SEL_MASK (0x3 << 3) @@ -1753,8 +1691,8 @@ enum { }; enum rt5677_type { - RT5677, - RT5676, + RT5677 = 1, + RT5676 = 2, }; /* ASRC clock source selection */ diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index fb8ffb5b2ff6..b05b4f73d8aa 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> @@ -170,11 +169,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); - } + ret = rt5682_get_ldo1(rt5682, &i2c->dev); + if (ret) + return ret; /* Sleep for 300 ms miniumum */ usleep_range(300000, 350000); diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 4968a8c0064d..e67c2e19cb1a 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -12,8 +12,6 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/mutex.h> @@ -322,6 +320,14 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, return ret; } + + ret = rt5682_get_ldo1(rt5682, dev); + if (ret) + return ret; + + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -336,7 +342,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, ret = devm_snd_soc_register_component(dev, &rt5682_soc_component_dev, rt5682_dai, ARRAY_SIZE(rt5682_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -352,30 +376,20 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) if (rt5682->hw_init) return 0; + regcache_cache_only(rt5682->sdw_regmap, false); + regcache_cache_only(rt5682->regmap, false); + if (rt5682->first_hw_init) + regcache_cache_bypass(rt5682->regmap, true); + /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt5682->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt5682->first_hw_init) /* 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); - if (rt5682->first_hw_init) { - regcache_cache_only(rt5682->regmap, false); - regcache_cache_bypass(rt5682->regmap, true); - } - while (loop > 0) { regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val); if (val == DEVICE_ID) @@ -674,9 +688,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return -EINVAL; - rt5682_sdw_init(&slave->dev, regmap, slave); - - return 0; + return rt5682_sdw_init(&slave->dev, regmap, slave); } static int rt5682_sdw_remove(struct sdw_slave *slave) @@ -686,8 +698,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave) if (rt5682->hw_init) cancel_delayed_work_sync(&rt5682->jack_detect_work); - if (rt5682->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } @@ -707,6 +718,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) cancel_delayed_work_sync(&rt5682->jack_detect_work); + regcache_cache_only(rt5682->sdw_regmap, true); regcache_cache_only(rt5682->regmap, true); regcache_mark_dirty(rt5682->regmap); @@ -771,6 +783,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) regmap_sync: slave->unattach_request = 0; + regcache_cache_only(rt5682->sdw_regmap, false); regcache_cache_only(rt5682->regmap, false); regcache_sync(rt5682->regmap); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 5d992543b791..e3aca9c785a0 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> @@ -1017,6 +1016,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, rt5682->hs_jack = hs_jack; + if (rt5682->is_sdw && !rt5682->first_hw_init) + return 0; + if (!hs_jack) { regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); @@ -3091,9 +3093,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) device_property_read_u32(dev, "realtek,dmic-delay-ms", &rt5682->pdata.dmic_delay); - rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682->pdata.dai_clk_names, RT5682_DAI_NUM_CLKS) < 0) @@ -3108,6 +3107,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) } EXPORT_SYMBOL_GPL(rt5682_parse_dt); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev) +{ + rt5682->ldo1_en = devm_gpiod_get_optional(dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682->ldo1_en)) { + dev_err(dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682->ldo1_en); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5682_get_ldo1); + void rt5682_calibrate(struct rt5682_priv *rt5682) { int value, count; diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 1a43d595f341..b2d9e87af259 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -11,6 +11,7 @@ #include <sound/rt5682.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> @@ -1430,6 +1431,7 @@ struct rt5682_priv { struct snd_soc_component *component; struct device *i2c_dev; struct rt5682_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct regmap *sdw_regmap; struct snd_soc_jack *hs_jack; @@ -1481,6 +1483,7 @@ int rt5682_register_component(struct device *dev); void rt5682_calibrate(struct rt5682_priv *rt5682); void rt5682_reset(struct rt5682_priv *rt5682); int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev); +int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev); int rt5682_register_dai_clks(struct rt5682_priv *rt5682); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c77c675bd5f5..68ac5ea50396 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/mutex.h> #include <sound/core.h> #include <sound/pcm.h> @@ -2973,9 +2972,6 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) device_property_read_u32(dev, "realtek,amic-delay-ms", &rt5682s->pdata.amic_delay); - rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node, - "realtek,ldo1-en-gpios", 0); - if (device_property_read_string_array(dev, "clock-output-names", rt5682s->pdata.dai_clk_names, RT5682S_DAI_NUM_CLKS) < 0) @@ -3172,10 +3168,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) return ret; } - if (gpio_is_valid(rt5682s->pdata.ldo1_en)) { - if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en, - GPIOF_OUT_INIT_HIGH, "rt5682s")) - dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev, + "realtek,ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5682s->ldo1_en)) { + dev_err(&i2c->dev, "Fail gpio request ldo1_en\n"); + return PTR_ERR(rt5682s->ldo1_en); } /* Sleep for 50 ms minimum */ diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index caa7733b430f..1d79d432d0d8 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -11,6 +11,7 @@ #include <sound/rt5682s.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> @@ -1446,6 +1447,7 @@ enum { struct rt5682s_priv { struct snd_soc_component *component; struct rt5682s_platform_data pdata; + struct gpio_desc *ldo1_en; struct regmap *regmap; struct snd_soc_jack *hs_jack; struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES]; diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 8b28e47775cc..52c33d56b143 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt700_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt700_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt700_sdw_remove(struct sdw_slave *slave) @@ -466,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt700->jack_btn_check_work); } - if (rt700->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index a04b9246256b..0ebf344a1b60 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, rt700->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component) rt700->component = component; + if (!rt700->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1099,6 +1106,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, rt700->sdw_regmap = sdw_regmap; rt700->regmap = regmap; + regcache_cache_only(rt700->regmap, true); + mutex_init(&rt700->disable_irq_lock); INIT_DELAYED_WORK(&rt700->jack_detect_work, @@ -1117,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt700, rt700_dai, ARRAY_SIZE(rt700_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ dev_dbg(&slave->dev, "%s\n", __func__); - return ret; + return 0; } int rt700_io_init(struct device *dev, struct sdw_slave *slave) @@ -1132,28 +1157,17 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hw_init) return 0; - if (rt700->first_hw_init) { - regcache_cache_only(rt700->regmap, false); + regcache_cache_only(rt700->regmap, false); + if (rt700->first_hw_init) regcache_cache_bypass(rt700->regmap, true); - } /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt700->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - - /* update count of parent 'active' children */ + if (!rt700->first_hw_init) + /* PM runtime status is marked as 'active' only when a Slave reports as Attached */ 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); /* reset */ diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 23f23f714b39..935e597022d3 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt711->jack_btn_check_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 07640d2f6e56..447154cb6010 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component) rt711_sdca_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1406,6 +1413,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + regcache_cache_only(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1431,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711_sdca_dai, ARRAY_SIZE(rt711_sdca_dai)); - dev_dbg(&slave->dev, "%s\n", __func__); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711) @@ -1500,27 +1528,19 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; + regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->mbq_regmap, false); + if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); regcache_cache_bypass(rt711->regmap, true); - regcache_cache_only(rt711->mbq_regmap, false); regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only 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); diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 33dced388f9e..3f5773310ae8 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt711_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt711_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt711_sdw_remove(struct sdw_slave *slave) @@ -468,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave) cancel_work_sync(&rt711->calibration_work); } - if (rt711->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt711->calibrate_mutex); mutex_destroy(&rt711->disable_irq_lock); diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index af53cbcc7bf2..66eaed13b0d6 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, rt711->hs_jack = hs_jack; + /* we can only resume if the device was initialized at least once */ + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component) rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; + if (!rt711->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1183,6 +1190,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + regcache_cache_only(rt711->regmap, true); + mutex_init(&rt711->calibrate_mutex); mutex_init(&rt711->disable_irq_lock); @@ -1204,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt711, rt711_dai, ARRAY_SIZE(rt711_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - dev_dbg(&slave->dev, "%s\n", __func__); + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1219,28 +1245,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; - if (rt711->first_hw_init) { - regcache_cache_only(rt711->regmap, false); + regcache_cache_only(rt711->regmap, false); + if (rt711->first_hw_init) regcache_cache_bypass(rt711->regmap, true); - } /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt711->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt711->first_hw_init) /* 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); rt711_reset(rt711->regmap); diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 869cc7bfd178..ba08d03e717c 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -182,27 +182,18 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only 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); @@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component) rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -777,6 +771,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -791,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap, &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } @@ -954,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave, static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave) { - struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev); - - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 6bc50396a0f6..6b644a89c589 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave) cancel_delayed_work_sync(&rt712->jack_btn_check_work); } - if (rt712->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); mutex_destroy(&rt712->calibrate_mutex); mutex_destroy(&rt712->disable_irq_lock); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 89d245655ca4..7077ff6ba1f4 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, rt712->hs_jack = hs_jack; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { if (ret != -EACCES) { @@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component) rt712_sdca_parse_dt(rt712, &rt712->slave->dev); rt712->component = component; + if (!rt712->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -1183,6 +1189,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->regmap = regmap; rt712->mbq_regmap = mbq_regmap; + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + mutex_init(&rt712->calibrate_mutex); mutex_init(&rt712->disable_irq_lock); @@ -1207,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, else ret = devm_snd_soc_register_component(dev, &soc_sdca_dev_rt712, rt712_sdca_dai, 1); + if (ret < 0) + return ret; - dev_dbg(&slave->dev, "%s\n", __func__); + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); - return ret; + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); + + return 0; } int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) @@ -1224,27 +1250,18 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hw_init) return 0; + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); if (rt712->first_hw_init) { - regcache_cache_only(rt712->regmap, false); regcache_cache_bypass(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, false); regcache_cache_bypass(rt712->mbq_regmap, true); } else { /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only 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); diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index df10916bab46..ab54a67a27eb 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, static int rt715_sdca_sdw_remove(struct sdw_slave *slave) { - struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index b989f907784b..9fa96fd83d4a 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { static int rt715_sdca_probe(struct snd_soc_component *component) { + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -977,6 +981,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, rt715->regmap = regmap; rt715->mbq_regmap = mbq_regmap; rt715->hw_sdw_ver = slave->id.sdw_version; + + regcache_cache_only(rt715->regmap, true); + regcache_cache_only(rt715->mbq_regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -988,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, &soc_codec_dev_rt715_sdca, rt715_sdca_dai, ARRAY_SIZE(rt715_sdca_dai)); + if (ret < 0) + return ret; + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + dev_dbg(dev, "%s\n", __func__); return ret; } @@ -1000,22 +1027,16 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + regcache_cache_only(rt715->mbq_regmap, false); + /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ if (!rt715->first_hw_init) { - /* 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); - rt715->first_hw_init = true; } diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 6db87442b783..21f37babd148 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -508,17 +508,12 @@ static int rt715_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); - rt715_init(&slave->dev, sdw_regmap, regmap, slave); - - return 0; + return rt715_init(&slave->dev, sdw_regmap, regmap, slave); } static int rt715_sdw_remove(struct sdw_slave *slave) { - struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); - - if (rt715->first_hw_init) - pm_runtime_disable(&slave->dev); + pm_runtime_disable(&slave->dev); return 0; } diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 6c2e165dd621..b59230c8fd32 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -16,14 +16,11 @@ #include <linux/pm_runtime.h> #include <linux/pm.h> #include <linux/soundwire/sdw.h> -#include <linux/gpio.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include <linux/gpio/consumer.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/of_device.h> #include <sound/core.h> #include <sound/pcm.h> @@ -52,6 +49,60 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg, return ret; } +static int rt715_index_write_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + pr_err("Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} + +static int rt715_index_read_nid(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) + pr_err("Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid, + unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp, orig; + int ret; + + ret = rt715_index_read_nid(regmap, nid, reg, &orig); + if (ret < 0) + return ret; + + tmp = orig & ~mask; + tmp |= val & mask; + + return rt715_index_write_nid(regmap, nid, reg, tmp); +} + +static void rt715_reset(struct regmap *regmap) +{ + regmap_write(regmap, RT715_FUNC_RESET, 0); + rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS, + RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG, + RT715_CLEAR_HIDDEN_REG); +} + + static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, unsigned int addr_l, unsigned int val_h, unsigned int *r_val, unsigned int *l_val) @@ -740,8 +791,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component, static int rt715_probe(struct snd_soc_component *component) { + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); int ret; + if (!rt715->first_hw_init) + return 0; + ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -984,6 +1039,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, rt715->regmap = regmap; rt715->sdw_regmap = sdw_regmap; + regcache_cache_only(rt715->regmap, true); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -995,8 +1052,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, &soc_codec_dev_rt715, rt715_dai, ARRAY_SIZE(rt715_dai)); + if (ret < 0) + return ret; - return ret; + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + + /* important note: the device is NOT tagged as 'active' and will remain + * 'suspended' until the hardware is enumerated/initialized. This is required + * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently + * fail with -EACCESS because of race conditions between card creation and enumeration + */ + + return 0; } int rt715_io_init(struct device *dev, struct sdw_slave *slave) @@ -1006,25 +1080,19 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) if (rt715->hw_init) return 0; + regcache_cache_only(rt715->regmap, false); + /* - * PM runtime is only enabled when a Slave reports as Attached + * PM runtime status is marked as 'active' only when a Slave reports as Attached */ - if (!rt715->first_hw_init) { - /* set autosuspend parameters */ - pm_runtime_set_autosuspend_delay(&slave->dev, 3000); - pm_runtime_use_autosuspend(&slave->dev); - + if (!rt715->first_hw_init) /* 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); + rt715_reset(rt715->regmap); + /* Mute nid=08h/09h */ regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080); regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080); diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 12a0ae656d09..6e37bf64e12f 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -48,6 +48,7 @@ struct rt715_priv { #define RT715_INLINE_CMD 0x55 /* Index (NID:20h) */ +#define RT715_VD_CLEAR_CTRL 0x01 #define RT715_SDW_INPUT_SEL 0x39 #define RT715_EXT_DMIC_CLK_CTRL2 0x54 @@ -71,6 +72,8 @@ struct rt715_priv { #define RT715_READ_HDA_0 0x2015 #define RT715_PRIV_INDEX_W_H 0x7520 #define RT715_PRIV_INDEX_W_L 0x85a0 +#define RT715_PRIV_INDEX_W_H_2 0x7500 +#define RT715_PRIV_INDEX_W_L_2 0x8580 #define RT715_PRIV_DATA_W_H 0x7420 #define RT715_PRIV_DATA_W_L 0x84a0 #define RT715_PRIV_INDEX_R_H 0x9d20 @@ -198,6 +201,10 @@ struct rt715_priv { #define RT715_SET_DMIC4_CONFIG_DEFAULT4\ (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4) +/* vendor register clear ctrl-1 (0x01)(NID:20h) */ +#define RT715_CLEAR_HIDDEN_REG (0x1 << 15) + + #define RT715_MUTE_SFT 7 #define RT715_DIR_IN_SFT 6 #define RT715_DIR_OUT_SFT 7 diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index e9103ffb3f50..a38ec5862214 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -175,7 +175,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_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_6); sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); } diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index 9c0d34366c9e..0e1c65a20392 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -191,8 +191,7 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work) return; /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ - if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 || - rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) { ret = rt722_sdca_headset_detect(rt722); if (ret < 0) return; diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c index 008cb3eb5758..8c6665677a17 100644 --- a/sound/soc/codecs/ssm3515.c +++ b/sound/soc/codecs/ssm3515.c @@ -437,7 +437,7 @@ MODULE_DEVICE_TABLE(of, ssm3515_of_match); static struct i2c_driver ssm3515_i2c_driver = { .driver = { .name = "ssm3515", - .of_match_table = of_match_ptr(ssm3515_of_match), + .of_match_table = ssm3515_of_match, }, .probe = ssm3515_i2c_probe, }; diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 4a694d0bfd68..34ffd32ab9dc 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1022,7 +1022,7 @@ static const struct regmap_config sta32x_regmap = { .max_register = STA32X_FDRC2, .reg_defaults = sta32x_regs, .num_reg_defaults = ARRAY_SIZE(sta32x_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta32x_write_regs, .rd_table = &sta32x_read_regs, .volatile_table = &sta32x_volatile_regs, diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index d05f3fd57661..e4a9e9241c60 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1065,7 +1065,7 @@ static const struct regmap_config sta350_regmap = { .max_register = STA350_MISC2, .reg_defaults = sta350_regs, .num_reg_defaults = ARRAY_SIZE(sta350_regs), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .wr_table = &sta350_write_regs, .rd_table = &sta350_read_regs, .volatile_table = &sta350_volatile_regs, diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0ac08478ddac..eedafef775e5 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -331,7 +331,7 @@ static const struct regmap_config sta529_regmap = { .max_register = STA529_MAX_REGISTER, .readable_reg = sta529_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = sta529_reg_defaults, .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), }; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 1824a71fe053..2f9f10a4dfed 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x78, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 99545bcb2ba9..c421906a0694 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -316,7 +316,7 @@ static const struct regmap_config stih407_sas_regmap = { .reg_defaults = stih407_sas_reg_defaults, .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), .volatile_reg = sti_sas_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_read = sti_sas_read_reg, .reg_write = sti_sas_write_reg, }; diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index a88c6c28a394..ffb26e4a7e2f 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -57,16 +57,17 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, if (client->addr != tasdev->dev_addr) { client->addr = tasdev->dev_addr; - if (tasdev->cur_book == book) { - ret = regmap_write(map, - TASDEVICE_PAGE_SELECT, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", - __func__, ret); - goto out; - } + /* All tas2781s share the same regmap, clear the page + * inside regmap once switching to another tas2781. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", + __func__, ret); + goto out; } - goto out; } if (tasdev->cur_book != book) { diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 4c59429a42b7..55cd5e3c23a5 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -743,7 +743,6 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match); static struct i2c_driver tasdevice_i2c_driver = { .driver = { .name = "tas2781-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tasdevice_of_match), #ifdef CONFIG_ACPI .acpi_match_table = ACPI_PTR(tasdevice_acpi_match), diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index aca3756ffab6..3b53eba38a0b 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -520,12 +520,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) } tas5805m->dsp_cfg_len = fw->size; - tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL); + tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL); if (!tas5805m->dsp_cfg_data) { release_firmware(fw); return -ENOMEM; } - memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size); release_firmware(fw); diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index c116e82f712d..5c0a76a4a106 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, u8 divisor; divisor = DIV_ROUND_UP(parent_rate, rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; return regmap_update_bits(div->regmap, div->reg, @@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, unsigned long divisor; divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); @@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); - unsigned int val; + int err; + + err = regmap_read(div->regmap, div->reg, &val); + if (err) + return 0; - regmap_read(div->regmap, div->reg, &val); + val &= AIC32X4_DIV_MASK; + if (!val) + val = AIC32X4_DIV_MAX; - return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK); + return DIV_ROUND_UP(parent_rate, val); } static const struct clk_ops aic32x4_div_ops = { diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index ffe1828a4b7e..6829834a412f 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1349,7 +1349,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) return -ENOMEM; aic32x4->dev = dev; - aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev); + aic32x4->type = (uintptr_t)dev_get_drvdata(dev); dev_set_drvdata(dev, aic32x4); diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 4de5bd9e8cc5..d6101ce73f80 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_REFPOWERUP_120MS 0x07 /* Common mask and enable for all of the dividers */ -#define AIC32X4_DIVEN BIT(7) -#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIVEN BIT(7) +#define AIC32X4_DIV_MASK GENMASK(6, 0) +#define AIC32X4_DIV_MAX 128 /* Clock Limits */ #define AIC32X4_MAX_DOSR_FREQ 6200000 diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 8bf3510a3ea3..a05b553e6472 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -4968,7 +4968,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wcd9335_regmap_config = { .reg_bits = 16, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WCD9335_MAX_REGISTER, .can_multi_write = true, .ranges = wcd9335_ranges, diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index bd0e9fbc12eb..6951120057e5 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1183,7 +1183,7 @@ static const struct regmap_config wcd938x_regmap_config = { .name = "wcd938x_csr", .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wcd938x_defaults, .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults), .max_register = WCD938X_MAX_REGISTER, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 277b8c468c78..9679906c6bd5 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops wm2200_dai_ops = { - .set_fmt = wm2200_set_fmt, - .hw_params = wm2200_hw_params, -}; - static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops wm2200_dai_ops = { + .probe = wm2200_dai_probe, + .set_fmt = wm2200_set_fmt, + .hw_params = wm2200_hw_params, +}; + #define WM2200_RATES SNDRV_PCM_RATE_8000_48000 #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ @@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver wm2200_dai = { .name = "wm2200", - .probe = wm2200_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, @@ -2151,7 +2151,7 @@ static const struct regmap_config wm2200_regmap = { .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults), .volatile_reg = wm2200_volatile_register, .readable_reg = wm2200_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .ranges = wm2200_ranges, .num_ranges = ARRAY_SIZE(wm2200_ranges), }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index a86eacb2a9bb..ff63723928a1 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2400,7 +2400,7 @@ static const struct regmap_config wm5100_regmap = { .num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults), .volatile_reg = wm5100_volatile_register, .readable_reg = wm5100_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const unsigned int wm5100_mic_ctrl_reg[] = { diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 3bdbdf3770b5..4ecf07c7448c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id, #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5102_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5102_dai[] = { { .name = "wm5102-aif1", @@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { .rates = WM5102_RATES, .formats = WM5102_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5102_dai_ops, }, { .name = "wm5102-dsp-trace", diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index ad670300de8d..ac1f2c850346 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id, #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static const struct snd_soc_dai_ops wm5110_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver wm5110_dai[] = { { .name = "wm5110-aif1", @@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-voicectrl", @@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, - .compress_new = snd_soc_new_compress, + .ops = &wm5110_dai_ops, }, { .name = "wm5110-dsp-trace", diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c0ed76d5b65f..6636a70f3895 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -607,7 +607,7 @@ static const struct regmap_config wm8510_regmap = { .reg_defaults = wm8510_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8510_volatile, }; diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 55c72c5ac845..ea87cd3cc0d6 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -437,7 +437,7 @@ static const struct regmap_config wm8523_regmap = { .reg_defaults = wm8523_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8523_volatile_register, }; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 34ae7fe05398..6d22f7d40ec2 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -975,7 +975,7 @@ static const struct regmap_config wm8580_regmap = { .reg_defaults = wm8580_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8580_volatile, }; diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 903a0147d584..916f297164de 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -393,7 +393,7 @@ static const struct regmap_config wm8711_regmap = { .reg_defaults = wm8711_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8711_volatile, }; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 5ea6d8fd10f6..0c943e7d4159 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -236,7 +236,7 @@ static const struct regmap_config wm8728_regmap = { .reg_defaults = wm8728_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d5ab3ba126a6..efc160c75f40 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -642,7 +642,7 @@ const struct regmap_config wm8731_regmap = { .max_register = WM8731_RESET, .volatile_reg = wm8731_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8731_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), }; diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 9f4e372e90ea..0d231c289ef3 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -599,7 +599,7 @@ static const struct regmap_config wm8737_regmap = { .reg_defaults = wm8737_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8737_volatile, }; diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 787156b980a1..19e8fc4062c7 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -543,7 +543,7 @@ static const struct regmap_config wm8741_regmap = { .reg_defaults = wm8741_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 20dc9ff9fea9..2d2feaf95e49 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -735,7 +735,7 @@ static const struct regmap_config wm8750_regmap = { .reg_defaults = wm8750_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5e8a8eb41b2b..b5d8290c37d9 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1507,7 +1507,7 @@ static const struct regmap_config wm8753_regmap = { .max_register = WM8753_ADCTL2, .volatile_reg = wm8753_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8753_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults), }; diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index e03fee8869c3..2469f4f3bea3 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -632,7 +632,7 @@ static const struct regmap_config wm8770_regmap = { .reg_defaults = wm8770_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8770_volatile_reg, }; diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 212224a68006..0673bbd32bab 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -451,7 +451,7 @@ static const struct regmap_config wm8776_regmap = { .reg_defaults = wm8776_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8776_volatile, }; diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 0b234bae480e..bbb4b6e3b41c 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -555,7 +555,7 @@ const struct regmap_config wm8804_regmap_config = { .max_register = WM8804_MAX_REGISTER, .volatile_reg = wm8804_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8804_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), }; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 320ccd92f318..84d06c190411 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1223,7 +1223,7 @@ static const struct regmap_config wm8900_regmap = { .reg_defaults = wm8900_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8900_volatile_register, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 901b65ef8de5..84ae1102ac88 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1902,7 +1902,7 @@ static const struct regmap_config wm8903_regmap = { .volatile_reg = wm8903_volatile_register, .readable_reg = wm8903_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8903_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults), }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index f2baee7c332e..829bf055622a 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2148,7 +2148,7 @@ static const struct regmap_config wm8904_regmap = { .volatile_reg = wm8904_volatile_register, .readable_reg = wm8904_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8904_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults), }; @@ -2202,7 +2202,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) match = of_match_node(wm8904_of_match, i2c->dev.of_node); if (match == NULL) return -EINVAL; - wm8904->devtype = (enum wm8904_type)match->data; + wm8904->devtype = (uintptr_t)match->data; } else { const struct i2c_device_id *id = i2c_match_id(wm8904_i2c_id, i2c); diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 53c27986d216..b9432f8b64e5 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -815,7 +815,7 @@ static const struct regmap_config wm8940_regmap = { .max_register = WM8940_MONOMIX, .reg_defaults = wm8940_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .readable_reg = wm8940_readable_register, .volatile_reg = wm8940_volatile_register, diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 78044f580a67..4f4338326438 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -962,7 +962,7 @@ static const struct regmap_config wm8955_regmap = { .volatile_reg = wm8955_volatile, .writeable_reg = wm8955_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8955_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 366f5d769d6d..0a50180750e8 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg) } } +#define WM8960_NUM_SUPPLIES 5 +static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = { + "DCVDD", + "DBVDD", + "AVDD", + "SPKVDD1", + "SPKVDD2", +}; + struct wm8960_priv { struct clk *mclk; struct regmap *regmap; @@ -137,6 +146,7 @@ struct wm8960_priv { bool is_stream_in_use[2]; struct wm8960_data pdata; ktime_t dsch_start; + struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES]; }; #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) @@ -155,6 +165,7 @@ static const char *wm8960_adc_data_output_sel[] = { "Left Data = Right ADC; Right Data = Left ADC", }; static const char *wm8960_dmonomix[] = {"Stereo", "Mono"}; +static const char *wm8960_dacslope[] = {"Normal", "Sloping"}; static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), @@ -165,6 +176,7 @@ static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), + SOC_ENUM_SINGLE(WM8960_DACCTL2, 1, 2, wm8960_dacslope), }; static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; @@ -307,6 +319,7 @@ SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), SOC_ENUM("DAC Mono Mix", wm8960_enum[7]), +SOC_ENUM("DAC Filter Characteristics", wm8960_enum[8]), }; static const struct snd_kcontrol_new wm8960_lin_boost[] = { @@ -1387,7 +1400,7 @@ static const struct regmap_config wm8960_regmap = { .reg_defaults = wm8960_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8960_volatile, }; @@ -1414,7 +1427,9 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; + unsigned int i; int ret; + u8 val; wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv), GFP_KERNEL); @@ -1425,6 +1440,31 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) if (IS_ERR(wm8960->mclk)) { if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER) return -EPROBE_DEFER; + } else { + ret = clk_get_rate(wm8960->mclk); + if (ret >= 0) { + wm8960->freq_in = ret; + } else { + dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n", + ret); + } + } + + for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++) + wm8960->supplies[i].supply = wm8960_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies), + wm8960->supplies); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; } wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); @@ -1436,6 +1476,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) else if (i2c->dev.of_node) wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + ret = i2c_master_recv(i2c, &val, sizeof(val)); + if (ret >= 0) { + dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n"); + return -EINVAL; + } + ret = wm8960_reset(wm8960->regmap); if (ret != 0) { dev_err(&i2c->dev, "Failed to issue reset\n"); @@ -1487,7 +1533,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c) } static void wm8960_i2c_remove(struct i2c_client *client) -{} +{ + struct wm8960_priv *wm8960 = i2c_get_clientdata(client); + + regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies); +} static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h index 63ba6c03c488..e8ff33b188e9 100644 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -77,9 +77,9 @@ #define WM8960_SYSCLK_DIV_1 (0 << 1) #define WM8960_SYSCLK_DIV_2 (2 << 1) -#define WM8960_SYSCLK_MCLK (0 << 0) +#define WM8960_SYSCLK_AUTO (0 << 0) #define WM8960_SYSCLK_PLL (1 << 0) -#define WM8960_SYSCLK_AUTO (2 << 0) +#define WM8960_SYSCLK_MCLK (2 << 0) #define WM8960_DAC_DIV_1 (0 << 3) #define WM8960_DAC_DIV_1_5 (1 << 3) diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index c076f78d04ce..8f8330efb341 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -904,7 +904,7 @@ static const struct regmap_config wm8961_regmap = { .reg_defaults = wm8961_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8961_volatile, .readable_reg = wm8961_readable, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 68ea15be7330..83ce5dbecc45 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3573,7 +3573,7 @@ static const struct regmap_config wm8962_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8962_reg), .volatile_reg = wm8962_volatile_register, .readable_reg = wm8962_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8962_set_pdata_from_of(struct i2c_client *i2c, diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b22d8f0b59be..e88f323d28b2 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -668,7 +668,7 @@ static const struct regmap_config wm8971_regmap = { .reg_defaults = wm8971_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8971_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 5c829301cf4c..718bfef302cc 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1014,7 +1014,7 @@ static const struct regmap_config wm8978_regmap_config = { .max_register = WM8978_MAX_REGISTER, .volatile_reg = wm8978_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8978_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), }; diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2bd26e2478d9..b26d6a68e8d2 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -995,7 +995,7 @@ static const struct regmap_config wm8983_regmap = { .reg_defaults = wm8983_defaults, .num_reg_defaults = ARRAY_SIZE(wm8983_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WM8983_MAX_REGISTER, .writeable_reg = wm8983_writeable, diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index c0816bcfa294..8606e0752a60 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1125,7 +1125,7 @@ static const struct regmap_config wm8985_regmap = { .max_register = WM8985_MAX_REGISTER, .writeable_reg = wm8985_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8985_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults), }; diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index b440719cca7d..76f214f12ce0 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -832,7 +832,7 @@ static const struct regmap_config wm8988_regmap = { .max_register = WM8988_LPPB, .writeable_reg = wm8988_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8988_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults), }; diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 8cb2ae829699..590318aafaea 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1253,7 +1253,7 @@ static const struct regmap_config wm8991_regmap = { .volatile_reg = wm8991_volatile, .reg_defaults = wm8991_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8991_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index feb997c698e2..5b788f35e5e4 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1608,7 +1608,7 @@ static const struct regmap_config wm8993_regmap = { .volatile_reg = wm8993_volatile, .readable_reg = wm8993_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm8993_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults), }; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index bca3ebe0dac4..a48e904a9740 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = { }; static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = { + .probe = wm8994_aif2_probe, .set_sysclk = wm8994_set_dai_sysclk, .set_fmt = wm8994_set_dai_fmt, .hw_params = wm8994_hw_params, @@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = { .formats = WM8994_FORMATS, .sig_bits = 24, }, - .probe = wm8994_aif2_probe, .ops = &wm8994_aif2_dai_ops, }, { diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 90588614edcc..4ffa1896faab 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2193,7 +2193,7 @@ static const struct regmap_config wm8995_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults), .volatile_reg = wm8995_volatile, .readable_reg = wm8995_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_SPI_MASTER) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 5d0eb0ae0475..df6195778c57 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2610,7 +2610,7 @@ static const struct regmap_config wm8996_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8996_reg), .volatile_reg = wm8996_volatile_register, .readable_reg = wm8996_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8996_probe(struct snd_soc_component *component) diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 34a07db7342a..e7ec799573d3 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1295,7 +1295,7 @@ static const struct regmap_config wm9081_regmap = { .num_reg_defaults = ARRAY_SIZE(wm9081_reg), .volatile_reg = wm9081_volatile_register, .readable_reg = wm9081_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm9081_i2c_probe(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 432729c753dd..50c1cbccfdb9 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -553,7 +553,7 @@ static const struct regmap_config wm9090_regmap = { .volatile_reg = wm9090_volatile, .readable_reg = wm9090_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9090_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults), }; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index d04902ef1d5f..5c6aebe29cf1 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -64,7 +64,7 @@ static const struct regmap_config wm9705_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = regmap_ac97_default_volatile, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index df9b7980706b..e63921de0c37 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -86,7 +86,7 @@ static const struct regmap_config wm9712_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm9712_volatile_reg, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 5d2e54e06e30..64b69316e4c7 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -727,7 +727,7 @@ static const struct regmap_config wm9713_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9713_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults), diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 5a89abfe8784..6fc34f41b175 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -998,7 +998,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); -int wm_adsp_power_up(struct wm_adsp *dsp) +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware) { int ret = 0; char *wmfw_filename = NULL; @@ -1006,11 +1006,13 @@ int wm_adsp_power_up(struct wm_adsp *dsp) char *coeff_filename = NULL; const struct firmware *coeff_firmware = NULL; - ret = wm_adsp_request_firmware_files(dsp, - &wmfw_firmware, &wmfw_filename, - &coeff_firmware, &coeff_filename); - if (ret) - return ret; + if (load_firmware) { + ret = wm_adsp_request_firmware_files(dsp, + &wmfw_firmware, &wmfw_filename, + &coeff_firmware, &coeff_filename); + if (ret) + return ret; + } ret = cs_dsp_power_up(&dsp->cs_dsp, wmfw_firmware, wmfw_filename, @@ -1025,13 +1027,19 @@ int wm_adsp_power_up(struct wm_adsp *dsp) } EXPORT_SYMBOL_GPL(wm_adsp_power_up); +void wm_adsp_power_down(struct wm_adsp *dsp) +{ + cs_dsp_power_down(&dsp->cs_dsp); +} +EXPORT_SYMBOL_GPL(wm_adsp_power_down); + static void wm_adsp_boot_work(struct work_struct *work) { struct wm_adsp *dsp = container_of(work, struct wm_adsp, boot_work); - wm_adsp_power_up(dsp); + wm_adsp_power_up(dsp, true); } int wm_adsp_early_event(struct snd_soc_dapm_widget *w, @@ -1046,7 +1054,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w, queue_work(system_unbound_wq, &dsp->boot_work); break; case SND_SOC_DAPM_PRE_PMD: - cs_dsp_power_down(&dsp->cs_dsp); + wm_adsp_power_down(dsp); break; default: break; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 769904d34a87..067d807a7ca8 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -91,7 +91,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -int wm_adsp_power_up(struct wm_adsp *dsp); +int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware); +void wm_adsp_power_down(struct wm_adsp *dsp); irqreturn_t wm_adsp2_bus_error(int irq, void *data); irqreturn_t wm_halo_bus_error(int irq, void *data); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 97f6873a0a8c..3c025dabaf7a 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -637,7 +637,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wsa881x_regmap_config = { .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wsa881x_defaults, .max_register = WSA881X_SPKR_STATUS3, .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults), diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index e40d583a1ce6..197fae23762f 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -938,7 +938,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg) static struct regmap_config wsa883x_regmap_config = { .reg_bits = 32, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wsa883x_defaults, .max_register = WSA883X_MAX_REGISTER, .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults), diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 97d652f0e84d..0a4698008d64 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -183,7 +183,15 @@ static void i2s_start(struct dw_i2s_dev *dev, { struct i2s_clk_config_data *config = &dev->config; - i2s_write_reg(dev->i2s_base, IER, 1); + u32 reg = IER_IEN; + + if (dev->tdm_slots) { + reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT; + reg |= IER_INTF_TYPE; + reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT; + } + + i2s_write_reg(dev->i2s_base, IER, reg); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) i2s_write_reg(dev->i2s_base, ITER, 1); @@ -233,13 +241,15 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) dev->xfer_resolution); i2s_write_reg(dev->i2s_base, TFCR(ch_reg), dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); + i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN | + dev->tdm_mask << TER_TXSLOT_SHIFT); } else { i2s_write_reg(dev->i2s_base, RCR(ch_reg), dev->xfer_resolution); i2s_write_reg(dev->i2s_base, RFCR(ch_reg), dev->fifo_th - 1); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); + i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN | + dev->tdm_mask << RER_RXSLOT_SHIFT); } } @@ -276,6 +286,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + if (dev->tdm_slots) + config->data_width = 32; + config->chan_nr = params_channels(params); switch (config->chan_nr) { @@ -384,14 +397,67 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ret = -EINVAL; break; } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_DSP_A: + dev->frame_offset = 1; + break; + case SND_SOC_DAIFMT_DSP_B: + dev->frame_offset = 0; + break; + default: + dev_err(dev->dev, "DAI format unsupported"); + return -EINVAL; + } + return ret; } +static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + + if (slot_width != 32) + return -EINVAL; + + if (slots < 0 || slots > 16) + return -EINVAL; + + if (rx_mask != tx_mask) + return -EINVAL; + + if (!rx_mask) + return -EINVAL; + + dev->tdm_slots = slots; + dev->tdm_mask = rx_mask; + + dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1); + dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1); + + return 0; +} + +static int dw_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); + return 0; +} + static const struct snd_soc_dai_ops dw_i2s_dai_ops = { + .probe = dw_i2s_dai_probe, .hw_params = dw_i2s_hw_params, .prepare = dw_i2s_prepare, .trigger = dw_i2s_trigger, .set_fmt = dw_i2s_set_fmt, + .set_tdm_slot = dw_i2s_set_tdm_slot, }; #ifdef CONFIG_PM @@ -623,14 +689,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev, } -static int dw_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); - return 0; -} - static int dw_i2s_probe(struct platform_device *pdev) { const struct i2s_platform_data *pdata = pdev->dev.platform_data; @@ -649,7 +707,6 @@ static int dw_i2s_probe(struct platform_device *pdev) return -ENOMEM; dw_i2s_dai->ops = &dw_i2s_dai_ops; - dw_i2s_dai->probe = dw_i2s_dai_probe; dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->i2s_base)) @@ -726,6 +783,8 @@ static int dw_i2s_probe(struct platform_device *pdev) if (irq >= 0) { ret = dw_pcm_register(pdev); dev->use_pio = true; + dev->l_reg = LRBR_LTHR(0); + dev->r_reg = RRBR_RTHR(0); } else { ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c index 9f25631d43d3..f99262b89008 100644 --- a/sound/soc/dwc/dwc-pcm.c +++ b/sound/soc/dwc/dwc-pcm.c @@ -31,8 +31,8 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \ int i; \ \ for (i = 0; i < dev->fifo_th; i++) { \ - iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \ - iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \ + iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \ + iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \ period_pos++; \ if (++tx_ptr >= runtime->buffer_size) \ tx_ptr = 0; \ @@ -51,8 +51,8 @@ static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \ int i; \ \ for (i = 0; i < dev->fifo_th; i++) { \ - p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \ - p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \ + p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \ + p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \ period_pos++; \ if (++rx_ptr >= runtime->buffer_size) \ rx_ptr = 0; \ diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index ba4e397099be..4ce96bac2f39 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -25,6 +25,13 @@ #define RXFFR 0x014 #define TXFFR 0x018 +/* Enable register fields */ +#define IER_TDM_SLOTS_SHIFT 8 +#define IER_FRAME_OFF_SHIFT 5 +#define IER_FRAME_OFF BIT(5) +#define IER_INTF_TYPE BIT(1) +#define IER_IEN BIT(0) + /* Interrupt status register fields */ #define ISR_TXFO BIT(5) #define ISR_TXFE BIT(4) @@ -46,6 +53,15 @@ #define TFCR(x) (0x40 * x + 0x04C) #define RFF(x) (0x40 * x + 0x050) #define TFF(x) (0x40 * x + 0x054) +#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224) + +/* Receive enable register fields */ +#define RER_RXSLOT_SHIFT 8 +#define RER_RXCHEN BIT(0) + +/* Transmit enable register fields */ +#define TER_TXSLOT_SHIFT 8 +#define TER_TXCHEN BIT(0) /* I2SCOMPRegisters */ #define I2S_COMP_PARAM_2 0x01F0 @@ -105,6 +121,8 @@ struct dw_i2s_dev { u32 ccr; u32 xfer_resolution; u32 fifo_th; + u32 l_reg; + u32 r_reg; /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; @@ -114,6 +132,12 @@ struct dw_i2s_dev { /* data related to PIO transfers */ bool use_pio; + + /* data related to TDM mode */ + u32 tdm_slots; + u32 tdm_mask; + u32 frame_offset; + struct snd_pcm_substream __rcu *tx_substream; struct snd_pcm_substream __rcu *rx_substream; unsigned int (*tx_fn)(struct dw_i2s_dev *dev, diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index adb8a59de2bd..b793263291dc 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { - .startup = fsl_asrc_dai_startup, - .hw_params = fsl_asrc_dai_hw_params, - .hw_free = fsl_asrc_dai_hw_free, - .trigger = fsl_asrc_dai_trigger, -}; - static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) { struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); @@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .probe = fsl_asrc_dai_probe, + .startup = fsl_asrc_dai_startup, + .hw_params = fsl_asrc_dai_hw_params, + .hw_free = fsl_asrc_dai_hw_free, + .trigger = fsl_asrc_dai_trigger, +}; + #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_3LE) static struct snd_soc_dai_driver fsl_asrc_dai = { - .probe = fsl_asrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 46b0c5dcc4a5..fc56f6ade368 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { - .trigger = fsl_aud2htx_trigger, -}; - static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev); @@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { + .probe = fsl_aud2htx_dai_probe, + .trigger = fsl_aud2htx_trigger, +}; + static struct snd_soc_dai_driver fsl_aud2htx_dai = { - .probe = fsl_aud2htx_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 670cbdb361b6..ba62995c909a 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { - .startup = fsl_easrc_startup, - .trigger = fsl_easrc_trigger, - .hw_params = fsl_easrc_hw_params, - .hw_free = fsl_easrc_hw_free, -}; - static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev); @@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_easrc_dai_ops = { + .probe = fsl_easrc_dai_probe, + .startup = fsl_easrc_startup, + .trigger = fsl_easrc_trigger, + .hw_params = fsl_easrc_hw_params, + .hw_free = fsl_easrc_hw_free, +}; + static struct snd_soc_dai_driver fsl_easrc_dai = { - .probe = fsl_easrc_dai_probe, .playback = { .stream_name = "ASRC-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 936f0cd4b06d..d0d8a01da9bd 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops fsl_esai_dai_ops = { - .startup = fsl_esai_startup, - .trigger = fsl_esai_trigger, - .hw_params = fsl_esai_hw_params, - .set_sysclk = fsl_esai_set_dai_sysclk, - .set_fmt = fsl_esai_set_dai_fmt, - .set_tdm_slot = fsl_esai_set_dai_tdm_slot, -}; - static int fsl_esai_dai_probe(struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); @@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_esai_dai_ops = { + .probe = fsl_esai_dai_probe, + .startup = fsl_esai_startup, + .trigger = fsl_esai_trigger, + .hw_params = fsl_esai_hw_params, + .set_sysclk = fsl_esai_set_dai_sysclk, + .set_fmt = fsl_esai_set_dai_fmt, + .set_tdm_slot = fsl_esai_set_dai_tdm_slot, +}; + static struct snd_soc_dai_driver fsl_esai_dai = { - .probe = fsl_esai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 3f08082a55be..0d37edb70261 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause // Copyright 2018 NXP #include <linux/bitfield.h> @@ -56,6 +56,8 @@ struct fsl_micfil { int vad_init_mode; int vad_enabled; int vad_detected; + struct fsl_micfil_verid verid; + struct fsl_micfil_param param; }; struct fsl_micfil_soc_data { @@ -64,6 +66,7 @@ struct fsl_micfil_soc_data { unsigned int dataline; bool imx; bool use_edma; + bool use_verid; u64 formats; }; @@ -90,6 +93,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { .dataline = 0xf, .formats = SNDRV_PCM_FMTBIT_S32_LE, .use_edma = true, + .use_verid = true, }; static const struct of_device_id fsl_micfil_dt_ids[] = { @@ -356,6 +360,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), }; +static int fsl_micfil_use_verid(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (!micfil->soc->use_verid) + return 0; + + ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "VERID: 0x%016X\n", val); + + micfil->verid.version = val & + (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK); + micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT; + micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK; + + ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val); + if (ret < 0) + return ret; + + dev_dbg(dev, "PARAM: 0x%016X\n", val); + + micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >> + MICFIL_PARAM_NUM_HWVAD_SHIFT; + micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD; + micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE; + micfil->param.hwvad = val & MICFIL_PARAM_HWVAD; + micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS; + micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS; + micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER; + micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH; + micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >> + MICFIL_PARAM_FIFO_PTRWID_SHIFT; + micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >> + MICFIL_PARAM_NPAIR_SHIFT; + + return 0; +} + /* The SRES is a self-negated bit which provides the CPU with the * capability to initialize the PDM Interface module through the * slave-bus interface. This bit always reads as zero, and this @@ -717,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } -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, -}; - static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -760,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .probe = fsl_micfil_dai_probe, + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, +}; + static struct snd_soc_dai_driver fsl_micfil_dai = { - .probe = fsl_micfil_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, @@ -825,6 +872,9 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: + case REG_MICFIL_FSYNC_CTRL: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: @@ -849,6 +899,7 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ + case REG_MICFIL_FSYNC_CTRL: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ @@ -873,6 +924,8 @@ 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_VERID: + case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: case REG_MICFIL_VAD0_NDATA: return true; @@ -1031,6 +1084,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid) return IRQ_HANDLED; } +static int fsl_micfil_runtime_suspend(struct device *dev); +static int fsl_micfil_runtime_resume(struct device *dev); + static int fsl_micfil_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1044,7 +1100,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) return -ENOMEM; micfil->pdev = pdev; - strncpy(micfil->name, np->name, sizeof(micfil->name) - 1); + strscpy(micfil->name, np->name, sizeof(micfil->name)); micfil->soc = of_device_get_match_data(&pdev->dev); @@ -1150,6 +1206,25 @@ static int fsl_micfil_probe(struct platform_device *pdev) platform_set_drvdata(pdev, micfil); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_micfil_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; + + /* Get micfil version */ + ret = fsl_micfil_use_verid(&pdev->dev); + if (ret < 0) + dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret); + + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0 && ret != -ENOSYS) + goto err_pm_get_sync; + regcache_cache_only(micfil->regmap, true); /* @@ -1174,6 +1249,9 @@ static int fsl_micfil_probe(struct platform_device *pdev) return ret; +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_micfil_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -1185,7 +1263,7 @@ static void fsl_micfil_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) +static int fsl_micfil_runtime_suspend(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); @@ -1197,7 +1275,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) +static int fsl_micfil_runtime_resume(struct device *dev) { struct fsl_micfil *micfil = dev_get_drvdata(dev); int ret; @@ -1219,26 +1297,12 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused fsl_micfil_suspend(struct device *dev) -{ - pm_runtime_force_suspend(dev); - - return 0; -} - -static int __maybe_unused fsl_micfil_resume(struct device *dev) -{ - pm_runtime_force_resume(dev); - - return 0; -} - static const struct dev_pm_ops fsl_micfil_pm_ops = { SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, fsl_micfil_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend, - fsl_micfil_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver fsl_micfil_driver = { @@ -1254,4 +1318,4 @@ module_platform_driver(fsl_micfil_driver); MODULE_AUTHOR("Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>"); MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index 9237a1c4cb8f..c6b902ba0a53 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * PDM Microphone Interface for the NXP i.MX SoC * Copyright 2018 NXP @@ -24,6 +24,9 @@ #define REG_MICFIL_DC_CTRL 0x64 #define REG_MICFIL_OUT_CTRL 0x74 #define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_FSYNC_CTRL 0x80 +#define REG_MICFIL_VERID 0x84 +#define REG_MICFIL_PARAM 0x88 #define REG_MICFIL_VAD0_CTRL1 0x90 #define REG_MICFIL_VAD0_CTRL2 0x94 #define REG_MICFIL_VAD0_STAT 0x98 @@ -39,6 +42,8 @@ #define MICFIL_CTRL1_DBG BIT(28) #define MICFIL_CTRL1_SRES BIT(27) #define MICFIL_CTRL1_DBGE BIT(26) +#define MICFIL_CTRL1_DECFILS BIT(20) +#define MICFIL_CTRL1_FSYNCEN BIT(16) #define MICFIL_CTRL1_DISEL_DISABLE 0 #define MICFIL_CTRL1_DISEL_DMA 1 @@ -82,6 +87,29 @@ #define MICFIL_DC_CUTOFF_152Hz 2 #define MICFIL_DC_BYPASS 3 +/* MICFIL VERID Register -- REG_MICFIL_VERID */ +#define MICFIL_VERID_MAJOR_SHIFT 24 +#define MICFIL_VERID_MAJOR_MASK GENMASK(31, 24) +#define MICFIL_VERID_MINOR_SHIFT 16 +#define MICFIL_VERID_MINOR_MASK GENMASK(23, 16) +#define MICFIL_VERID_FEATURE_SHIFT 0 +#define MICFIL_VERID_FEATURE_MASK GENMASK(15, 0) + +/* MICFIL PARAM Register -- REG_MICFIL_PARAM */ +#define MICFIL_PARAM_NUM_HWVAD_SHIFT 24 +#define MICFIL_PARAM_NUM_HWVAD_MASK GENMASK(27, 24) +#define MICFIL_PARAM_HWVAD_ZCD BIT(19) +#define MICFIL_PARAM_HWVAD_ENERGY_MODE BIT(17) +#define MICFIL_PARAM_HWVAD BIT(16) +#define MICFIL_PARAM_DC_OUT_BYPASS BIT(11) +#define MICFIL_PARAM_DC_IN_BYPASS BIT(10) +#define MICFIL_PARAM_LOW_POWER BIT(9) +#define MICFIL_PARAM_FIL_OUT_WIDTH BIT(8) +#define MICFIL_PARAM_FIFO_PTRWID_SHIFT 4 +#define MICFIL_PARAM_FIFO_PTRWID_MASK GENMASK(7, 4) +#define MICFIL_PARAM_NPAIR_SHIFT 0 +#define MICFIL_PARAM_NPAIR_MASK GENMASK(3, 0) + /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ #define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24) #define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16) @@ -146,4 +174,40 @@ #define MICFIL_HWVAD_ENVELOPE_MODE 0 #define MICFIL_HWVAD_ENERGY_MODE 1 +/** + * struct fsl_micfil_verid - version id data + * @version: version number + * @feature: feature specification number + */ +struct fsl_micfil_verid { + u32 version; + u32 feature; +}; + +/** + * struct fsl_micfil_param - parameter data + * @hwvad_num: the number of HWVADs + * @hwvad_zcd: HWVAD zero-cross detector is active + * @hwvad_energy_mode: HWVAD energy mode is active + * @hwvad: HWVAD is active + * @dc_out_bypass: points out if the output DC remover is disabled + * @dc_in_bypass: points out if the input DC remover is disabled + * @low_power: low power decimation filter + * @fil_out_width: filter output width + * @fifo_ptrwid: FIFO pointer width + * @npair: number of microphone pairs + */ +struct fsl_micfil_param { + u32 hwvad_num; + bool hwvad_zcd; + bool hwvad_energy_mode; + bool hwvad; + bool dc_out_bypass; + bool dc_in_bypass; + bool low_power; + bool fil_out_width; + u32 fifo_ptrwid; + u32 npair; +}; + #endif /* _FSL_MICFIL_H */ diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 7cbb8e4758cc..56d6b0b039a2 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); unsigned int channels = params_channels(params); unsigned int slot_width; + snd_pcm_format_t format; struct snd_mask f_new; - unsigned int i; if (!channels || channels > nb_ts) { dev_err(qmc_dai->dev, "channels %u not supported\n", @@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai, slot_width = (nb_ts / channels) * 8; snd_mask_none(&f_new); - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { - if (snd_mask_test(f_old, i)) { - if (snd_pcm_format_physical_width(i) <= slot_width) - snd_mask_set(&f_new, i); + pcm_for_each_format(format) { + if (snd_mask_test_format(f_old, format)) { + if (snd_pcm_format_physical_width(format) <= slot_width) + snd_mask_set_format(&f_new, format); } } @@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = { static u64 qmc_audio_formats(u8 nb_ts) { - u64 formats; - unsigned int chan_width; unsigned int format_width; - int i; + unsigned int chan_width; + snd_pcm_format_t format; + u64 formats_mask; if (!nb_ts) return 0; - formats = 0; + formats_mask = 0; chan_width = nb_ts * 8; - for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { + pcm_for_each_format(format) { /* * Support format other than little-endian (ie big-endian or * without endianness such as 8bit formats) */ - if (snd_pcm_format_little_endian(i) == 1) + if (snd_pcm_format_little_endian(format) == 1) continue; /* Support physical width multiple of 8bit */ - format_width = snd_pcm_format_physical_width(i); + format_width = snd_pcm_format_physical_width(format); if (format_width == 0 || format_width % 8) continue; @@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts) if (format_width > chan_width || chan_width % format_width) continue; - formats |= (1ULL << i); + formats_mask |= pcm_format_to_bits(format); } - return formats; + return formats_mask; } static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 15b48b5ea856..abe19a8a7aa7 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -170,12 +170,20 @@ static const struct fsl_rpmsg_soc_data imx8mp_data = { SNDRV_PCM_FMTBIT_S32_LE, }; +static const struct fsl_rpmsg_soc_data imx93_data = { + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, +}; + static const struct of_device_id fsl_rpmsg_ids[] = { { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data}, { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data}, { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data}, { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data}, + { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index f7676d30c82f..1e4020fae05a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { - .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, - .set_sysclk = fsl_sai_set_dai_sysclk, - .set_fmt = fsl_sai_set_dai_fmt, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, - .hw_params = fsl_sai_hw_params, - .hw_free = fsl_sai_hw_free, - .trigger = fsl_sai_trigger, - .startup = fsl_sai_startup, -}; - static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); @@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { + .probe = fsl_sai_dai_probe, + .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, + .set_sysclk = fsl_sai_set_dai_sysclk, + .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .hw_params = fsl_sai_hw_params, + .hw_free = fsl_sai_hw_free, + .trigger = fsl_sai_trigger, + .startup = fsl_sai_startup, +}; + static int fsl_sai_dai_resume(struct snd_soc_component *component) { struct fsl_sai *sai = snd_soc_component_get_drvdata(component); @@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) } static struct snd_soc_dai_driver fsl_sai_dai_template = { - .probe = fsl_sai_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3fd26f2cdd60..78d9dfbe6548 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -514,6 +514,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, int ret; switch (sample_rate) { + case 22050: + rate = SPDIF_TXRATE_22050; + csfs = IEC958_AES3_CON_FS_22050; + break; case 32000: rate = SPDIF_TXRATE_32000; csfs = IEC958_AES3_CON_FS_32000; @@ -761,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { - .startup = fsl_spdif_startup, - .hw_params = fsl_spdif_hw_params, - .trigger = fsl_spdif_trigger, - .shutdown = fsl_spdif_shutdown, -}; - - /* * FSL SPDIF IEC958 controller(mixer) functions * @@ -1279,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_spdif_dai_ops = { + .probe = fsl_spdif_dai_probe, + .startup = fsl_spdif_startup, + .hw_params = fsl_spdif_hw_params, + .trigger = fsl_spdif_trigger, + .shutdown = fsl_spdif_shutdown, +}; + static struct snd_soc_dai_driver fsl_spdif_dai = { - .probe = &fsl_spdif_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 2, @@ -1424,7 +1427,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, struct clk *clk, u64 savesub, enum spdif_txrate index, bool round) { - static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, }; bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); u64 rate_ideal, rate_actual, sub; @@ -1485,7 +1488,7 @@ out: static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index) { - static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, }; struct platform_device *pdev = spdif_priv->pdev; struct device *dev = &pdev->dev; diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index 75b42a692c90..2bc1b10c17d4 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -175,7 +175,8 @@ enum spdif_gainsel { /* SPDIF tx rate */ enum spdif_txrate { - SPDIF_TXRATE_32000 = 0, + SPDIF_TXRATE_22050 = 0, + SPDIF_TXRATE_32000, SPDIF_TXRATE_44100, SPDIF_TXRATE_48000, SPDIF_TXRATE_88200, @@ -191,7 +192,8 @@ enum spdif_txrate { #define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8) -#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ +#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | \ SNDRV_PCM_RATE_88200 | \ diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 53ed3701b0b0..079ac04272b8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { + .probe = fsl_ssi_dai_probe, .startup = fsl_ssi_startup, .shutdown = fsl_ssi_shutdown, .hw_params = fsl_ssi_hw_params, @@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { }; static struct snd_soc_dai_driver fsl_ssi_dai_template = { - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, @@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .symmetric_channels = 1, - .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "CPU AC97 Playback", .channels_min = 2, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 318fe77683f5..fa0a15263c66 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { }, }; -static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { - .prepare = fsl_xcvr_prepare, - .startup = fsl_xcvr_startup, - .shutdown = fsl_xcvr_shutdown, - .trigger = fsl_xcvr_trigger, -}; - static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); @@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = { + .probe = fsl_xcvr_dai_probe, + .prepare = fsl_xcvr_prepare, + .startup = fsl_xcvr_startup, + .shutdown = fsl_xcvr_shutdown, + .trigger = fsl_xcvr_trigger, +}; + static struct snd_soc_dai_driver fsl_xcvr_dai = { - .probe = fsl_xcvr_dai_probe, .ops = &fsl_xcvr_dai_ops, .playback = { .stream_name = "CPU-Playback", diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index d5234ac4b09b..289e47c03d40 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -116,7 +116,6 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = { static struct rpmsg_driver imx_audio_rpmsg_driver = { .drv.name = "imx_audio_rpmsg", - .drv.owner = THIS_MODULE, .id_table = imx_audio_rpmsg_id_table, .probe = imx_audio_rpmsg_probe, .callback = imx_audio_rpmsg_cb, diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 85bd36fb68a2..6f0d031c1d5f 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -37,6 +37,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = { }; static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) { @@ -46,9 +56,11 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) /* Headphone jack detection */ if (gpio_is_valid(data->jack_gpio)) { - ret = snd_soc_card_jack_new(rtd->card, "Headphone", - SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack); + ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; @@ -68,6 +80,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), }; +static const struct snd_kcontrol_new imx_es8328_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; + static int imx_es8328_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -183,6 +200,8 @@ static int imx_es8328_probe(struct platform_device *pdev) data->card.dev = dev; data->card.dapm_widgets = imx_es8328_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + data->card.controls = imx_es8328_controls; + data->card.num_controls = ARRAY_SIZE(imx_es8328_controls); ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) { dev_err(dev, "Unable to parse card name\n"); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 765dad607bf6..d63782b8bdef 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -228,6 +228,10 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + struct snd_pcm_hardware pcm_hardware; struct rpmsg_msg *msg; int ret = 0; int cmd; @@ -255,10 +259,11 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component, info->send_message(msg, info); - imx_rpmsg_pcm_hardware.period_bytes_max = - imx_rpmsg_pcm_hardware.buffer_bytes_max / 2; + pcm_hardware = imx_rpmsg_pcm_hardware; + pcm_hardware.buffer_bytes_max = rpmsg->buffer_size; + pcm_hardware.period_bytes_max = pcm_hardware.buffer_bytes_max / 2; - snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware); + snd_soc_set_runtime_hwparams(substream, &pcm_hardware); ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -597,7 +602,6 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component, if (ret) return ret; - imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size; return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC, pcm->card->dev, rpmsg->buffer_size); } diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c6e0f9132193..13693ef9c242 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); if (dai && (dai->component->driver->pcm_construct || - dai->driver->pcm_new)) + (dai->driver->ops && dai->driver->ops->pcm_new))) return true; return false; @@ -126,7 +126,7 @@ static int graph_parse_node(struct asoc_simple_priv *priv, graph_parse_mclk_fs(top, ep, dai_props); - ret = asoc_graph_parse_dai(ep, dlc, cpu); + ret = asoc_graph_parse_dai(dev, ep, dlc, cpu); if (ret < 0) return ret; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 542c4a114940..98732468a992 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -407,7 +407,7 @@ static int __graph_parse_node(struct asoc_simple_priv *priv, graph_parse_mclk_fs(ep, dai_props); - ret = asoc_graph_parse_dai(ep, dlc, &is_single_links); + ret = asoc_graph_parse_dai(dev, ep, dlc, &is_single_links); if (ret < 0) return ret; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3019626b0592..5b18a4af022f 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -649,7 +649,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo * simple-card.c :: simple_count_noml() */ if (!platforms->of_node) - platforms->of_node = cpus->of_node; + snd_soc_dlc_use_cpu_as_platform(platforms, cpus); } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); @@ -1066,12 +1066,12 @@ static int graph_get_dai_id(struct device_node *ep) return id; } -int asoc_graph_parse_dai(struct device_node *ep, - struct snd_soc_dai_link_component *dlc, - int *is_single_link) +int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, + struct snd_soc_dai_link_component *dlc, int *is_single_link) { struct device_node *node; struct of_phandle_args args = {}; + struct snd_soc_dai *dai; int ret; if (!ep) @@ -1079,6 +1079,20 @@ int asoc_graph_parse_dai(struct device_node *ep, node = of_graph_get_port_parent(ep); + /* + * Try to find from DAI node + */ + args.np = ep; + dai = snd_soc_get_dai_via_args(&args); + if (dai) { + dlc->dai_name = snd_soc_dai_name_get(dai); + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); + if (!dlc->dai_args) + return -ENOMEM; + + goto parse_dai_end; + } + /* Get dai->name */ args.np = node; args.args[0] = graph_get_dai_id(ep); @@ -1109,6 +1123,7 @@ int asoc_graph_parse_dai(struct device_node *ep, return ret; } +parse_dai_end: if (is_single_link) *is_single_link = of_graph_get_endpoint_count(node) == 1; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 0745bf6a09aa..190f11366e84 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -52,11 +52,13 @@ static int asoc_simple_parse_platform(struct device_node *node, return 0; } -static int asoc_simple_parse_dai(struct device_node *node, +static int asoc_simple_parse_dai(struct device *dev, + struct device_node *node, struct snd_soc_dai_link_component *dlc, int *is_single_link) { struct of_phandle_args args; + struct snd_soc_dai *dai; int ret; if (!node) @@ -71,6 +73,19 @@ static int asoc_simple_parse_dai(struct device_node *node, return ret; /* + * Try to find from DAI args + */ + dai = snd_soc_get_dai_via_args(&args); + if (dai) { + dlc->dai_name = snd_soc_dai_name_get(dai); + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); + if (!dlc->dai_args) + return -ENOMEM; + + goto parse_dai_end; + } + + /* * FIXME * * Here, dlc->dai_name is pointer to CPU/Codec DAI name. @@ -93,6 +108,7 @@ static int asoc_simple_parse_dai(struct device_node *node, if (ret < 0) return ret; +parse_dai_end: if (is_single_link) *is_single_link = !args.args_count; @@ -156,7 +172,7 @@ static int simple_parse_node(struct asoc_simple_priv *priv, simple_parse_mclk_fs(top, np, dai_props, prefix); - ret = asoc_simple_parse_dai(np, dlc, cpu); + ret = asoc_simple_parse_dai(dev, np, dlc, cpu); if (ret) return ret; @@ -346,6 +362,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; + struct device_node *add_devs; uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); bool is_top = 0; int ret = 0; @@ -357,6 +374,8 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, is_top = 1; } + add_devs = of_get_child_by_name(top, PREFIX "additional-devs"); + /* loop for all dai-link */ do { struct asoc_simple_data adata; @@ -365,6 +384,12 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, struct device_node *np; int num = of_get_child_count(node); + /* Skip additional-devs node */ + if (node == add_devs) { + node = of_get_next_child(top, node); + continue; + } + /* get codec */ codec = of_get_child_by_name(node, is_top ? PREFIX "codec" : "codec"); @@ -378,12 +403,15 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) + for_each_child_of_node(node, np) { + if (np == add_devs) + continue; simple_parse_convert(dev, np, &adata); + } /* loop for all CPU/Codec node */ for_each_child_of_node(node, np) { - if (plat == np) + if (plat == np || add_devs == np) continue; /* * It is DPCM @@ -426,6 +454,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv, } while (!is_top && node); error: + of_node_put(add_devs); of_node_put(node); return ret; } @@ -463,6 +492,31 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, return ret; } +static void simple_depopulate_aux(void *data) +{ + struct asoc_simple_priv *priv = data; + + of_platform_depopulate(simple_priv_to_dev(priv)); +} + +static int simple_populate_aux(struct asoc_simple_priv *priv) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *node; + int ret; + + node = of_get_child_by_name(dev->of_node, PREFIX "additional-devs"); + if (!node) + return 0; + + ret = of_platform_populate(node, NULL, NULL, dev); + of_node_put(node); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, simple_depopulate_aux, priv); +} + static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) { struct snd_soc_card *card = simple_priv_to_card(priv); @@ -492,6 +546,10 @@ static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) if (ret < 0) return ret; + ret = simple_populate_aux(priv); + if (ret < 0) + return ret; + ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); return ret; diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 27219a9e7d0d..dd7d2a077248 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { + .probe = hi6210_i2s_dai_probe, .trigger = hi6210_i2s_trigger, .hw_params = hi6210_i2s_hw_params, .set_fmt = hi6210_i2s_set_fmt, @@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { }; static const struct snd_soc_dai_driver hi6210_i2s_dai_init = { - .probe = hi6210_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index b7ab8467b5cf..b6b6339c164b 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { - .trigger = img_i2s_in_trigger, - .hw_params = img_i2s_in_hw_params, - .set_fmt = img_i2s_in_set_fmt -}; - static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); @@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .probe = img_i2s_in_dai_probe, + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_in_component = { .name = "img-i2s-in", .legacy_dai_naming = 1, @@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; i2s->dma_data.addr_width = 4; - i2s->dai_driver.probe = img_i2s_in_dai_probe; i2s->dai_driver.capture.channels_min = 2; i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index fe95ddfb8407..41ea5ba52181 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { - .trigger = img_i2s_out_trigger, - .hw_params = img_i2s_out_hw_params, - .set_fmt = img_i2s_out_set_fmt -}; - static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) { struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); @@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .probe = img_i2s_out_dai_probe, + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + static const struct snd_soc_component_driver img_i2s_out_component = { .name = "img-i2s-out", .legacy_dai_naming = 1, @@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->dma_data.addr_width = 4; i2s->dma_data.maxburst = 4; - i2s->dai_driver.probe = img_i2s_out_dai_probe; i2s->dai_driver.playback.channels_min = 2; i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index df1291ee2b3b..815e68a7048c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops img_prl_out_dai_ops = { - .trigger = img_prl_out_trigger, - .hw_params = img_prl_out_hw_params, - .set_fmt = img_prl_out_set_fmt -}; - static int img_prl_out_dai_probe(struct snd_soc_dai *dai) { struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); @@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .probe = img_prl_out_dai_probe, + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + static struct snd_soc_dai_driver img_prl_out_dai = { - .probe = img_prl_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 558062a1804a..9646e9d3f0bc 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, return img_spdif_in_do_clkgen_single(spdif, rate); } -static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { - .trigger = img_spdif_in_trigger, - .hw_params = img_spdif_in_hw_params -}; - static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); @@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .probe = img_spdif_in_dai_probe, + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + static struct snd_soc_dai_driver img_spdif_in_dai = { - .probe = img_spdif_in_dai_probe, .capture = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index b13e128e50d6..dfa72afa946e 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { - .trigger = img_spdif_out_trigger, - .hw_params = img_spdif_out_hw_params -}; - static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) { struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); @@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .probe = img_spdif_out_dai_probe, + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + static struct snd_soc_dai_driver img_spdif_out_dai = { - .probe = img_spdif_out_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index ba4597bdf32e..6f986c7bbc8b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = { }; static const struct snd_soc_dai_ops sst_compr_dai_ops = { + .compress_new = snd_soc_new_compress, .mute_stream = sst_media_digital_mute, }; @@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, { .name = "compress-cpu-dai", - .compress_new = snd_soc_new_compress, .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index a0d29510d2bc..e0357d257c6c 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -16,6 +16,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/firmware.h> +#include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/pm_qos.h> #include <linux/async.h> @@ -174,9 +175,9 @@ int sst_driver_ops(struct intel_sst_drv *sst) { switch (sst->dev_id) { - case SST_MRFLD_PCI_ID: - case SST_BYT_ACPI_ID: - case SST_CHV_ACPI_ID: + case PCI_DEVICE_ID_INTEL_SST_TNG: + case PCI_DEVICE_ID_INTEL_SST_BYT: + case PCI_DEVICE_ID_INTEL_SST_BSW: sst->tstamp = SST_TIME_STAMP_MRFLD; sst->ops = &mrfld_ops; return 0; @@ -221,8 +222,13 @@ static void sst_init_locks(struct intel_sst_drv *ctx) spin_lock_init(&ctx->block_lock); } +/* + * Driver handles PCI IDs in ACPI - sst_acpi_probe() - and we are using only + * device ID part. If real ACPI ID appears, the kstrtouint() returns error, so + * we are fine with using unsigned short as dev_id type. + */ int sst_alloc_drv_context(struct intel_sst_drv **ctx, - struct device *dev, unsigned int dev_id) + struct device *dev, unsigned short dev_id) { *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL); if (!(*ctx)) diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 4d37d39fd8f4..126903e126e4 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -20,9 +20,6 @@ /* driver names */ #define SST_DRV_NAME "intel_sst_driver" -#define SST_MRFLD_PCI_ID 0x119A -#define SST_BYT_ACPI_ID 0x80860F28 -#define SST_CHV_ACPI_ID 0x808622A8 #define SST_SUSPEND_DELAY 2000 #define FW_CONTEXT_MEM (64*1024) @@ -358,7 +355,7 @@ struct sst_fw_save { struct intel_sst_drv { int sst_state; int irq_num; - unsigned int dev_id; + unsigned short dev_id; void __iomem *ddr; void __iomem *shim; void __iomem *mailbox; @@ -523,7 +520,7 @@ int sst_register(struct device *); int sst_unregister(struct device *); int sst_alloc_drv_context(struct intel_sst_drv **ctx, - struct device *dev, unsigned int dev_id); + struct device *dev, unsigned short dev_id); int sst_context_init(struct intel_sst_drv *ctx); void sst_context_cleanup(struct intel_sst_drv *ctx); void sst_configure_runtime_pm(struct intel_sst_drv *ctx); diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 4058b4f80a0c..d1e64c3500be 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -32,7 +32,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) /* map registers */ /* DDR base */ - if (ctx->dev_id == SST_MRFLD_PCI_ID) { + if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) { ctx->ddr_base = pci_resource_start(pci, 0); /* check that the relocated IMR base matches with FW Binary */ ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); @@ -173,7 +173,7 @@ static void intel_sst_remove(struct pci_dev *pci) /* PCI Routines */ static const struct pci_device_id intel_sst_ids[] = { - { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, + { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) }, { 0, } }; diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 862a19ae5429..288221db7323 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, u32 length; int pvt_id, ret = 0; struct sst_block *block = NULL; + u8 bytes_block = bytes->block; dev_dbg(sst_drv_ctx->dev, "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", - bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, + bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id, bytes->pipe_id, bytes->len); if (sst_create_ipc_msg(&msg, true)) @@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, pvt_id = sst_assign_pvt_id(sst_drv_ctx); sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, bytes->task_id, 1, pvt_id); - msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; + msg->mrfld_header.p.header_high.part.res_rqd = bytes_block; length = bytes->len; msg->mrfld_header.p.header_low_payload = length; dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); - if (bytes->block) { + if (bytes_block) { block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); if (block == NULL) { kfree(msg); @@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", msg->mrfld_header.p.header_low_payload); - if (bytes->block) { + if (bytes_block) { ret = sst_wait_timeout(sst_drv_ctx, block); if (ret) { dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); @@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, * copy the reply and send back * we need to update only sz and payload */ - if (bytes->block) { + if (bytes_block) { unsigned char *r = block->data; dev_dbg(sst_drv_ctx->dev, "read back %d bytes", @@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, memcpy(bytes->bytes, r, bytes->len); } } - if (bytes->block) + if (bytes_block) sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 60f8fb0bff95..59a13feec57b 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -136,6 +136,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { .tplg_filename = "max98927-tplg.bin", }, { + .id = "10EC5663", + .drv_name = "avs_rt5663", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt5663-tplg.bin", + }, + { .id = "MX98373", .drv_name = "avs_max98373", .mach_params = { @@ -159,6 +167,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { }, .tplg_filename = "da7219-tplg.bin", }, + { + .id = "ESSX8336", + .drv_name = "avs_es8336", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "es8336-tplg.bin", + }, {}, }; @@ -263,14 +279,14 @@ struct avs_acpi_boards { }; #define AVS_MACH_ENTRY(_id, _mach) \ - { .id = (_id), .machs = (_mach), } + { .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), } /* supported I2S boards per platform */ static const struct avs_acpi_boards i2s_boards[] = { - AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */ - AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */ - AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */ - AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */ + AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), + AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), + AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), + AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), {}, }; diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index e4c230efe8d7..07353d37ecae 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -22,6 +22,16 @@ config SND_SOC_INTEL_AVS_MACH_DMIC Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_ES8336 + tristate "es8336 I2S board" + depends on X86 && I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_ES8316 + help + This adds support for AVS with ES8336 I2S codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_AVS_MACH_HDAUDIO tristate "HD-Audio generic board" select SND_SOC_HDA @@ -115,6 +125,16 @@ config SND_SOC_INTEL_AVS_MACH_RT298 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_RT5663 + tristate "rt5663 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5663 + help + This adds support for ASoC machine driver with RT5663 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_AVS_MACH_RT5682 tristate "rt5682 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index b81343420370..34347bcd1e7d 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -2,6 +2,7 @@ snd-soc-avs-da7219-objs := da7219.o snd-soc-avs-dmic-objs := dmic.o +snd-soc-avs-es8336-objs := es8336.o snd-soc-avs-hdaudio-objs := hdaudio.o snd-soc-avs-i2s-test-objs := i2s_test.o snd-soc-avs-max98927-objs := max98927.o @@ -12,11 +13,13 @@ snd-soc-avs-probe-objs := probe.o snd-soc-avs-rt274-objs := rt274.o snd-soc-avs-rt286-objs := rt286.o snd-soc-avs-rt298-objs := rt298.o +snd-soc-avs-rt5663-objs := rt5663.o snd-soc-avs-rt5682-objs := rt5682.o snd-soc-avs-ssm4567-objs := ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_ES8336) += snd-soc-avs-es8336.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o @@ -27,5 +30,6 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 964a763732ab..85014d98f7e8 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -22,6 +22,7 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), }; @@ -68,6 +70,22 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) @@ -75,7 +93,9 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; struct snd_soc_jack *jack; + int num_pins; int clk_freq; int ret; @@ -91,14 +111,20 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } + num_pins = ARRAY_SIZE(card_headset_pins); + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + jack, pins, num_pins); if (ret) { dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); return ret; diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c new file mode 100644 index 000000000000..0a023f871d93 --- /dev/null +++ b/sound/soc/intel/avs/boards/es8336.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/processor.h> +#include <linux/slab.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <asm/intel-family.h> + +#define ES8336_CODEC_DAI "ES8316 HiFi" + +struct avs_card_drvdata { + struct snd_soc_jack jack; + struct gpio_desc *gpiod; +}; + +static const struct acpi_gpio_params enable_gpio = { 0, 0, true }; + +static const struct acpi_gpio_mapping speaker_gpios[] = { + { "speaker-enable-gpios", &enable_gpio, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, + { } +}; + +static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct avs_card_drvdata *data; + bool speaker_en; + + data = snd_soc_card_get_drvdata(card); + /* As enable_gpio has active_low=true, logic is inverted. */ + speaker_en = !SND_SOC_DAPM_EVENT_ON(event); + + gpiod_set_value_cansleep(data->gpiod, speaker_en); + return 0; +} + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + avs_es8336_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" widget. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, + + /* Mic route map */ + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_card *card = runtime->card; + struct snd_soc_jack_pin *pins; + struct avs_card_drvdata *data; + struct gpio_desc *gpiod; + int num_pins, ret; + + data = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, + &data->jack, pins, num_pins); + if (ret) + return ret; + + ret = devm_acpi_dev_add_driver_gpios(codec_dai->dev, speaker_gpios); + if (ret) + dev_warn(codec_dai->dev, "Unable to add GPIO mapping table\n"); + + gpiod = gpiod_get_optional(codec_dai->dev, "speaker-enable", GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) + return dev_err_probe(codec_dai->dev, PTR_ERR(gpiod), "Get gpiod failed: %ld\n", + PTR_ERR(gpiod)); + + data->gpiod = gpiod; + snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(component, &data->jack, NULL); + + card->dapm.idle_bias_off = true; + + return 0; +} + +static void avs_es8336_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct avs_card_drvdata *data = snd_soc_card_get_drvdata(runtime->card); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + + snd_soc_component_set_jack(codec_dai->component, NULL, NULL); + gpiod_put(data->gpiod); +} + +static int avs_es8336_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); + int clk_freq; + int ret; + + switch (boot_cpu_data.x86_model) { + case INTEL_FAM6_KABYLAKE_L: + case INTEL_FAM6_KABYLAKE: + clk_freq = 24000000; + break; + default: + clk_freq = 19200000; + break; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 1, clk_freq, SND_SOC_CLOCK_OUT); + if (ret < 0) + dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_es8336_ops = { + .hw_params = avs_es8336_hw_params, +}; + +static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_3LE); + + return 0; +} +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-ESSX8336:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, ES8336_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->init = avs_es8336_codec_init; + dl->exit = avs_es8336_codec_exit; + dl->be_hw_params_fixup = avs_es8336_be_fixup; + dl->ops = &avs_es8336_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + dl->dpcm_capture = 1; + dl->dpcm_playback = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI); + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI); + struct avs_card_drvdata *data = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, &data->jack, NULL); +} + +static int avs_es8336_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct avs_card_drvdata *data; + struct snd_soc_card *card; + struct device *dev = &pdev->dev; + const char *pname; + int ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!data || !card) + return -ENOMEM; + + card->name = "avs_es8336"; + card->dev = dev; + card->owner = THIS_MODULE; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + snd_soc_card_set_drvdata(card, data); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_es8336_driver = { + .probe = avs_es8336_probe, + .driver = { + .name = "avs_es8336", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_es8336_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_es8336"); diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c new file mode 100644 index 000000000000..770b36d05bf4 --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022-2023 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/clk.h> +#include <linux/input.h> +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt5663.h" + +#define RT5663_CODEC_DAI "rt5663-aif" + +struct rt5663_private { + struct snd_soc_jack jack; +}; + +static const struct snd_kcontrol_new card_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + /* HP jack connectors */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* Mic jacks */ + { "IN1P", NULL, "Headset Mic" }, + { "IN1N", NULL, "Headset Mic" }, +}; + +static struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct rt5663_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; + + jack = &priv->jack; + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, + pins, num_pins); + if (ret) + return ret; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL); + + return 0; +} + +static void avs_rt5663_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, NULL, NULL); +} + +static int +avs_rt5663_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate, *channels; + struct snd_mask *fmt; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSPN to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ + rt5663_sel_asrc_clk_src(codec_dai->component, + RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, + RT5663_CLK_SEL_I2S1_ASRC); + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); + + return ret; +} + +static const struct snd_soc_ops avs_rt5663_ops = { + .hw_params = avs_rt5663_hw_params, +}; + + +static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = platform_name; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5663:00"); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5663_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->init = avs_rt5663_codec_init; + dl->exit = avs_rt5663_codec_exit; + 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; + + return 0; +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI); + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI); + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, jack, NULL); +} + +static int avs_rt5663_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct rt5663_private *priv; + struct device *dev = &pdev->dev; + const char *pname; + int ssp_port, ret; + + mach = dev_get_platdata(dev); + pname = mach->mach_params.platform; + ssp_port = __ffs(mach->mach_params.i2s_link_mask); + + ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!priv || !card) + return -ENOMEM; + + card->name = "avs_rt5663"; + card->dev = dev; + card->owner = THIS_MODULE; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->controls = card_controls; + card->num_controls = ARRAY_SIZE(card_controls); + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + snd_soc_card_set_drvdata(card, priv); + + ret = snd_soc_fixup_dai_links_platform_name(card, pname); + if (ret) + return ret; + + return devm_snd_soc_register_card(dev, card); +} + +static struct platform_driver avs_rt5663_driver = { + .probe = avs_rt5663_probe, + .driver = { + .name = "avs_rt5663", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(avs_rt5663_driver); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:avs_rt5663"); diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 7142a67900bf..b93468ae0977 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -79,14 +79,31 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "IN1P", NULL, "Headset Mic" }, }; +static struct snd_soc_jack_pin card_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; - struct snd_soc_jack *jack; struct snd_soc_card *card = runtime->card; - int ret; + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_jack_pins); + + pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; /* Need to enable ASRC function for 24MHz mclk rate */ if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) && @@ -95,12 +112,10 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC); } - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack); + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, + pins, num_pins); if (ret) { dev_err(card->dev, "Headset Jack creation failed: %d\n", ret); return ret; @@ -130,39 +145,36 @@ avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_para { struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); - int clk_id, clk_freq; - int pll_out, ret; + int pll_source, freq_in, freq_out; + int ret; if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) { - clk_id = RT5682_PLL1_S_MCLK; + pll_source = RT5682_PLL1_S_MCLK; if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ) - clk_freq = 24000000; + freq_in = 24000000; else - clk_freq = 19200000; + freq_in = 19200000; } else { - clk_id = RT5682_PLL1_S_BCLK1; - clk_freq = params_rate(params) * 50; + pll_source = RT5682_PLL1_S_BCLK1; + freq_in = params_rate(params) * 50; } - pll_out = params_rate(params) * 512; + freq_out = params_rate(params) * 512; - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, pll_source, freq_in, freq_out); if (ret < 0) - dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret); + dev_err(runtime->dev, "Set PLL failed: %d\n", ret); - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, freq_out, SND_SOC_CLOCK_IN); if (ret < 0) - dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + dev_err(runtime->dev, "Set sysclk failed: %d\n", ret); - /* slot_width should equal or large than data length, set them be the same */ + /* slot_width should be equal or larger than data length. */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params)); - if (ret < 0) { - dev_err(runtime->dev, "set TDM slot err:%d\n", ret); - return ret; - } + if (ret < 0) + dev_err(runtime->dev, "Set TDM slot failed: %d\n", ret); - return 0; + return ret; } static const struct snd_soc_ops avs_rt5682_ops = { @@ -220,6 +232,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt5682_codec_init; dl->exit = avs_rt5682_codec_exit; dl->be_hw_params_fixup = avs_rt5682_be_fixup; diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 637501850728..859b217fc761 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -745,14 +745,14 @@ static const struct avs_spec apl_desc = { }; static const struct pci_device_id avs_ids[] = { - { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */ - { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */ - { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */ - { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */ - { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */ - { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */ - { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */ - { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */ + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) }, { 0 } }; MODULE_DEVICE_TABLE(pci, avs_ids); diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 275928281c6c..4cab8c6c4576 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr return count; } -static const struct snd_soc_cdai_ops avs_probe_dai_ops = { +static const struct snd_soc_cdai_ops avs_probe_cdai_ops = { .startup = avs_probe_compr_open, .shutdown = avs_probe_compr_free, .set_params = avs_probe_compr_set_params, @@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = { .pointer = avs_probe_compr_pointer, }; +static const struct snd_soc_dai_ops avs_probe_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static const struct snd_compress_ops avs_probe_compress_ops = { .copy = avs_probe_compr_copy, }; @@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = { static struct snd_soc_dai_driver probe_cpu_dais[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, - .cops = &avs_probe_dai_ops, + .cops = &avs_probe_cdai_ops, + .ops = &avs_probe_dai_ops, .capture = { .stream_name = "Probe Extraction", .channels_min = 1, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index cdb4ec500261..45d0eb2a8e71 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1388,12 +1388,12 @@ static int avs_route_load(struct snd_soc_component *comp, int index, port = __ffs(mach->mach_params.i2s_link_mask); snprintf(buf, len, route->source, port); - strncpy((char *)route->source, buf, len); + strscpy((char *)route->source, buf, len); snprintf(buf, len, route->sink, port); - strncpy((char *)route->sink, buf, len); + strscpy((char *)route->sink, buf, len); if (route->control) { snprintf(buf, len, route->control, port); - strncpy((char *)route->control, buf, len); + strscpy((char *)route->control, buf, len); } } diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f472f603ab75..0ae6eecc8851 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -475,7 +475,7 @@ endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH - tristate "SOF with rt5682 codec in I2S Mode" + tristate "SOF with rt5650/rt5682 codec in I2S Mode" depends on I2C && ACPI depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ @@ -485,6 +485,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_RT1011 select SND_SOC_RT1015 select SND_SOC_RT1015P + select SND_SOC_RT5645 select SND_SOC_RT5682_I2C select SND_SOC_RT5682S select SND_SOC_DMIC @@ -494,7 +495,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_INTEL_SOF_REALTEK_COMMON help This adds support for ASoC machine driver for SOF platforms - with rt5682 codec. + with rt5650 or rt5682 codec. Say Y if you have such a device. If unsure select "N". @@ -670,14 +671,15 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT711_SDCA_SDW select SND_SOC_RT712_SDCA_SDW select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT1316_SDW select SND_SOC_RT1318_SDW - select SND_SOC_RT715_SDW - select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW + select SND_SOC_CS35L56_SDW select SND_SOC_DMIC select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_SOF_MAXIM_COMMON diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 931415d9cf6f..a570b5b40f22 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -42,7 +42,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ sof_sdw_rt712_sdca.o sof_sdw_rt715.o \ sof_sdw_rt715_sdca.o sof_sdw_dmic.o \ - sof_sdw_cs42l42.o \ + sof_sdw_cs42l42.o sof_sdw_cs_amp.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index b7687a93a923..036579331d8f 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -187,6 +187,9 @@ static int card_suspend_pre(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); } @@ -194,6 +197,9 @@ static int card_resume_post(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1"); + if (!codec_dai) + return 0; + return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL); } diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c593995facaa..cbfff466c5c8 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -90,6 +90,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new broxton_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_kcontrol_new max98357a_controls[] = { @@ -104,6 +105,7 @@ static const struct snd_kcontrol_new max98390_controls[] = { static const struct snd_soc_dapm_widget broxton_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -150,6 +152,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static const struct snd_soc_dapm_route max98357a_routes[] = { @@ -194,6 +197,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index f2382d4cb76f..5c9e06ed1a53 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -144,6 +145,7 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = { {"Headset Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"}, + {"Line Out", NULL, "Platform Clock"}, {"Speaker", NULL, "SPKOUTLP"}, {"Speaker", NULL, "SPKOUTLN"}, @@ -177,6 +179,7 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static struct snd_soc_jack_pin byt_wm5102_pins[] = { @@ -188,6 +191,10 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 18365ce6bcba..97149513076f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -83,12 +83,14 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -107,6 +109,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -147,6 +153,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index ad4223fee0c5..a1f8234c77bd 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -102,6 +102,7 @@ static const struct snd_kcontrol_new kabylake_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget kabylake_widgets[] = { @@ -109,6 +110,7 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), @@ -127,6 +129,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_MICROPHONE, + }, }; static const struct snd_soc_dapm_route kabylake_map[] = { @@ -182,6 +188,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, }; static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index 740aa11cb019..bbd47e7e4343 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -65,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), }; @@ -72,6 +73,7 @@ static const struct snd_kcontrol_new controls[] = { static const struct snd_kcontrol_new m98360a_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Spk"), }; @@ -79,6 +81,7 @@ static const struct snd_kcontrol_new m98360a_controls[] = { static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), @@ -98,6 +101,7 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, @@ -110,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static const struct snd_soc_dapm_widget max98360a_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Spk", NULL), @@ -128,6 +133,7 @@ static const struct snd_soc_dapm_route max98360a_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, + { "Line Out", NULL, "Platform Clock" }, {"Spk", NULL, "Speaker"}, @@ -144,6 +150,10 @@ static struct snd_soc_jack_pin jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_jack headset; diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index d6c38d8ea2ff..f8a3e8a91761 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -798,6 +798,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "rpl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 112e89951da0..628b6d5d3ee4 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -4,6 +4,7 @@ #include <linux/module.h> #include <linux/string.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> #include <sound/soc-dai.h> @@ -11,6 +12,18 @@ #include <uapi/sound/asound.h> #include "sof_maxim_common.h" +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + #define MAX_98373_PIN_NAME 16 const struct snd_soc_dapm_route max_98373_dapm_routes[] = { @@ -168,17 +181,6 @@ static struct snd_soc_codec_conf max_98390_codec_conf[] = { .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), .name_prefix = "Left", }, -}; - -static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), - .name_prefix = "Left", - }, { .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), .name_prefix = "Tweeter Right", @@ -189,19 +191,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { }, }; -struct snd_soc_dai_link_component max_98390_components[] = { - { - .name = MAX_98390_DEV0_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, - { - .name = MAX_98390_DEV1_NAME, - .dai_name = MAX_98390_CODEC_DAI, - }, -}; -EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); - -struct snd_soc_dai_link_component max_98390_4spk_components[] = { +static struct snd_soc_dai_link_component max_98390_components[] = { { .name = MAX_98390_DEV0_NAME, .dai_name = MAX_98390_CODEC_DAI, @@ -219,62 +209,56 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = { .dai_name = MAX_98390_CODEC_DAI, }, }; -EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +static const struct { + unsigned int tx; + unsigned int rx; +} max_98390_tdm_mask[] = { + {.tx = 0x01, .rx = 0x3}, + {.tx = 0x02, .rx = 0x3}, + {.tx = 0x04, .rx = 0x3}, + {.tx = 0x08, .rx = 0x3}, +}; static int max_98390_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; - int i; + int i, ret; for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (i >= ARRAY_SIZE(max_98390_4spk_components)) { + if (i >= ARRAY_SIZE(max_98390_tdm_mask)) { dev_err(codec_dai->dev, "invalid codec index %d\n", i); return -ENODEV; } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { - /* DEV0 tdm slot configuration Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { - /* DEV1 tdm slot configuration Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); - } - - if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { - /* DEVi2 tdm slot configuration Tweeter Right */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { - /* DEV3 tdm slot configuration Tweeter Left */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx, + max_98390_tdm_mask[i].rx, 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; } } return 0; } -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +static int max_98390_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); int ret; - /* add regular speakers dapm route */ - ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, - ARRAY_SIZE(max_98390_dapm_routes)); - if (ret) { - dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); - return ret; - } - - /* add widgets/controls/dapm for tweeter speakers */ - if (acpi_dev_present("MX98390", "3", -1)) { + switch (num_codecs) { + case 4: + /* add widgets/controls/dapm for tweeter speakers */ ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, ARRAY_SIZE(max_98390_tt_dapm_widgets)); - if (ret) { - dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", + ret); /* Don't need to add routes if widget addition failed */ return ret; } @@ -282,33 +266,79 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, ARRAY_SIZE(max_98390_tt_kcontrols)); if (ret) { - dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); + dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n", + ret); return ret; } ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, ARRAY_SIZE(max_98390_tt_dapm_routes)); - if (ret) - dev_err(rtd->dev, - "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); + if (ret) { + dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", + ret); + return ret; + } + + fallthrough; + case 2: + /* add regular speakers dapm route */ + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ARRAY_SIZE(max_98390_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "invalid codec number %d\n", num_codecs); + return -EINVAL; } + return ret; } -EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); -const struct snd_soc_ops max_98390_ops = { +static const struct snd_soc_ops max_98390_ops = { .hw_params = max_98390_hw_params, }; -EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + link->codecs = max_98390_components; + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; + } + + link->init = max_98390_init; + link->ops = &max_98390_ops; +} +EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) { - if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { - card->codec_conf = max_98390_4spk_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); - } else { - card->codec_conf = max_98390_codec_conf; - card->num_configs = ARRAY_SIZE(max_98390_codec_conf); + unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); + + card->codec_conf = max_98390_codec_conf; + + switch (num_codecs) { + case 2: + case 4: + card->num_configs = num_codecs; + break; + default: + dev_err(dev, "invalid codec number %d for %s\n", num_codecs, + MAX_98390_ACPI_HID); + break; } } EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 7a8c53049e4d..a095b47b856b 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -27,18 +27,15 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); /* * Maxim MAX98390 */ -#define MAX_98390_CODEC_DAI "max98390-aif1" -#define MAX_98390_DEV0_NAME "i2c-MX98390:00" -#define MAX_98390_DEV1_NAME "i2c-MX98390:01" -#define MAX_98390_DEV2_NAME "i2c-MX98390:02" -#define MAX_98390_DEV3_NAME "i2c-MX98390:03" - -extern struct snd_soc_dai_link_component max_98390_components[2]; -extern struct snd_soc_dai_link_component max_98390_4spk_components[4]; -extern const struct snd_soc_ops max_98390_ops; - -void max_98390_set_codec_conf(struct snd_soc_card *card, int ch); -int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd); +#define MAX_98390_ACPI_HID "MX98390" +#define MAX_98390_CODEC_DAI "max98390-aif1" +#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00" +#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01" +#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02" +#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03" + +void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card); /* * Maxim MAX98357A/MAX98360A diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 4fc6e1c6aef3..46b7ecf6f9f1 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -684,6 +684,16 @@ static const struct platform_device_id board_ids[] = { SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .name = "rpl_nau8318_8825", + .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_NAU8318_SPEAKER_AMP_PRESENT | + SOF_NAU8825_SSP_AMP(1) | + SOF_NAU8825_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 7c034d671cf3..fae091b9b55c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -22,6 +22,7 @@ #include <sound/soc-acpi.h> #include "../../codecs/rt5682.h" #include "../../codecs/rt5682s.h" +#include "../../codecs/rt5645.h" #include "../../codecs/hdac_hdmi.h" #include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" @@ -58,9 +59,14 @@ #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23) #define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24) -#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25) #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26) +#define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27) +/* HDMI capture*/ +#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27 +#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) +#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ + (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -197,23 +203,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { .callback = sof_rt5682_quirk_cb, .matches = { DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), - DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_SPEAKER_AMP_PRESENT | - SOF_MAX98390_SPEAKER_AMP_PRESENT | - SOF_MAX98390_TWEETER_SPEAKER_PRESENT | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - - }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"), DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | @@ -305,6 +294,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; struct snd_soc_jack *jack; + int extra_jack_data; int ret; /* need to enable ASRC function for 24MHz mclk rate */ @@ -315,7 +305,16 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) RT5682S_DA_STEREO1_FILTER | RT5682S_AD_STEREO1_FILTER, RT5682S_CLK_SEL_I2S1_ASRC); - else + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + rt5645_sel_asrc_clk_src(component, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + rt5645_sel_asrc_clk_src(component, + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER, + RT5645_CLK_SEL_I2S2_ASRC); + } else rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | RT5682_AD_STEREO1_FILTER, @@ -365,7 +364,12 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, jack, NULL); + + if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0; + ret = snd_soc_component_set_jack(component, jack, &extra_jack_data); + } else + ret = snd_soc_component_set_jack(component, jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); @@ -402,6 +406,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) pll_source = RT5682S_PLL_S_MCLK; + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) + pll_source = RT5645_PLL1_S_MCLK; else pll_source = RT5682_PLL1_S_MCLK; @@ -422,6 +428,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, } else { if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) pll_source = RT5682S_PLL_S_BCLK1; + else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) + pll_source = RT5645_PLL1_S_BCLK1; else pll_source = RT5682_PLL1_S_BCLK1; @@ -431,6 +439,9 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { pll_id = RT5682S_PLL2; clk_id = RT5682S_SCLK_S_PLL2; + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + pll_id = 0; /* not used in codec driver */ + clk_id = RT5645_SCLK_S_PLL1; } else { pll_id = RT5682_PLL1; clk_id = RT5682_SCLK_S_PLL1; @@ -559,11 +570,30 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; +static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "SPOL" }, + { "Right Spk", NULL, "SPOR" }, +}; + static const struct snd_soc_dapm_route dmic_map[] = { /* digital mics */ {"DMic", NULL, "SoC DMIC"}, }; +static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes, + ARRAY_SIZE(rt5650_spk_dapm_routes)); + if (ret) + dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret); + + return ret; +} + static int dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -614,6 +644,17 @@ static struct snd_soc_dai_link_component rt5682s_component[] = { } }; +static struct snd_soc_dai_link_component rt5650_components[] = { + { + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif1", + }, + { + .name = "i2c-10EC5650:00", + .dai_name = "rt5645-aif2", + } +}; + static struct snd_soc_dai_link_component dmic_component[] = { { .name = "dmic-codec", @@ -634,6 +675,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i, id = 0; + int hdmi_id_offset = 0; links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -652,6 +694,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) { links[id].codecs = rt5682s_component; links[id].num_codecs = ARRAY_SIZE(rt5682s_component); + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + links[id].codecs = &rt5650_components[0]; + links[id].num_codecs = 1; } else { links[id].codecs = rt5682_component; links[id].num_codecs = ARRAY_SIZE(rt5682_component); @@ -793,17 +838,12 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, sof_rt1011_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & - SOF_MAX98390_TWEETER_SPEAKER_PRESENT) { - links[id].codecs = max_98390_4spk_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components); - } else { - links[id].codecs = max_98390_components; - links[id].num_codecs = ARRAY_SIZE(max_98390_components); - } - links[id].init = max_98390_spk_codec_init; - links[id].ops = &max_98390_ops; - + max_98390_dai_link(dev, &links[id]); + } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) { + links[id].codecs = &rt5650_components[1]; + links[id].num_codecs = 1; + links[id].init = rt5650_spk_init; + links[id].ops = &sof_rt5682_ops; } else { max_98357a_dai_link(&links[id]); } @@ -857,6 +897,34 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_cpus = 1; } + /* HDMI-In SSP */ + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) { + unsigned long hdmi_in_ssp = (sof_rt5682_quirk & + SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + int port = 0; + + for_each_set_bit(port, &hdmi_in_ssp, 32) { + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + return NULL; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); + if (!links[id].name) + return NULL; + links[id].id = id + hdmi_id_offset; + links[id].codecs = &asoc_dummy_dlc; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; + id++; + } + } + return links; devm_err: return NULL; @@ -890,6 +958,12 @@ static int sof_audio_probe(struct platform_device *pdev) /* Detect the headset codec variant */ if (acpi_dev_present("RTL5682", NULL, -1)) sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT; + else if (acpi_dev_present("10EC5650", NULL, -1)) { + sof_rt5682_quirk |= SOF_RT5650_HEADPHONE_CODEC_PRESENT; + + sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650", + GFP_KERNEL); + } if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; @@ -951,17 +1025,17 @@ static int sof_audio_probe(struct platform_device *pdev) else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) sof_rt1015p_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) { - if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT) - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_4spk_components)); - else - max_98390_set_codec_conf(&sof_audio_card_rt5682, - ARRAY_SIZE(max_98390_components)); + max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); } if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) sof_audio_card_rt5682.num_links++; + if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) + sof_audio_card_rt5682.num_links += + hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num, ctx->idisp_codec); if (!dai_links) @@ -1129,6 +1203,22 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_BT_OFFLOAD_PRESENT), }, { + .name = "adl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(1) | + SOF_RT5682_NUM_HDMIDEV(3) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + }, + { + .name = "rpl_mx98357_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, + { .name = "rpl_mx98360_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0) | @@ -1178,6 +1268,14 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(0) | SOF_RT5682_NUM_HDMIDEV(3)), }, + { + .name = "jsl_rt5650", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, { } }; 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 dbee8c98ff01..5a1c750e6ae6 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -311,6 +311,16 @@ 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, "0AFE") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2 | + SOF_SDW_FOUR_SPK), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | @@ -467,7 +477,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC), + .driver_data = (void *)(SOF_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, /* LunarLake devices */ { @@ -476,7 +488,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), }, - .driver_data = (void *)(RT711_JD2_100K), + .driver_data = (void *)(RT711_JD2), }, {} }; @@ -511,9 +523,8 @@ int sdw_prepare(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -531,9 +542,8 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -555,7 +565,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd) } if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret); + dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); return ret; } @@ -619,9 +629,8 @@ int sdw_hw_free(struct snd_pcm_substream *substream) dai = asoc_rtd_to_cpu(rtd, 0); sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return PTR_ERR(sdw_stream); } @@ -895,6 +904,19 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_num = 1, }, { + .part_id = 0x3556, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs35l56-sdw1", + .dai_type = SOF_SDW_DAI_TYPE_AMP, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, + .init = sof_sdw_cs_amp_init, + }, + }, + .dai_num = 1, + }, + { .part_id = 0x4242, .dais = { { @@ -940,10 +962,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .version_id = 0, .dais = { { - .direction = {true, false}, + .direction = {true, true}, .dai_name = "sdw-mockup-aif1", .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = NULL, }, }, @@ -965,7 +987,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { }, }; -static inline int find_codec_info_part(u64 adr) +static inline int find_codec_info_part(const u64 adr) { unsigned int part_id, sdw_version; int i; @@ -994,14 +1016,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) return -EINVAL; for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, - ACPI_ID_LEN)) - break; - - if (i == ARRAY_SIZE(codec_info_list)) - return -EINVAL; + if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) + return i; - return i; + return -EINVAL; } /* @@ -1009,10 +1027,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id) * Since some sdw slaves may be aggregated, the CPU DAI number * may be larger than the number of BE dailinks. */ -static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links, - int *sdw_be_num, int *sdw_cpu_dai_num) +static int get_dailink_info(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num) { - const struct snd_soc_acpi_link_adr *link; bool group_visited[SDW_MAX_GROUPS]; bool no_aggregation; int i; @@ -1022,27 +1040,45 @@ static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_li *sdw_cpu_dai_num = 0; *sdw_be_num = 0; - if (!links) + if (!adr_link) return -EINVAL; for (i = 0; i < SDW_MAX_GROUPS; i++) group_visited[i] = false; - for (link = links; link->num_adr; link++) { + for (; adr_link->num_adr; adr_link++) { const struct snd_soc_acpi_endpoint *endpoint; struct sof_sdw_codec_info *codec_info; int codec_index; int stream; u64 adr; - for (i = 0; i < link->num_adr; i++) { - adr = link->adr_d[i].adr; + /* make sure the link mask has a single bit set */ + if (!is_power_of_2(adr_link->mask)) + return -EINVAL; + + for (i = 0; i < adr_link->num_adr; i++) { + adr = adr_link->adr_d[i].adr; codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; + codec_info = &codec_info_list[codec_index]; - endpoint = link->adr_d[i].endpoints; + *codecs_num += codec_info->dai_num; + + if (!adr_link->adr_d[i].name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_link->adr_d[i].adr); + return -EINVAL; + } + + endpoint = adr_link->adr_d[i].endpoints; + if (endpoint->aggregated && !endpoint->group_id) { + dev_err(dev, "invalid group id on link %x\n", + adr_link->mask); + return -EINVAL; + } for (j = 0; j < codec_info->dai_num; j++) { /* count DAI number for playback and capture */ @@ -1090,17 +1126,16 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links dai_links->ops = ops; } -static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, +static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int sdw_version, unsigned int mfg_id, unsigned int part_id, unsigned int class_id, - int index_in_link - ) + int index_in_link) { int i; - for (i = 0; i < link->num_adr; i++) { + for (i = 0; i < adr_link->num_adr; i++) { unsigned int sdw1_version, mfg1_id, part1_id, class1_id; u64 adr; @@ -1108,7 +1143,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, if (i == index_in_link) continue; - adr = link->adr_d[i].adr; + adr = adr_link->adr_d[i].adr; sdw1_version = SDW_VERSION(adr); mfg1_id = SDW_MFG_ID(adr); @@ -1125,83 +1160,50 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link, return true; } -static int create_codec_dai_name(struct device *dev, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link_component *codec, - int offset, - struct snd_soc_codec_conf *codec_conf, - int codec_count, - int *codec_conf_index, - int adr_index, - int dai_index) +static int fill_sdw_codec_dlc(struct device *dev, + const struct snd_soc_acpi_link_adr *adr_link, + struct snd_soc_dai_link_component *codec, + int adr_index, int dai_index) { - int _codec_index = -1; - int i; - - /* sanity check */ - if (*codec_conf_index + link->num_adr - adr_index > codec_count) { - dev_err(dev, "codec_conf: out-of-bounds access requested\n"); - return -EINVAL; - } - - for (i = adr_index; i < link->num_adr; i++) { - unsigned int sdw_version, unique_id, mfg_id; - unsigned int link_id, part_id, class_id; - int codec_index, comp_index; - char *codec_str; - u64 adr; - - adr = link->adr_d[i].adr; - - sdw_version = SDW_VERSION(adr); - link_id = SDW_DISCO_LINK_ID(adr); - unique_id = SDW_UNIQUE_ID(adr); - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - class_id = SDW_CLASS_ID(adr); - - comp_index = i - adr_index + offset; - if (is_unique_device(link, sdw_version, mfg_id, part_id, - class_id, i)) { - codec_str = "sdw:%01x:%04x:%04x:%02x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id); - } else { - codec_str = "sdw:%01x:%04x:%04x:%02x:%01x"; - codec[comp_index].name = - devm_kasprintf(dev, GFP_KERNEL, codec_str, - link_id, mfg_id, part_id, - class_id, unique_id); - } - - if (!codec[comp_index].name) - return -ENOMEM; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - if (_codec_index != -1 && codec_index != _codec_index) { - dev_dbg(dev, "Different devices on the same sdw link\n"); - break; - } - _codec_index = codec_index; + unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; + u64 adr = adr_link->adr_d[adr_index].adr; + int codec_index; - codec[comp_index].dai_name = - codec_info_list[codec_index].dais[dai_index].dai_name; + codec_index = find_codec_info_part(adr); + if (codec_index < 0) + return codec_index; - codec_conf[*codec_conf_index].dlc = codec[comp_index]; - codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix; + sdw_version = SDW_VERSION(adr); + link_id = SDW_DISCO_LINK_ID(adr); + unique_id = SDW_UNIQUE_ID(adr); + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + class_id = SDW_CLASS_ID(adr); + + if (codec_info_list[codec_index].codec_name) + codec->name = devm_kstrdup(dev, + codec_info_list[codec_index].codec_name, + GFP_KERNEL); + else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x", link_id, + mfg_id, part_id, class_id); + else + codec->name = devm_kasprintf(dev, GFP_KERNEL, + "sdw:%01x:%04x:%04x:%02x:%01x", link_id, + mfg_id, part_id, class_id, unique_id); + + if (!codec->name) + return -ENOMEM; - ++*codec_conf_index; - } + codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; return 0; } static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, + const struct snd_soc_acpi_link_adr *adr_link, struct snd_soc_dai_link *dai_links, bool playback, int group_id, int adr_index, int dai_index) { @@ -1212,34 +1214,34 @@ static int set_codec_init_func(struct snd_soc_card *card, * Initialize the codec. If codec is part of an aggregated * group (group_id>0), initialize all codecs belonging to * same group. - * The first link should start with link->adr_d[adr_index] + * The first link should start with adr_link->adr_d[adr_index] * because that is the device that we want to initialize and * we should end immediately if it is not aggregated (group_id=0) */ - for ( ; i < link->num_adr; i++) { + for ( ; i < adr_link->num_adr; i++) { int codec_index; - codec_index = find_codec_info_part(link->adr_d[i].adr); - + codec_index = find_codec_info_part(adr_link->adr_d[i].adr); if (codec_index < 0) return codec_index; /* The group_id is > 0 iff the codec is aggregated */ - if (link->adr_d[i].endpoints->group_id != group_id) + if (adr_link->adr_d[i].endpoints->group_id != group_id) continue; if (codec_info_list[codec_index].dais[dai_index].init) codec_info_list[codec_index].dais[dai_index].init(card, - link, + adr_link, dai_links, &codec_info_list[codec_index], playback); if (!group_id) return 0; } + i = 0; - link++; - } while (link->mask); + adr_link++; + } while (adr_link->mask); return 0; } @@ -1261,73 +1263,45 @@ static int set_codec_init_func(struct snd_soc_card *card, static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, struct device *dev, int *cpu_dai_id, int *cpu_dai_num, int *codec_num, unsigned int *group_id, - bool *group_generated, int adr_index) + int adr_index) { - const struct snd_soc_acpi_adr_device *adr_d; - const struct snd_soc_acpi_link_adr *adr_next; - bool no_aggregation; - int index = 0; + bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; int i; - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - adr_d = &adr_link->adr_d[adr_index]; - - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - - cpu_dai_id[index++] = ffs(adr_link->mask) - 1; - if (!adr_d->endpoints->aggregated || no_aggregation) { + if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { + cpu_dai_id[0] = ffs(adr_link->mask) - 1; *cpu_dai_num = 1; *codec_num = 1; *group_id = 0; return 0; } - *group_id = adr_d->endpoints->group_id; - - /* Count endpoints with the same group_id in the adr_link */ *codec_num = 0; - for (i = 0; i < adr_link->num_adr; i++) { - if (adr_link->adr_d[i].endpoints->aggregated && - adr_link->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; - } + *cpu_dai_num = 0; + *group_id = adr_link->adr_d[adr_index].endpoints->group_id; - /* gather other link ID of slaves in the same group */ - for (adr_next = adr_link + 1; adr_next && adr_next->num_adr; - adr_next++) { - const struct snd_soc_acpi_endpoint *endpoint; + /* Count endpoints with the same group_id in the adr_link */ + for (; adr_link && adr_link->num_adr; adr_link++) { + unsigned int link_codecs = 0; - endpoint = adr_next->adr_d->endpoints; - if (!endpoint->aggregated || - endpoint->group_id != *group_id) - continue; + for (i = 0; i < adr_link->num_adr; i++) { + if (adr_link->adr_d[i].endpoints->aggregated && + adr_link->adr_d[i].endpoints->group_id == *group_id) + link_codecs++; + } - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_next->mask)) - return -EINVAL; + if (link_codecs) { + *codec_num += link_codecs; - if (index >= SDW_MAX_CPU_DAIS) { - dev_err(dev, " cpu_dai_id array overflows"); - return -EINVAL; - } + if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { + dev_err(dev, "cpu_dai_id array overflowed\n"); + return -EINVAL; + } - cpu_dai_id[index++] = ffs(adr_next->mask) - 1; - for (i = 0; i < adr_next->num_adr; i++) { - if (adr_next->adr_d[i].endpoints->aggregated && - adr_next->adr_d[i].endpoints->group_id == *group_id) - (*codec_num)++; + cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; } } - /* - * indicate CPU DAIs for this group have been generated - * to avoid generating CPU DAIs for this group again. - */ - group_generated[*group_id] = true; - *cpu_dai_num = index; - return 0; } @@ -1344,37 +1318,36 @@ static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_m static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -static int create_sdw_dailink(struct snd_soc_card *card, - struct device *dev, int *link_index, +static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, struct snd_soc_dai_link *dai_links, int sdw_be_num, int sdw_cpu_dai_num, struct snd_soc_dai_link_component *cpus, - const struct snd_soc_acpi_link_adr *link, - int *cpu_id, bool *group_generated, - struct snd_soc_codec_conf *codec_conf, - int codec_count, int *link_id, + const struct snd_soc_acpi_link_adr *adr_link, + int *cpu_id, struct snd_soc_codec_conf *codec_conf, + int codec_count, int *be_id, int *codec_conf_index, bool *ignore_pch_dmic, bool append_dai_type, int adr_index, int dai_index) { - const struct snd_soc_acpi_link_adr *link_next; + struct device *dev = card->dev; + const struct snd_soc_acpi_link_adr *adr_link_next; struct snd_soc_dai_link_component *codecs; struct sof_sdw_codec_info *codec_info; int cpu_dai_id[SDW_MAX_CPU_DAIS]; int cpu_dai_num, cpu_dai_index; unsigned int group_id; - int codec_idx = 0; + int codec_dlc_index = 0; int codec_index; int codec_num; int stream; int i = 0; + int j, k; int ret; - int k; - ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, group_generated, adr_index); + ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, + &group_id, adr_index); if (ret) return ret; @@ -1383,32 +1356,50 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -ENOMEM; /* generate codec name on different links in the same group */ - for (link_next = link; link_next && link_next->num_adr && - i < cpu_dai_num; link_next++) { - const struct snd_soc_acpi_endpoint *endpoints; - - endpoints = link_next->adr_d->endpoints; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - + j = adr_index; + for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && + i < cpu_dai_num; adr_link_next++) { /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(link_next->mask) - 1) + if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) continue; - ret = create_codec_dai_name(dev, link_next, codecs, codec_idx, - codec_conf, codec_count, codec_conf_index, - adr_index, dai_index); - if (ret < 0) - return ret; + /* j reset after loop, adr_index only applies to first link */ + for (; j < adr_link_next->num_adr; j++) { + const struct snd_soc_acpi_endpoint *endpoints; + + endpoints = adr_link_next->adr_d[j].endpoints; + + if (group_id && (!endpoints->aggregated || + endpoints->group_id != group_id)) + continue; + + /* sanity check */ + if (*codec_conf_index >= codec_count) { + dev_err(dev, "codec_conf array overflowed\n"); + return -EINVAL; + } + + ret = fill_sdw_codec_dlc(dev, adr_link_next, + &codecs[codec_dlc_index], + j, dai_index); + if (ret) + return ret; + + codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; + codec_conf[*codec_conf_index].name_prefix = + adr_link_next->adr_d[j].name_prefix; + + codec_dlc_index++; + (*codec_conf_index)++; + } + j = 0; /* check next link to create codec dai in the processed group */ i++; - codec_idx += link_next->num_adr; } /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(link->adr_d[adr_index].adr); + codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); if (codec_index < 0) return codec_index; codec_info = &codec_info_list[codec_index]; @@ -1431,9 +1422,9 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (!codec_info->dais[dai_index].direction[stream]) continue; - *link_id = codec_info->dais[dai_index].dailink[stream]; - if (*link_id < 0) { - dev_err(dev, "Invalid dailink id %d\n", *link_id); + *be_id = codec_info->dais[dai_index].dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); return -EINVAL; } @@ -1466,7 +1457,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -ENOMEM; if (cpu_dai_index >= sdw_cpu_dai_num) { - dev_err(dev, "invalid cpu dai index %d", + dev_err(dev, "invalid cpu dai index %d\n", cpu_dai_index); return -EINVAL; } @@ -1479,18 +1470,18 @@ static int create_sdw_dailink(struct snd_soc_card *card, * not be larger than sdw_be_num */ if (*link_index >= sdw_be_num) { - dev_err(dev, "invalid dai link index %d", *link_index); + dev_err(dev, "invalid dai link index %d\n", *link_index); return -EINVAL; } if (*cpu_id >= sdw_cpu_dai_num) { - dev_err(dev, " invalid cpu dai index %d", *cpu_id); + dev_err(dev, "invalid cpu dai index %d\n", *cpu_id); return -EINVAL; } playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *link_index, (*link_id)++, name, + init_dai_link(dev, dai_links + *link_index, (*be_id)++, name, playback, capture, cpus + *cpu_id, cpu_dai_num, codecs, codec_num, @@ -1504,10 +1495,10 @@ static int create_sdw_dailink(struct snd_soc_card *card, set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; - ret = set_codec_init_func(card, link, dai_links + (*link_index)++, + ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { - dev_err(dev, "failed to init codec %d", codec_index); + dev_err(dev, "failed to init codec %d\n", codec_index); return ret; } @@ -1519,65 +1510,26 @@ static int create_sdw_dailink(struct snd_soc_card *card, #define IDISP_CODEC_MASK 0x4 -static int sof_card_codec_conf_alloc(struct device *dev, - struct snd_soc_acpi_mach_params *mach_params, - struct snd_soc_codec_conf **codec_conf, - int *codec_conf_count) +static int sof_card_dai_links_create(struct snd_soc_card *card) { - const struct snd_soc_acpi_link_adr *adr_link; - struct snd_soc_codec_conf *c_conf; - int num_codecs = 0; - int codec_index; - int i; - - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - - /* generate DAI links by each sdw link */ - for (; adr_link->num_adr; adr_link++) { - for (i = 0; i < adr_link->num_adr; i++) { - if (!adr_link->adr_d[i].name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_link->adr_d[i].adr); - return -EINVAL; - } - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; - num_codecs += codec_info_list[codec_index].dai_num; - } - } - - c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL); - if (!c_conf) - return -ENOMEM; - - *codec_conf = c_conf; - *codec_conf_count = num_codecs; - - return 0; -} - -static int sof_card_dai_links_create(struct device *dev, - struct snd_soc_acpi_mach *mach, - struct snd_soc_card *card) -{ - int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num; + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link_component *idisp_components; struct snd_soc_dai_link_component *ssp_components; - struct snd_soc_acpi_mach_params *mach_params; - const struct snd_soc_acpi_link_adr *adr_link; + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; + bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; bool append_dai_type = false; bool ignore_pch_dmic = false; - int codec_conf_count; + int codec_conf_num = 0; int codec_conf_index = 0; - bool group_generated[SDW_MAX_GROUPS]; + bool group_generated[SDW_MAX_GROUPS] = { }; int ssp_codec_index, ssp_mask; - struct snd_soc_dai_link *links; + struct snd_soc_dai_link *dai_links; int num_links, link_index = 0; char *name, *cpu_name; int total_cpu_dai_num; @@ -1585,30 +1537,15 @@ static int sof_card_dai_links_create(struct device *dev, int i, j, be_id = 0; int codec_index; int cpu_id = 0; - int comp_num; int ret; - mach_params = &mach->mach_params; - - /* allocate codec conf, will be populated when dailinks are created */ - ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count); - if (ret < 0) + ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num, + &codec_conf_num); + if (ret < 0) { + dev_err(dev, "failed to get sdw link info %d\n", ret); return ret; - - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - codec_info_list[i].amp_num = 0; - - if (mach_params->codec_mask & IDISP_CODEC_MASK) { - ctx->idisp_codec = true; - - if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) - hdmi_num = SOF_TGL_HDMI_COUNT; - else - hdmi_num = SOF_PRE_TGL_HDMI_COUNT; } - ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* * on generic tgl platform, I2S or sdw mode is supported * based on board rework. A ACPI device is registered in @@ -1616,54 +1553,52 @@ static int sof_card_dai_links_create(struct device *dev, * Here check ACPI ID to confirm I2S is supported. */ ssp_codec_index = find_codec_info_acpi(mach->id); - ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0; - comp_num = hdmi_num + ssp_num; + if (ssp_codec_index >= 0) { + ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); + ssp_num = hweight_long(ssp_mask); + } - ret = get_sdw_dailink_info(dev, mach_params->links, - &sdw_be_num, &sdw_cpu_dai_num); - if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d", ret); - return ret; + if (mach_params->codec_mask & IDISP_CODEC_MASK) { + ctx->idisp_codec = true; + + if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) + hdmi_num = SOF_TGL_HDMI_COUNT; + else + hdmi_num = SOF_PRE_TGL_HDMI_COUNT; } /* enable dmic01 & dmic16k */ - dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; - comp_num += dmic_num; + if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) + dmic_num = 2; if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - comp_num++; + bt_num = 1; - dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, - dmic_num, ctx->idisp_codec ? hdmi_num : 0); + dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", + sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num); /* allocate BE dailinks */ - num_links = comp_num + sdw_be_num; - links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL); + num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) + return -ENOMEM; /* allocated CPU DAIs */ - total_cpu_dai_num = comp_num + sdw_cpu_dai_num; - cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), - GFP_KERNEL); + total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num; + cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; - if (!links || !cpus) + /* allocate codec conf, will be populated when dailinks are created */ + codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), + GFP_KERNEL); + if (!codec_conf) return -ENOMEM; /* SDW */ if (!sdw_be_num) goto SSP; - adr_link = mach_params->links; - if (!adr_link) - return -EINVAL; - - /* - * SoundWire Slaves aggregated in the same group may be - * located on different hardware links. Clear array to indicate - * CPU DAIs for this group have not been generated. - */ - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_generated[i] = false; - for (i = 0; i < SDW_MAX_LINKS; i++) sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; @@ -1702,11 +1637,6 @@ out: const struct snd_soc_acpi_endpoint *endpoint; endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x", - adr_link->mask); - continue; - } /* this group has been generated */ if (endpoint->aggregated && @@ -1719,17 +1649,20 @@ out: return codec_index; for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num, - sdw_cpu_dai_num, cpus, adr_link, - &cpu_id, group_generated, - codec_conf, codec_conf_count, + ret = create_sdw_dailink(card, &link_index, dai_links, + sdw_be_num, sdw_cpu_dai_num, cpus, + adr_link, &cpu_id, + codec_conf, codec_conf_num, &be_id, &codec_conf_index, &ignore_pch_dmic, append_dai_type, i, j); if (ret < 0) { - dev_err(dev, "failed to create dai link %d", link_index); + dev_err(dev, "failed to create dai link %d\n", link_index); return ret; } } + + if (aggregation && endpoint->aggregated) + group_generated[endpoint->group_id] = true; } } @@ -1773,13 +1706,13 @@ SSP: playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, playback, capture, cpus + cpu_id, 1, ssp_components, 1, NULL, info->ops); - ret = info->dais[0].init(card, NULL, links + link_index, info, 0); + ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); if (ret < 0) return ret; @@ -1794,7 +1727,7 @@ DMIC: goto HDMI; } cpus[cpu_id].dai_name = "DMIC01 Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic01", + init_dai_link(dev, dai_links + link_index, be_id, "dmic01", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1802,7 +1735,7 @@ DMIC: INC_ID(be_id, cpu_id, link_index); cpus[cpu_id].dai_name = "DMIC16k Pin"; - init_dai_link(dev, links + link_index, be_id, "dmic16k", + init_dai_link(dev, dai_links + link_index, be_id, "dmic16k", 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, @@ -1845,7 +1778,7 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 0, // HDMI only supports playback cpus + cpu_id, 1, idisp_components + i, 1, @@ -1866,15 +1799,15 @@ HDMI: return -ENOMEM; cpus[cpu_id].dai_name = cpu_name; - init_dai_link(dev, links + link_index, be_id, name, 1, 1, - cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); + init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1, + cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); } - card->dai_link = links; + card->dai_link = dai_links; card->num_links = num_links; card->codec_conf = codec_conf; - card->num_configs = codec_conf_count; + card->num_configs = codec_conf_num; return 0; } @@ -1913,15 +1846,15 @@ static struct snd_soc_card card_sof_sdw = { static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, const char *dai_name) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int i; int j; - for_each_card_prelinks(card, i, link) { - for (j = 0; j < link->num_codecs; j++) { + for_each_card_prelinks(card, i, dai_link) { + for (j = 0; j < dai_link->num_codecs; j++) { /* Check each codec in a link */ - if (!strcmp(link->codecs[j].dai_name, dai_name)) - return link; + if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) + return dai_link; } } return NULL; @@ -1929,7 +1862,7 @@ static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card static void mc_dailink_exit_loop(struct snd_soc_card *card) { - struct snd_soc_dai_link *link; + struct snd_soc_dai_link *dai_link; int ret; int i, j; @@ -1942,10 +1875,11 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) * We don't need to call .exit function if there is no matched * dai link found. */ - link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name); - if (link) { + dai_link = mc_find_codec_dai_used(card, + codec_info_list[i].dais[j].dai_name); + if (dai_link) { /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, link); + ret = codec_info_list[i].dais[j].exit(card, dai_link); if (ret) dev_warn(card->dev, "codec exit failed %d\n", @@ -1959,34 +1893,38 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) static int mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = &card_sof_sdw; - struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); struct mc_private *ctx; int amp_num = 0, i; int ret; - dev_dbg(&pdev->dev, "Entry\n"); + card->dev = &pdev->dev; + + dev_dbg(card->dev, "Entry\n"); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + snd_soc_card_set_drvdata(card, ctx); + dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(&pdev->dev); - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + log_quirks(card->dev); - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + codec_info_list[i].amp_num = 0; - mach = pdev->dev.platform_data; - ret = sof_card_dai_links_create(&pdev->dev, mach, - card); + ret = sof_card_dai_links_create(card); if (ret < 0) return ret; @@ -2017,7 +1955,7 @@ static int mc_probe(struct platform_device *pdev) card->long_name = sdw_card_long_name; /* Register the card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); mc_dailink_exit_loop(card); @@ -2036,6 +1974,12 @@ static void mc_remove(struct platform_device *pdev) mc_dailink_exit_loop(card); } +static const struct platform_device_id mc_id_table[] = { + { "sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + static struct platform_driver sof_sdw_driver = { .driver = { .name = "sof_sdw", @@ -2043,6 +1987,7 @@ static struct platform_driver sof_sdw_driver = { }, .probe = mc_probe, .remove_new = mc_remove, + .id_table = mc_id_table, }; module_platform_driver(sof_sdw_driver); @@ -2052,6 +1997,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_sdw"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 37402170d5f9..2f4fe6bc3d5d 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -80,6 +80,7 @@ struct sof_sdw_dai_info { struct sof_sdw_codec_info { const int part_id; const int version_id; + const char *codec_name; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool ignore_pch_dmic; @@ -205,4 +206,10 @@ int sof_sdw_cs42l42_init(struct snd_soc_card *card, struct sof_sdw_codec_info *info, bool playback); +/* CS AMP support */ +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); #endif diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c index c4a16e4c9f69..ad130d913415 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ b/sound/soc/intel/boards/sof_sdw_cs42l42.c @@ -99,9 +99,9 @@ static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd) jack = &ctx->sdw_headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); ret = snd_soc_component_set_jack(component, jack, NULL); diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c new file mode 100644 index 000000000000..98f6546f484b --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 Intel Corporation + +/* + * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "sof_sdw_common.h" + +#define CODEC_NAME_SIZE 8 + +static int cs_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + const char *dai_name = rtd->dai_link->codecs->dai_name; + struct snd_soc_card *card = rtd->card; + char codec_name[CODEC_NAME_SIZE]; + + snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:%s", + card->components, codec_name); + if (!card->components) + return -ENOMEM; + + return 0; +} + + +int sof_sdw_cs_amp_init(struct snd_soc_card *card, + const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* Count amp number and do init on playback link only. */ + if (!playback) + return 0; + + info->amp_num++; + dai_links->init = cs_spk_init; + + return 0; +} diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 0aef718e82b2..5aa16fd3939b 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -472,6 +472,15 @@ static const struct platform_device_id board_ids[] = { SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, + { + .name = "rpl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_NO_OF_HDMI_PLAYBACK(3) | + SOF_HDMI_PLAYBACK_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 30ca5416c9a3..f1a5cb825ff1 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, return 0; } +static const struct snd_soc_dai_ops catpt_dai_ops = { + .pcm_new = catpt_dai_pcm_new, +}; + static struct snd_soc_dai_driver dai_drivers[] = { /* FE DAIs */ { @@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = { { .name = "ssp0-port", .id = CATPT_SSP_IFACE_0, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, { .name = "ssp1-port", .id = CATPT_SSP_IFACE_1, - .pcm_new = catpt_dai_pcm_new, .playback = { .channels_min = 1, .channels_max = 8, @@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 1, .channels_max = 8, }, + .ops = &catpt_dai_ops, }, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index bcd66e0094b4..8e995edf4c10 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -570,6 +570,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { }, { .comp_ids = &adl_rt5682_rt5682s_hp, + .drv_name = "adl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_lt6911_hdmi, + .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &adl_rt5682_rt5682s_hp, .drv_name = "adl_rt5682", .sof_tplg_filename = "sof-adl-rt5682.tplg", }, diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index f5c7e1bbded0..f56bd7d656e9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -34,6 +34,11 @@ static const struct snd_soc_acpi_codecs mx98360a_spk = { .codecs = {"MX98360A"} }; +static struct snd_soc_acpi_codecs rt5650_spk = { + .num_codecs = 1, + .codecs = {"10EC5650"} +}; + static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = { .num_codecs = 2, .codecs = {"10EC5682", "RTL5682"}, @@ -98,6 +103,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "10EC5650", + .drv_name = "jsl_rt5650", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt5650_spk, + .sof_tplg_filename = "sof-jsl-rt5650.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_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 ed9821adc1d9..0304246d2922 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -161,6 +161,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { + { + .adr = 0x000130025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1318-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { + { + .adr = 0x000232025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1318-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { + { + .adr = 0x000030025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { { .adr = 0x000130025D071401ull, @@ -232,6 +259,25 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_group1_adr), + .adr_d = rt1318_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1318_2_group1_adr), + .adr_d = rt1318_2_group1_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = { { .adr = 0x000230019F836300ull, @@ -299,6 +345,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", }, { + .link_mask = GENMASK(2, 0), + .links = mtl_sdw_rt1318_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg" + }, + { .link_mask = GENMASK(3, 0), .links = mtl_3_in_1_sdca, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 302a08018572..122673c1dae2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -308,6 +308,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {} }; +static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr rplp_crb[] = { { .mask = BIT(2), @@ -322,6 +331,16 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .codecs = {"10EC5682", "RTL5682"}, }; +static const struct snd_soc_acpi_codecs rpl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + +static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { .num_codecs = 1, .codecs = {"MX98360A"}, @@ -332,6 +351,16 @@ static const struct snd_soc_acpi_codecs rpl_max98373_amp = { .codecs = {"MX98373"} }; +static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + +static const struct snd_soc_acpi_codecs rpl_nau8318_amp = { + .num_codecs = 1, + .codecs = {"NVTN2012"} +}; + static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { .num_codecs = 1, .codecs = {"RTL1019"} @@ -340,6 +369,13 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, + .drv_name = "rpl_mx98357_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_max98357a_amp, + .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg", + }, + { + .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_mx98360_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_max98360a_amp, @@ -353,12 +389,39 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", }, { + .id = "10508825", + .drv_name = "rpl_nau8318_8825", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_nau8318_amp, + .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", + }, + { .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_rt1019_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_rt1019p_amp, .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "rpl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rpl_lt6911_hdmi, + .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &rpl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, + { + .id = "INTC10B0", + .drv_name = "rpl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); @@ -414,6 +477,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", }, { + .link_mask = 0x1, /* link0 required */ + .links = rpl_sdca_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-rt711-l0.tplg", + }, + { .link_mask = 0x4, /* link2 required */ .links = rplp_crb, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index b4893365d01d..6b06b7b5ede8 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops kmb_dai_ops = { + .probe = kmb_probe, .startup = kmb_dai_startup, .trigger = kmb_dai_trigger, .hw_params = kmb_dai_hw_params, @@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; @@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = { SNDRV_PCM_FMTBIT_S16_LE), }, .ops = &kmb_dai_ops, - .probe = kmb_probe, }, }; diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index d31509298a0a..fc2eb04da172 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -169,7 +169,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void) static const struct skl_dsp_ops dsp_ops[] = { { - .id = 0x9d70, + .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, .num_cores = 2, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, @@ -177,7 +177,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = skl_sst_dsp_cleanup }, { - .id = 0x9d71, + .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, .num_cores = 2, .loader_ops = skl_get_loader_ops, .init = skl_sst_dsp_init, @@ -185,7 +185,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = skl_sst_dsp_cleanup }, { - .id = 0x5a98, + .id = PCI_DEVICE_ID_INTEL_HDA_APL, .num_cores = 2, .loader_ops = bxt_get_loader_ops, .init = bxt_sst_dsp_init, @@ -193,7 +193,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = bxt_sst_dsp_cleanup }, { - .id = 0x3198, + .id = PCI_DEVICE_ID_INTEL_HDA_GML, .num_cores = 2, .loader_ops = bxt_get_loader_ops, .init = bxt_sst_dsp_init, @@ -201,7 +201,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = bxt_sst_dsp_cleanup }, { - .id = 0x9dc8, + .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0xa348, + .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -217,7 +217,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0x02c8, + .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, @@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = { .cleanup = cnl_sst_dsp_cleanup }, { - .id = 0x06c8, + .id = PCI_DEVICE_ID_INTEL_HDA_CML_H, .num_cores = 4, .loader_ops = bxt_get_loader_ops, .init = cnl_sst_dsp_init, diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a4209d88b0c6..ac3dc8c63c26 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -13,6 +13,7 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/delay.h> +#include <sound/hdaudio.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include "skl.h" @@ -152,7 +153,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) * The recommended SDxFMT programming sequence for BXT * platforms is to couple the stream before writing the format */ - if (IS_BXT(skl->pci)) { + if (HDA_CONTROLLER_IS_APL(skl->pci)) { snd_hdac_ext_stream_decouple(bus, stream, false); err = snd_hdac_stream_setup(hdac_stream(stream)); snd_hdac_ext_stream_decouple(bus, stream, true); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 998bd0232cf1..77408a981b97 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -608,8 +608,8 @@ struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) static void init_skl_xtal_rate(int pci_id) { switch (pci_id) { - case 0x9d70: - case 0x9d71: + case PCI_DEVICE_ID_INTEL_HDA_SKL_LP: + case PCI_DEVICE_ID_INTEL_HDA_KBL_LP: skl_clk_src[0].rate = 24000000; return; @@ -1145,44 +1145,28 @@ static void skl_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id skl_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) - /* BXT-P */ - { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) - /* KBL */ - { PCI_DEVICE(0x8086, 0x9D71), - .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) - /* GLK */ - { PCI_DEVICE(0x8086, 0x3198), - .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) - /* CNL */ - { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) - /* CFL */ - { PCI_DEVICE(0x8086, 0xa348), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) - /* CML-LP */ - { PCI_DEVICE(0x8086, 0x02c8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) }, #endif #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) - /* CML-H */ - { PCI_DEVICE(0x8086, 0x06c8), - .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) }, #endif { 0, } }; diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 578af21769c9..517619531615 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { + .probe = jz4740_i2s_dai_probe, .startup = jz4740_i2s_startup, .shutdown = jz4740_i2s_shutdown, .trigger = jz4740_i2s_trigger, @@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver jz4740_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = { }; static struct snd_soc_dai_driver jz4770_i2s_dai = { - .probe = jz4740_i2s_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index 9ded16329747..406ee8db1a3c 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -208,7 +208,7 @@ static struct platform_driver loongson_audio_driver = { .driver = { .name = "loongson-asoc-card", .pm = &snd_soc_pm_ops, - .of_match_table = of_match_ptr(loongson_asoc_dt_ids), + .of_match_table = loongson_asoc_dt_ids, }, }; module_platform_driver(loongson_audio_driver); diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index b919f0fe8361..d45228a3a558 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { - .trigger = loongson_i2s_trigger, - .hw_params = loongson_i2s_hw_params, - .set_sysclk = loongson_i2s_set_dai_sysclk, - .set_fmt = loongson_i2s_set_fmt, -}; - static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) { struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev); @@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static const struct snd_soc_dai_ops loongson_i2s_dai_ops = { + .probe = loongson_i2s_dai_probe, + .trigger = loongson_i2s_trigger, + .hw_params = loongson_i2s_hw_params, + .set_sysclk = loongson_i2s_set_dai_sysclk, + .set_fmt = loongson_i2s_set_fmt, +}; + struct snd_soc_dai_driver loongson_i2s_dai = { .name = "loongson-i2s", - .probe = loongson_i2s_dai_probe, .playback = { .stream_name = "CPU-Playback", .channels_min = 1, diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 90db67e0ce4f..8d1bc8814486 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -54,6 +54,26 @@ config SND_SOC_MT6797_MT6351 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT7986 + tristate "ASoC support for Mediatek MT7986 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for MediaTek MT7986 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT7986_WM8960 + tristate "ASoc Audio driver for MT7986 with WM8960 codec" + depends on SND_SOC_MT7986 && I2C + select SND_SOC_WM8960 + help + This adds support for ASoC machine driver for MediaTek MT7986 + boards with the WM8960 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3de38cfc69e5..3938e7f75c2e 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ +obj-$(CONFIG_SND_SOC_MT7986) += mt7986/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/ diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile new file mode 100644 index 000000000000..fc4c82559b29 --- /dev/null +++ b/sound/soc/mediatek/mt7986/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt7986-afe-objs := \ + mt7986-afe-pcm.o \ + mt7986-dai-etdm.o + +obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o +obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h new file mode 100644 index 000000000000..fc3bb31e5167 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu <vic.wu@mediatek.com> + * Maso Huang <maso.huang@mediatek.com> + */ + +#ifndef _MT_7986_AFE_COMMON_H_ +#define _MT_7986_AFE_COMMON_H_ + +#include <sound/soc.h> +#include <linux/clk.h> +#include <linux/list.h> +#include <linux/regmap.h> +#include "../common/mtk-base-afe.h" + +enum { + MT7986_MEMIF_DL1, + MT7986_MEMIF_VUL12, + MT7986_MEMIF_NUM, + MT7986_DAI_ETDM = MT7986_MEMIF_NUM, + MT7986_DAI_NUM, +}; + +enum { + MT7986_IRQ_0, + MT7986_IRQ_1, + MT7986_IRQ_2, + MT7986_IRQ_NUM, +}; + +struct mt7986_afe_private { + struct clk_bulk_data *clks; + int num_clks; + + int pm_runtime_bypass_reg_ctl; + + /* dai */ + void *dai_priv[MT7986_DAI_NUM]; +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, + unsigned int rate); + +/* dai register */ +int mt7986_dai_etdm_register(struct mtk_base_afe *afe); +#endif diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c new file mode 100644 index 000000000000..d497e1129889 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC AFE platform driver for MT7986 + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu <vic.wu@mediatek.com> + * Maso Huang <maso.huang@mediatek.com> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> + +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 13, + MTK_AFE_RATE_96K = 14, + MTK_AFE_RATE_176K = 17, + MTK_AFE_RATE_192K = 18, +}; + +enum { + CLK_INFRA_AUD_BUS_CK = 0, + CLK_INFRA_AUD_26M_CK, + CLK_INFRA_AUD_L_CK, + CLK_INFRA_AUD_AUD_CK, + CLK_INFRA_AUD_EG2_CK, + CLK_NUM +}; + +static const char *aud_clks[CLK_NUM] = { + [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck", + [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck", + [CLK_INFRA_AUD_L_CK] = "aud_l_ck", + [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck", + [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck", +}; + +unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static const struct snd_pcm_hardware mt7986_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt7986_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +static int mt7986_irq_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt7986_afe_rate_transform(afe->dev, rate); +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT7986_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +static const struct snd_kcontrol_new o018_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0), +}; + +static const struct snd_kcontrol_new o019_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = { + /* DL */ + SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* UL */ + SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0, + o018_mix, ARRAY_SIZE(o018_mix)), + SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0, + o019_mix, ARRAY_SIZE(o019_mix)), +}; + +static const struct snd_soc_dapm_route mt7986_memif_routes[] = { + {"I032", NULL, "DL1"}, + {"I033", NULL, "DL1"}, + {"UL1", NULL, "O018"}, + {"UL1", NULL, "O019"}, + {"O018", "I150_Switch", "I150"}, + {"O019", "I151_Switch", "I151"}, +}; + +static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = { + .name = "mt7986-afe-pcm-dai", +}; + +static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = { + [MT7986_MEMIF_DL1] = { + .name = "DL1", + .id = MT7986_MEMIF_DL1, + .reg_ofs_base = AFE_DL0_BASE, + .reg_ofs_cur = AFE_DL0_CUR, + .reg_ofs_end = AFE_DL0_END, + .reg_ofs_base_msb = AFE_DL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL0_CUR_MSB, + .reg_ofs_end_msb = AFE_DL0_END_MSB, + .fs_reg = AFE_DL0_CON0, + .fs_shift = DL0_MODE_SFT, + .fs_maskbit = DL0_MODE_MASK, + .mono_reg = AFE_DL0_CON0, + .mono_shift = DL0_MONO_SFT, + .enable_reg = AFE_DL0_CON0, + .enable_shift = DL0_ON_SFT, + .hd_reg = AFE_DL0_CON0, + .hd_shift = DL0_HD_MODE_SFT, + .hd_align_reg = AFE_DL0_CON0, + .hd_align_mshift = DL0_HALIGN_SFT, + .pbuf_reg = AFE_DL0_CON0, + .pbuf_shift = DL0_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL0_CON0, + .minlen_shift = DL0_MINLEN_SFT, + }, + [MT7986_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT7986_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL0_BASE, + .reg_ofs_cur = AFE_VUL0_CUR, + .reg_ofs_end = AFE_VUL0_END, + .reg_ofs_base_msb = AFE_VUL0_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL0_END_MSB, + .fs_reg = AFE_VUL0_CON0, + .fs_shift = VUL0_MODE_SFT, + .fs_maskbit = VUL0_MODE_MASK, + .mono_reg = AFE_VUL0_CON0, + .mono_shift = VUL0_MONO_SFT, + .enable_reg = AFE_VUL0_CON0, + .enable_shift = VUL0_ON_SFT, + .hd_reg = AFE_VUL0_CON0, + .hd_shift = VUL0_HD_MODE_SFT, + .hd_align_reg = AFE_VUL0_CON0, + .hd_align_mshift = VUL0_HALIGN_SFT, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = { + [MT7986_IRQ_0] = { + .id = MT7986_IRQ_0, + .irq_cnt_reg = AFE_IRQ0_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ0_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ0_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT7986_IRQ_1] = { + .id = MT7986_IRQ_1, + .irq_cnt_reg = AFE_IRQ1_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ1_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ1_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT7986_IRQ_2] = { + .id = MT7986_IRQ_2, + .irq_cnt_reg = AFE_IRQ2_MCU_CFG1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ2_MCU_CFG0, + .irq_fs_shift = IRQ_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ2_MCU_CFG0, + .irq_en_shift = IRQ_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, +}; + +static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Those auto-gen regs are read-only, so put it as volatile because + * volatile registers cannot be cached, which means that they cannot + * be set when power is off + */ + + switch (reg) { + case AFE_DL0_CUR_MSB: + case AFE_DL0_CUR: + case AFE_DL0_RCH_MON: + case AFE_DL0_LCH_MON: + case AFE_VUL0_CUR_MSB: + case AFE_VUL0_CUR: + case AFE_IRQ_MCU_STATUS: + case AFE_MEMIF_RD_MON: + case AFE_MEMIF_WR_MON: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt7986_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .volatile_reg = mt7986_is_volatile_reg, + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1), +}; + +static int mt7986_init_clock(struct mtk_base_afe *afe) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret, i; + + afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM, + sizeof(*afe_priv->clks), GFP_KERNEL); + if (!afe_priv->clks) + return -ENOMEM; + afe_priv->num_clks = CLK_NUM; + + for (i = 0; i < afe_priv->num_clks; i++) + afe_priv->clks[i].id = aud_clks[i]; + + ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to get clocks\n"); + + return 0; +} + +static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + u32 mcu_en, status, status_mcu; + int i, ret; + irqreturn_t irq_ret = IRQ_HANDLED; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + irq_ret = IRQ_NONE; + goto err_irq; + } + + for (i = 0; i < MT7986_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu); + + return irq_ret; +} + +static int mt7986_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0); + + /* make sure all irq status are cleared, twice intended */ + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + +skip_regmap: + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); + + return 0; +} + +static int mt7986_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + return 0; + + /* enable clk*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, + AUD_APLL2_EN); + regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, + AUD_26M_EN); + + return 0; +} + +static int mt7986_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt7986_afe_component = { + .name = AFE_PCM_NAME, + .probe = mt7986_afe_component_probe, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, +}; + +static int mt7986_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt7986_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver); + + dai->dapm_widgets = mt7986_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets); + dai->dapm_routes = mt7986_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes); + + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt7986_dai_etdm_register, + mt7986_dai_memif_register, +}; + +static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt7986_afe_private *afe_priv; + struct device *dev; + int i, irq_id, ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + dev = afe->dev; + + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(afe->base_addr)) + return PTR_ERR(afe->base_addr); + + /* initial audio related clock */ + ret = mt7986_init_clock(afe); + if (ret) + return dev_err_probe(dev, ret, "Cannot initialize clocks\n"); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, + &mt7986_afe_regmap_config); + + pm_runtime_put_sync(&pdev->dev); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + afe_priv->pm_runtime_bypass_reg_ctl = false; + + /* init memif */ + afe->memif_size = MT7986_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = -1; + } + + mutex_init(&afe->irq_alloc_lock); + + /* irq initialize */ + afe->irqs_size = MT7986_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id < 0) { + ret = irq_id; + return dev_err_probe(dev, ret, "No irq found\n"); + } + ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) + return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n"); + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) + return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i); + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) + return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n"); + + afe->mtk_afe_hardware = &mt7986_afe_hardware; + afe->memif_fs = mt7986_memif_fs; + afe->irq_fs = mt7986_irq_fs; + + afe->runtime_resume = mt7986_afe_runtime_resume; + afe->runtime_suspend = mt7986_afe_runtime_suspend; + + /* register component */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt7986_afe_component, + NULL, 0); + if (ret) + return dev_err_probe(dev, ret, "Cannot register AFE component\n"); + + ret = devm_snd_soc_register_component(afe->dev, + &mt7986_afe_pcm_dai_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) + return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n"); + + return 0; +} + +static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt7986_afe_runtime_suspend(&pdev->dev); +} + +static const struct of_device_id mt7986_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt7986-afe" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match); + +static const struct dev_pm_ops mt7986_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend, + mt7986_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt7986_afe_pcm_driver = { + .driver = { + .name = "mt7986-audio", + .of_match_table = mt7986_afe_pcm_dt_match, + .pm = &mt7986_afe_pm_ops, + }, + .probe = mt7986_afe_pcm_dev_probe, + .remove_new = mt7986_afe_pcm_dev_remove, +}; +module_platform_driver(mt7986_afe_pcm_driver); + +MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986"); +MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c new file mode 100644 index 000000000000..e523d33846fe --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI eTDM Control + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu <vic.wu@mediatek.com> + * Maso Huang <maso.huang@mediatek.com> + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include "mt7986-afe-common.h" +#include "mt7986-reg.h" + +#define HOPPING_CLK 0 +#define APLL_CLK 1 +#define MTK_DAI_ETDM_FORMAT_I2S 0 +#define MTK_DAI_ETDM_FORMAT_DSPA 4 +#define MTK_DAI_ETDM_FORMAT_DSPB 5 + +enum { + MTK_ETDM_RATE_8K = 0, + MTK_ETDM_RATE_12K = 1, + MTK_ETDM_RATE_16K = 2, + MTK_ETDM_RATE_24K = 3, + MTK_ETDM_RATE_32K = 4, + MTK_ETDM_RATE_48K = 5, + MTK_ETDM_RATE_96K = 7, + MTK_ETDM_RATE_192K = 9, + MTK_ETDM_RATE_11K = 16, + MTK_ETDM_RATE_22K = 17, + MTK_ETDM_RATE_44K = 18, + MTK_ETDM_RATE_88K = 19, + MTK_ETDM_RATE_176K = 20, +}; + +struct mtk_dai_etdm_priv { + bool bck_inv; + bool lrck_inv; + bool slave_mode; + unsigned int format; +}; + +static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_ETDM_RATE_8K; + case 11025: + return MTK_ETDM_RATE_11K; + case 12000: + return MTK_ETDM_RATE_12K; + case 16000: + return MTK_ETDM_RATE_16K; + case 22050: + return MTK_ETDM_RATE_22K; + case 24000: + return MTK_ETDM_RATE_24K; + case 32000: + return MTK_ETDM_RATE_32K; + case 44100: + return MTK_ETDM_RATE_44K; + case 48000: + return MTK_ETDM_RATE_48K; + case 88200: + return MTK_ETDM_RATE_88K; + case 96000: + return MTK_ETDM_RATE_96K; + case 176400: + return MTK_ETDM_RATE_176K; + case 192000: + return MTK_ETDM_RATE_192K; + default: + dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n", + __func__, rate, MTK_ETDM_RATE_48K); + return MTK_ETDM_RATE_48K; + } +} + +static int get_etdm_wlen(unsigned int bitwidth) +{ + return bitwidth <= 16 ? 16 : 32; +} + +/* dai component */ +/* interconnection */ + +static const struct snd_kcontrol_new o124_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new o125_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { + + /* DL */ + SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0), + /* UL */ + SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)), + SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)), +}; + +static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { + {"I150", NULL, "ETDM Capture"}, + {"I151", NULL, "ETDM Capture"}, + {"ETDM Playback", NULL, "O124"}, + {"ETDM Playback", NULL, "O125"}, + {"O124", "I032_Switch", "I032"}, + {"O125", "I033_Switch", "I033"}, +}; + +/* dai ops */ +static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks); + if (ret) + return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n"); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0); + + return 0; +} + +static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, + CLK_OUT5_PDN); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, + CLK_IN5_PDN); + + clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks); +} + +static unsigned int get_etdm_ch_fixup(unsigned int channels) +{ + if (channels > 16) + return 24; + else if (channels > 8) + return 16; + else if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static int mtk_dai_etdm_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai, + int stream) +{ + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; + unsigned int rate = params_rate(params); + unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate); + unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate); + unsigned int channels = params_channels(params); + unsigned int bit_width = params_width(params); + unsigned int wlen = get_etdm_wlen(bit_width); + unsigned int val = 0; + unsigned int mask = 0; + + dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n", + __func__, stream, rate, bit_width); + + /* CON0 */ + mask |= ETDM_BIT_LEN_MASK; + val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1); + mask |= ETDM_WRD_LEN_MASK; + val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1); + mask |= ETDM_FMT_MASK; + val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format); + mask |= ETDM_CH_NUM_MASK; + val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1); + mask |= RELATCH_SRC_MASK; + val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK); + + switch (stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + /* set ETDM_OUT5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val); + + /* set ETDM_OUT5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_RELATCH_MASK, OUT_RELATCH(afe_rate)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK)); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, + OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate)); + + /* set ETDM_OUT5_CON5 */ + regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, + ETDM_CLK_DIV_MASK, ETDM_CLK_DIV); + break; + case SNDRV_PCM_STREAM_CAPTURE: + /* set ETDM_IN5_CON0 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val); + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, + ETDM_SYNC_MASK, ETDM_SYNC); + + /* set ETDM_IN5_CON2 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON2, + IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK)); + + /* set ETDM_IN5_CON3 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON3, + IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate)); + + /* set ETDM_IN5_CON4 */ + regmap_update_bits(afe->regmap, ETDM_IN5_CON4, + IN_RELATCH_MASK, IN_RELATCH(afe_rate)); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK); + mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE); + + return 0; +} + +static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + ETDM_EN); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + ETDM_EN); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, + 0); + regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, + 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt7986_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_etdm_priv *etdm_data; + void *priv_data; + + switch (dai->id) { + case MT7986_DAI_ETDM: + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv), + GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + afe_priv->dai_priv[dai->id] = priv_data; + etdm_data = afe_priv->dai_priv[dai->id]; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA; + break; + case SND_SOC_DAIFMT_DSP_B: + etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_NB_IF: + etdm_data->bck_inv = false; + etdm_data->lrck_inv = true; + break; + case SND_SOC_DAIFMT_IB_NF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = false; + break; + case SND_SOC_DAIFMT_IB_IF: + etdm_data->bck_inv = true; + etdm_data->lrck_inv = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + etdm_data->slave_mode = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + etdm_data->slave_mode = false; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +/* dai driver */ +#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { + { + .name = "ETDM", + .id = MT7986_DAI_ETDM, + .capture = { + .stream_name = "ETDM Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .playback = { + .stream_name = "ETDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ETDM_RATES, + .formats = MTK_ETDM_FORMATS, + }, + .ops = &mtk_dai_etdm_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + }, +}; + +int mt7986_dai_etdm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_etdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver); + + dai->dapm_widgets = mtk_dai_etdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets); + dai->dapm_routes = mtk_dai_etdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h new file mode 100644 index 000000000000..c2b200743c3f --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-reg.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt7986-reg.h -- MediaTek 7986 audio driver reg definition + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu <vic.wu@mediatek.com> + * Maso Huang <maso.huang@mediatek.com> + */ + +#ifndef _MT7986_REG_H_ +#define _MT7986_REG_H_ + +#define AUDIO_TOP_CON2 0x0008 +#define AUDIO_TOP_CON4 0x0010 +#define AUDIO_ENGEN_CON0 0x0014 +#define AFE_IRQ_MCU_EN 0x0100 +#define AFE_IRQ_MCU_STATUS 0x0120 +#define AFE_IRQ_MCU_CLR 0x0128 +#define AFE_IRQ0_MCU_CFG0 0x0140 +#define AFE_IRQ0_MCU_CFG1 0x0144 +#define AFE_IRQ1_MCU_CFG0 0x0148 +#define AFE_IRQ1_MCU_CFG1 0x014c +#define AFE_IRQ2_MCU_CFG0 0x0150 +#define AFE_IRQ2_MCU_CFG1 0x0154 +#define ETDM_IN5_CON0 0x13f0 +#define ETDM_IN5_CON1 0x13f4 +#define ETDM_IN5_CON2 0x13f8 +#define ETDM_IN5_CON3 0x13fc +#define ETDM_IN5_CON4 0x1400 +#define ETDM_OUT5_CON0 0x1570 +#define ETDM_OUT5_CON4 0x1580 +#define ETDM_OUT5_CON5 0x1584 +#define ETDM_4_7_COWORK_CON0 0x15e0 +#define ETDM_4_7_COWORK_CON1 0x15e4 +#define AFE_CONN018_1 0x1b44 +#define AFE_CONN018_4 0x1b50 +#define AFE_CONN019_1 0x1b64 +#define AFE_CONN019_4 0x1b70 +#define AFE_CONN124_1 0x2884 +#define AFE_CONN124_4 0x2890 +#define AFE_CONN125_1 0x28a4 +#define AFE_CONN125_4 0x28b0 +#define AFE_CONN_RS_0 0x3920 +#define AFE_CONN_RS_3 0x392c +#define AFE_CONN_16BIT_0 0x3960 +#define AFE_CONN_16BIT_3 0x396c +#define AFE_CONN_24BIT_0 0x3980 +#define AFE_CONN_24BIT_3 0x398c +#define AFE_MEMIF_CON0 0x3d98 +#define AFE_MEMIF_RD_MON 0x3da0 +#define AFE_MEMIF_WR_MON 0x3da4 +#define AFE_DL0_BASE_MSB 0x3e40 +#define AFE_DL0_BASE 0x3e44 +#define AFE_DL0_CUR_MSB 0x3e48 +#define AFE_DL0_CUR 0x3e4c +#define AFE_DL0_END_MSB 0x3e50 +#define AFE_DL0_END 0x3e54 +#define AFE_DL0_RCH_MON 0x3e58 +#define AFE_DL0_LCH_MON 0x3e5c +#define AFE_DL0_CON0 0x3e60 +#define AFE_VUL0_BASE_MSB 0x4220 +#define AFE_VUL0_BASE 0x4224 +#define AFE_VUL0_CUR_MSB 0x4228 +#define AFE_VUL0_CUR 0x422c +#define AFE_VUL0_END_MSB 0x4230 +#define AFE_VUL0_END 0x4234 +#define AFE_VUL0_CON0 0x4238 + +#define AFE_MAX_REGISTER AFE_VUL0_CON0 +#define AFE_IRQ_STATUS_BITS 0x7 +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0xffffff + +/* AUDIO_TOP_CON2 */ +#define CLK_OUT5_PDN BIT(14) +#define CLK_OUT5_PDN_MASK BIT(14) +#define CLK_IN5_PDN BIT(7) +#define CLK_IN5_PDN_MASK BIT(7) + +/* AUDIO_TOP_CON4 */ +#define PDN_APLL_TUNER2 BIT(12) +#define PDN_APLL_TUNER2_MASK BIT(12) + +/* AUDIO_ENGEN_CON0 */ +#define AUD_APLL2_EN BIT(3) +#define AUD_APLL2_EN_MASK BIT(3) +#define AUD_26M_EN BIT(0) +#define AUD_26M_EN_MASK BIT(0) + +/* AFE_DL0_CON0 */ +#define DL0_ON_SFT 28 +#define DL0_ON_MASK 0x1 +#define DL0_ON_MASK_SFT BIT(28) +#define DL0_MINLEN_SFT 20 +#define DL0_MINLEN_MASK 0xf +#define DL0_MINLEN_MASK_SFT (0xf << 20) +#define DL0_MODE_SFT 8 +#define DL0_MODE_MASK 0x1f +#define DL0_MODE_MASK_SFT (0x1f << 8) +#define DL0_PBUF_SIZE_SFT 5 +#define DL0_PBUF_SIZE_MASK 0x3 +#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5) +#define DL0_MONO_SFT 4 +#define DL0_MONO_MASK 0x1 +#define DL0_MONO_MASK_SFT BIT(4) +#define DL0_HALIGN_SFT 2 +#define DL0_HALIGN_MASK 0x1 +#define DL0_HALIGN_MASK_SFT BIT(2) +#define DL0_HD_MODE_SFT 0 +#define DL0_HD_MODE_MASK 0x3 +#define DL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL0_CON0 */ +#define VUL0_ON_SFT 28 +#define VUL0_ON_MASK 0x1 +#define VUL0_ON_MASK_SFT BIT(28) +#define VUL0_MODE_SFT 8 +#define VUL0_MODE_MASK 0x1f +#define VUL0_MODE_MASK_SFT (0x1f << 8) +#define VUL0_MONO_SFT 4 +#define VUL0_MONO_MASK 0x1 +#define VUL0_MONO_MASK_SFT BIT(4) +#define VUL0_HALIGN_SFT 2 +#define VUL0_HALIGN_MASK 0x1 +#define VUL0_HALIGN_MASK_SFT BIT(2) +#define VUL0_HD_MODE_SFT 0 +#define VUL0_HD_MODE_MASK 0x3 +#define VUL0_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_IRQ_MCU_CON */ +#define IRQ_MCU_MODE_SFT 4 +#define IRQ_MCU_MODE_MASK 0x1f +#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4) +#define IRQ_MCU_ON_SFT 0 +#define IRQ_MCU_ON_MASK 0x1 +#define IRQ_MCU_ON_MASK_SFT BIT(0) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT BIT(0) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT BIT(1) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT BIT(2) + +/* ETDM_IN5_CON2 */ +#define IN_CLK_SRC(x) ((x) << 10) +#define IN_CLK_SRC_SFT 10 +#define IN_CLK_SRC_MASK GENMASK(12, 10) + +/* ETDM_IN5_CON3 */ +#define IN_SEL_FS(x) ((x) << 26) +#define IN_SEL_FS_SFT 26 +#define IN_SEL_FS_MASK GENMASK(30, 26) + +/* ETDM_IN5_CON4 */ +#define IN_RELATCH(x) ((x) << 20) +#define IN_RELATCH_SFT 20 +#define IN_RELATCH_MASK GENMASK(24, 20) +#define IN_CLK_INV BIT(18) +#define IN_CLK_INV_MASK BIT(18) + +/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */ +#define RELATCH_SRC_MASK GENMASK(30, 28) +#define ETDM_CH_NUM_MASK GENMASK(27, 23) +#define ETDM_WRD_LEN_MASK GENMASK(20, 16) +#define ETDM_BIT_LEN_MASK GENMASK(15, 11) +#define ETDM_FMT_MASK GENMASK(8, 6) +#define ETDM_SYNC BIT(1) +#define ETDM_SYNC_MASK BIT(1) +#define ETDM_EN BIT(0) +#define ETDM_EN_MASK BIT(0) + +/* ETDM_OUT5_CON4 */ +#define OUT_RELATCH(x) ((x) << 24) +#define OUT_RELATCH_SFT 24 +#define OUT_RELATCH_MASK GENMASK(28, 24) +#define OUT_CLK_SRC(x) ((x) << 6) +#define OUT_CLK_SRC_SFT 6 +#define OUT_CLK_SRC_MASK GENMASK(8, 6) +#define OUT_SEL_FS(x) (x) +#define OUT_SEL_FS_SFT 0 +#define OUT_SEL_FS_MASK GENMASK(4, 0) + +/* ETDM_OUT5_CON5 */ +#define ETDM_CLK_DIV BIT(12) +#define ETDM_CLK_DIV_MASK BIT(12) +#define OUT_CLK_INV BIT(9) +#define OUT_CLK_INV_MASK BIT(9) + +/* ETDM_4_7_COWORK_CON0 */ +#define OUT_SEL(x) ((x) << 12) +#define OUT_SEL_SFT 12 +#define OUT_SEL_MASK GENMASK(15, 12) +#endif diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c new file mode 100644 index 000000000000..364d13b1c426 --- /dev/null +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver + * + * Copyright (c) 2023 MediaTek Inc. + * Authors: Vic Wu <vic.wu@mediatek.com> + * Maso Huang <maso.huang@mediatek.com> + */ + +#include <linux/module.h> +#include <sound/soc.h> + +#include "mt7986-afe-common.h" + +struct mt7986_wm8960_priv { + struct device_node *platform_node; + struct device_node *codec_node; +}; + +static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), +}; + +static const struct snd_kcontrol_new mt7986_wm8960_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("AMIC"), +}; + +SND_SOC_DAILINK_DEFS(playback, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(codec, + DAILINK_COMP_ARRAY(COMP_CPU("ETDM")), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { + /* FE */ + { + .name = "wm8960-playback", + .stream_name = "wm8960-playback", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback), + }, + { + .name = "wm8960-capture", + .stream_name = "wm8960-capture", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture), + }, + /* BE */ + { + .name = "wm8960-codec", + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + 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), + }, +}; + +static struct snd_soc_card mt7986_wm8960_card = { + .name = "mt7986-wm8960", + .owner = THIS_MODULE, + .dai_link = mt7986_wm8960_dai_links, + .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links), + .controls = mt7986_wm8960_controls, + .num_controls = ARRAY_SIZE(mt7986_wm8960_controls), + .dapm_widgets = mt7986_wm8960_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets), +}; + +static int mt7986_wm8960_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt7986_wm8960_card; + struct snd_soc_dai_link *dai_link; + struct device_node *platform, *codec; + struct mt7986_wm8960_priv *priv; + int ret, i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform = of_get_child_by_name(pdev->dev.of_node, "platform"); + + if (platform) { + priv->platform_node = of_parse_phandle(platform, "sound-dai", 0); + of_node_put(platform); + + if (!priv->platform_node) { + dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n"); + return -EINVAL; + } + } else { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platforms->name) + continue; + dai_link->platforms->of_node = priv->platform_node; + } + + card->dev = &pdev->dev; + + codec = of_get_child_by_name(pdev->dev.of_node, "codec"); + + if (codec) { + priv->codec_node = of_parse_phandle(codec, "sound-dai", 0); + of_node_put(codec); + + if (!priv->codec_node) { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n"); + return -EINVAL; + } + } else { + of_node_put(priv->platform_node); + dev_err(&pdev->dev, "Property 'codec' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codecs->name) + continue; + dai_link->codecs->of_node = priv->codec_node; + } + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret); + goto err_of_node_put; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret); + goto err_of_node_put; + } + +err_of_node_put: + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); + return ret; +} + +static void mt7986_wm8960_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card); + + of_node_put(priv->codec_node); + of_node_put(priv->platform_node); +} + +static const struct of_device_id mt7986_wm8960_machine_dt_match[] = { + {.compatible = "mediatek,mt7986-wm8960-sound"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match); + +static struct platform_driver mt7986_wm8960_machine = { + .driver = { + .name = "mt7986-wm8960", + .of_match_table = mt7986_wm8960_machine_dt_match, + }, + .probe = mt7986_wm8960_machine_probe, + .remove_new = mt7986_wm8960_machine_remove, +}; + +module_platform_driver(mt7986_wm8960_machine); + +/* Module information */ +MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver"); +MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mt7986 wm8960 soc card"); diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index c2b0619b6158..bfb2094758ff 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -70,7 +70,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; /* enable jack detection */ - ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE, + ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET, &mt8173_max98090_jack, mt8173_max98090_jack_pins, ARRAY_SIZE(mt8173_max98090_jack_pins)); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index f803f121659d..e502cd1670ba 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -40,6 +40,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -82,11 +93,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) RT5645_CLK_SEL_I2S1_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5514_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5514_jack, + mt8173_rt5650_rt5514_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 8794720cea3a..ffb094284bfb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -44,6 +44,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -95,11 +106,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime) RT5677_CLK_SEL_I2S2_ASRC); /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_rt5676_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5676_jack, + mt8173_rt5650_rt5676_jack_pins, + ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 3ece4b5eaca2..18cf84bb25c7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -54,6 +54,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), }; +static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -128,11 +139,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) } /* enable jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &mt8173_rt5650_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_jack, + mt8173_rt5650_jack_pins, + ARRAY_SIZE(mt8173_rt5650_jack_pins)); if (ret) { dev_err(card->dev, "Can't new Headset Jack %d\n", ret); return ret; diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 87bb04846991..701fbcc0f2c9 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -29,6 +29,21 @@ struct mt8183_da7219_max98357_priv { struct snd_soc_jack headset_jack, hdmi_jack; }; +static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, +}; + static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -572,13 +587,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_LINEOUT, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_LINEOUT, + &priv->headset_jack, + mt8183_da7219_max98357_jack_pins, + ARRAY_SIZE(mt8183_da7219_max98357_jack_pins)); if (ret) return ret; @@ -609,12 +626,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_SPK("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; @@ -657,14 +680,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL", "aud_tdm_out_on", "aud_tdm_out_off"), }; diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index ce9aedde7e1e..850f4d949d97 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -592,11 +592,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { }, }; +static const +struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const +struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .name = "mt8183_mt6358_ts3a227_max98357", .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { @@ -604,6 +631,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = { @@ -624,6 +655,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = { .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), .codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf, .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { @@ -631,6 +666,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), + .controls = mt8183_mt6358_ts3a227_max98357_snd_controls, + .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls), + .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets), }; static int @@ -641,12 +680,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(component->card, - "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(component->card, + "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &priv->headset_jack, + mt8183_mt6358_ts3a227_max98357_jack_pins, + ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins)); if (ret) return ret; diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c index 539e3a023bc4..70ec101890d3 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -13,8 +13,6 @@ #include "mt8186-afe-clk.h" #include "mt8186-audsys-clk.h" -static DEFINE_MUTEX(mutex_request_dram); - static const char *aud_clks[CLK_NUM] = { [CLK_AFE] = "aud_afe_clk", [CLK_DAC] = "aud_dac_clk", diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index a868a04ed4e7..b86159f70a33 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -2815,7 +2815,6 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8186_afe_private *afe_priv; - struct resource *res; struct reset_control *rstc; struct device *dev = &pdev->dev; int i, ret, irq_id; @@ -2836,8 +2835,7 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c index 0432f9d89020..aa8e00bba19b 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c @@ -46,6 +46,10 @@ static struct snd_soc_jack_pin mt8186_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = { @@ -964,6 +968,7 @@ mt8186_mt6366_da7219_max98357_widgets[] = { SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_OUTPUT("HDMI1"), SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -996,6 +1001,7 @@ mt8186_mt6366_da7219_max98357_controls[] = { SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("HDMI1"), }; diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index 6a24b339444b..5e14655c5617 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_platform.h> +#include <linux/of_reserved_mem.h> #include <linux/pm_runtime.h> #include <linux/soc/mediatek/infracfg.h> #include <linux/reset.h> @@ -3193,11 +3194,15 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8188_afe_private *afe_priv; - struct device *dev; + struct device *dev = &pdev->dev; struct reset_control *rstc; struct regmap *infra_ao; int i, irq_id, ret; + ret = of_reserved_mem_device_init(dev); + if (ret) + dev_dbg(dev, "failed to assign memory region: %d\n", ret); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); if (ret) return ret; @@ -3213,7 +3218,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev) afe_priv = afe->platform_priv; afe->dev = &pdev->dev; - dev = afe->dev; afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index ac69c23e0da1..7c9e08e6a4f5 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -723,6 +723,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback2), }, [DAI_LINK_DL3_FE] = { @@ -734,6 +737,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback3), }, [DAI_LINK_DL6_FE] = { @@ -745,6 +751,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(playback6), }, [DAI_LINK_DL7_FE] = { @@ -833,6 +842,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(capture4), }, [DAI_LINK_UL5_FE] = { @@ -844,6 +856,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, + .dpcm_merged_chan = 1, + .dpcm_merged_rate = 1, + .dpcm_merged_format = 1, SND_SOC_DAILINK_REG(capture5), }, [DAI_LINK_UL6_FE] = { diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index eedb9165f911..fd4f9f8f032d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_etdm_cal_mclk(afe, freq, dai->id); } -static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { - .startup = mtk_dai_etdm_startup, - .shutdown = mtk_dai_etdm_shutdown, - .hw_params = mtk_dai_etdm_hw_params, - .trigger = mtk_dai_etdm_trigger, - .set_sysclk = mtk_dai_etdm_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, - .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, -}; - -static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { - .startup = mtk_dai_hdmitx_dptx_startup, - .shutdown = mtk_dai_hdmitx_dptx_shutdown, - .hw_params = mtk_dai_hdmitx_dptx_hw_params, - .trigger = mtk_dai_hdmitx_dptx_trigger, - .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, - .set_fmt = mtk_dai_etdm_set_fmt, -}; - /* dai driver */ #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000) @@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = { + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_hdmitx_dptx_startup, + .shutdown = mtk_dai_hdmitx_dptx_shutdown, + .hw_params = mtk_dai_hdmitx_dptx_hw_params, + .trigger = mtk_dai_hdmitx_dptx_trigger, + .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, +}; + +static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { + .probe = mtk_dai_etdm_probe, + .startup = mtk_dai_etdm_startup, + .shutdown = mtk_dai_etdm_shutdown, + .hw_params = mtk_dai_etdm_hw_params, + .trigger = mtk_dai_etdm_trigger, + .set_sysclk = mtk_dai_etdm_set_sysclk, + .set_fmt = mtk_dai_etdm_set_fmt, + .set_tdm_slot = mtk_dai_etdm_set_tdm_slot, +}; + static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { { .name = "DPTX", @@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_IN", @@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM1_OUT", @@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM2_OUT", @@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .formats = MTK_ETDM_FORMATS, }, .ops = &mtk_dai_etdm_ops, - .probe = mtk_dai_etdm_probe, }, { .name = "ETDM3_OUT", @@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { .rates = MTK_ETDM_RATES, .formats = MTK_ETDM_FORMATS, }, - .ops = &mtk_dai_hdmitx_dptx_ops, - .probe = mtk_dai_etdm_probe, + .ops = &mtk_dai_hdmitx_dptx_ops2, }, }; diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index d0f0ada5f4bc..7b04b97f7b41 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = aiu_acodec_ctrl_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = { .name = "ACODEC CTRL " xname, \ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \ .ops = &aiu_acodec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_ACODEC_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 84c10956c241..ee0ef6301010 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { }; static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = { .name = "CODEC CTRL " xname, \ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \ .ops = &aiu_codec_ctrl_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define AIU_CODEC_CTRL_OUTPUT(xname) { \ diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 59e00a74b5f8..7d833500c799 100644 --- a/sound/soc/meson/aiu-fifo-i2s.c +++ b/sound/soc/meson/aiu-fifo-i2s.c @@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_i2s_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = aiu_fifo_i2s_trigger, .prepare = aiu_fifo_i2s_prepare, .hw_params = aiu_fifo_i2s_hw_params, diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index ddbd2fc40185..fa91f3c53fa4 100644 --- a/sound/soc/meson/aiu-fifo-spdif.c +++ b/sound/soc/meson/aiu-fifo-spdif.c @@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream, } const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = { + .pcm_new = aiu_fifo_pcm_new, + .probe = aiu_fifo_spdif_dai_probe, + .remove = aiu_fifo_dai_remove, .trigger = fifo_spdif_trigger, .prepare = fifo_spdif_prepare, .hw_params = fifo_spdif_hw_params, diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index da351a60df0c..7109b81cc3d0 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_i2s_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_i2s_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_SPDIF_FIFO] = { .name = "SPDIF FIFO", @@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_fifo_spdif_dai_ops, - .pcm_new = aiu_fifo_pcm_new, - .probe = aiu_fifo_spdif_dai_probe, - .remove = aiu_fifo_dai_remove, }, [CPU_I2S_ENCODER] = { .name = "I2S Encoder", diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 61f9d417fd60..8c166a5f338c 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver axg_frddr_dai_drv = { @@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static const char * const axg_frddr_sel_texts[] = { @@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = { .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, + .pcm_new = axg_frddr_pcm_new, }; static struct snd_soc_dai_driver g12a_frddr_dai_drv = { @@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_frddr_ops, - .pcm_new = axg_frddr_pcm_new, }; static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index ad43cb2a1e3f..d59050914d3c 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(priv->dclk); } -static const struct snd_soc_dai_ops axg_pdm_dai_ops = { - .trigger = axg_pdm_trigger, - .hw_params = axg_pdm_hw_params, - .startup = axg_pdm_startup, - .shutdown = axg_pdm_shutdown, -}; - static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) { const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; @@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops axg_pdm_dai_ops = { + .probe = axg_pdm_dai_probe, + .remove = axg_pdm_dai_remove, + .trigger = axg_pdm_trigger, + .hw_params = axg_pdm_hw_params, + .startup = axg_pdm_startup, + .shutdown = axg_pdm_shutdown, +}; + static struct snd_soc_dai_driver axg_pdm_dai_drv = { .name = "PDM", .capture = { @@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = { SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &axg_pdm_dai_ops, - .probe = axg_pdm_dai_probe, - .remove = axg_pdm_dai_remove, }; static const struct snd_soc_component_driver axg_pdm_component_drv = { diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index e2cc4c4be758..d86880169075 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_spdifin_ops = { + .probe = axg_spdifin_dai_probe, + .remove = axg_spdifin_dai_remove, .prepare = axg_spdifin_prepare, .startup = axg_spdifin_startup, .shutdown = axg_spdifin_shutdown, @@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) drv->name = "SPDIF Input"; drv->ops = &axg_spdifin_ops; - drv->probe = axg_spdifin_dai_probe; - drv->remove = axg_spdifin_dai_remove; drv->capture.stream_name = "Capture"; drv->capture.channels_min = 1; drv->capture.channels_max = 2; diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 9883dc777f63..63333a2b0a9c 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -30,27 +30,32 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, struct axg_tdm_stream *ts, unsigned int offset) { - unsigned int val, ch = ts->channels; - unsigned long mask; - int i, j; + unsigned int ch = ts->channels; + u32 val[AXG_TDM_NUM_LANES]; + int i, j, k; + + /* + * We need to mimick the slot distribution used by the HW to keep the + * channel placement consistent regardless of the number of channel + * in the stream. This is why the odd algorithm below is used. + */ + memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES); /* * Distribute the channels of the stream over the available slots - * of each TDM lane + * of each TDM lane. We need to go over the 32 slots ... */ - for (i = 0; i < AXG_TDM_NUM_LANES; i++) { - val = 0; - mask = ts->mask[i]; - - for (j = find_first_bit(&mask, 32); - (j < 32) && ch; - j = find_next_bit(&mask, 32, j + 1)) { - val |= 1 << j; - ch -= 1; + for (i = 0; (i < 32) && ch; i += 2) { + /* ... of all the lanes ... */ + for (j = 0; j < AXG_TDM_NUM_LANES; j++) { + /* ... then distribute the channels in pairs */ + for (k = 0; k < 2; k++) { + if ((BIT(i + k) & ts->mask[j]) && ch) { + val[j] |= BIT(i + k); + ch -= 1; + } + } } - - regmap_write(map, offset, val); - offset += regmap_get_reg_stride(map); } /* @@ -63,6 +68,11 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map, return -EINVAL; } + for (i = 0; i < AXG_TDM_NUM_LANES; i++) { + regmap_write(map, offset, val[i]); + offset += regmap_get_reg_stride(map); + } + return 0; } EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 5e5e4c56d505..1c3d433cefd2 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops axg_tdm_iface_ops = { + .probe = axg_tdm_iface_probe_dai, + .remove = axg_tdm_iface_remove_dai, .set_sysclk = axg_tdm_iface_set_sysclk, .set_fmt = axg_tdm_iface_set_fmt, .startup = axg_tdm_iface_startup, @@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_PAD, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, [TDM_IFACE_LOOPBACK] = { .name = "TDM Loopback", @@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { }, .id = TDM_IFACE_LOOPBACK, .ops = &axg_tdm_iface_ops, - .probe = axg_tdm_iface_probe_dai, - .remove = axg_tdm_iface_remove_dai, }, }; diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index e9208e74e965..1a0be177b8fe 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = axg_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver axg_toddr_dai_drv = { @@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &axg_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const char * const axg_toddr_sel_texts[] = { @@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = { .hw_params = axg_toddr_dai_hw_params, .startup = g12a_toddr_dai_startup, .shutdown = axg_toddr_dai_shutdown, + .pcm_new = axg_toddr_pcm_new, }; static struct snd_soc_dai_driver g12a_toddr_dai_drv = { @@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = { .formats = AXG_FIFO_FORMATS, }, .ops = &g12a_toddr_ops, - .pcm_new = axg_toddr_pcm_new, }; static const struct snd_soc_component_driver g12a_toddr_component_drv = { diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index ddc667956cf5..6c4503766fdc 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops g12a_toacodec_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = g12a_toacodec_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = { .id = (xid), \ .playback = TOACODEC_STREAM(xname, "Playback", 8), \ .ops = &g12a_toacodec_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOACODEC_OUTPUT(xname, xid) { \ diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 579a04ad4d19..f7ef9aa1eed8 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .probe = meson_codec_glue_input_dai_probe, + .remove = meson_codec_glue_input_dai_remove, .hw_params = meson_codec_glue_input_hw_params, .set_fmt = meson_codec_glue_input_set_fmt, }; @@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { .id = (xid), \ .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ .ops = &g12a_tohdmitx_input_ops, \ - .probe = meson_codec_glue_input_dai_probe, \ - .remove = meson_codec_glue_input_dai_remove, \ } #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index a1ed141b8795..abfaf3cdf5bb 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { + .probe = mmp_sspa_probe, .startup = mmp_sspa_startup, .shutdown = mmp_sspa_shutdown, .trigger = mmp_sspa_trigger, @@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = { }; static struct snd_soc_dai_driver mmp_sspa_dai = { - .probe = mmp_sspa_probe, .playback = { .channels_min = 1, .channels_max = 128, diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 430dd446321e..b70034c07eee 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (ret < 0) { const struct pxa_ssp_clock_mode *m; - int ssacd, acds; + int ssacd; for (m = pxa_ssp_clock_modes; m->rate; m++) { if (m->rate == rate) @@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if (!m->rate) return -EINVAL; - acds = m->acds; - - /* The values in the table are for 16 bits */ - if (width == 32) - acds--; - ret = pxa_ssp_set_pll(priv, bclk); if (ret < 0) return ret; @@ -819,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, .startup = pxa_ssp_startup, .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, @@ -830,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { }; static struct snd_soc_dai_driver pxa_ssp_dai = { - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, .playback = { .channels_min = 1, .channels_max = 8, diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 3e4c70403672..10636506b622 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -370,18 +370,11 @@ static const struct snd_soc_component_driver pxa_i2s_component = { static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *res; - if (!res) { - dev_err(&pdev->dev, "missing MMIO resource\n"); - return -ENXIO; - } - - i2s_reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(i2s_reg_base)) { - dev_err(&pdev->dev, "ioremap failed\n"); + i2s_reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(i2s_reg_base)) return PTR_ERR(i2s_reg_base); - } pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR; pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR; diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index e54b8961112f..6de533d45e7d 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -44,6 +44,17 @@ struct apq8016_sbc_data { #define DEFAULT_MCLK_RATE 9600000 #define MI2S_BCLK_RATE 1536000 +static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) { struct snd_soc_dai *codec_dai; @@ -90,13 +101,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) if (!pdata->jack_setup) { struct snd_jack *jack; - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4, + &pdata->jack, + apq8016_sbc_jack_pins, + ARRAY_SIZE(apq8016_sbc_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -255,8 +268,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card) } } -static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { +static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; +static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("Handset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Secondary Mic", NULL), @@ -285,6 +304,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dapm_widgets = apq8016_sbc_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets); + card->controls = apq8016_sbc_snd_controls; + card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls); ret = qcom_snd_parse_of(card); if (ret) diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index abaf694ee9a3..f919d46e18ca 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_SECONDARY] = { @@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_TERTIARY] = { @@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, [MI2S_QUATERNARY] = { @@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, }; diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index dbdaaa85ce48..39571fed4001 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { - .set_sysclk = lpass_cpu_daiops_set_sysclk, - .startup = lpass_cpu_daiops_startup, - .shutdown = lpass_cpu_daiops_shutdown, - .hw_params = lpass_cpu_daiops_hw_params, - .trigger = lpass_cpu_daiops_trigger, - .prepare = lpass_cpu_daiops_prepare, -}; -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); - -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { int ret; struct snd_soc_dai_driver *drv = dai->driver; @@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } -EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) +static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; @@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) return ret; } -EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); + +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = { + .pcm_new = lpass_cpu_daiops_pcm_new, + .probe = lpass_cpu_daiops_probe, + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .trigger = lpass_cpu_daiops_trigger, + .prepare = lpass_cpu_daiops_prepare, +}; +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2); static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index ef8a7984f232..2c97f295e394 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .channels_min = 1, .channels_max = 8, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 56db852f4eab..d16c0d83aaad 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, - .ops = &asoc_qcom_lpass_cpu_dai_ops, - .pcm_new = lpass_cpu_pcm_new, + .ops = &asoc_qcom_lpass_cpu_dai_ops2, }, { .id = LPASS_DP_RX, .name = "Hdmi", diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index bcf18fe8e14d..6b2eb25ed939 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = MI2S_SECONDARY, @@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = { .channels_min = 2, .channels_max = 2, }, - .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, }, { .id = LPASS_DP_RX, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index dd78600fc7b0..bdfe66ec3314 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); -int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; -int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai); +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2; extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops; #endif /* __LPASS_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index dbff55a97162..3faa7e0eb0dd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, }; -static const struct snd_soc_dai_ops q6hdmi_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6hdmi_hw_params, - .shutdown = q6afe_dai_shutdown, -}; - -static const struct snd_soc_dai_ops q6i2s_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6i2s_hw_params, - .set_fmt = q6i2s_set_fmt, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, -}; - -static const struct snd_soc_dai_ops q6slim_ops = { - .prepare = q6afe_dai_prepare, - .hw_params = q6slim_hw_params, - .shutdown = q6afe_dai_shutdown, - .set_channel_map = q6slim_set_channel_map, -}; - -static const struct snd_soc_dai_ops q6tdm_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_tdm_slot = q6tdm_set_tdm_slot, - .set_channel_map = q6tdm_set_channel_map, - .hw_params = q6tdm_hw_params, -}; - -static const struct snd_soc_dai_ops q6dma_ops = { - .prepare = q6afe_dai_prepare, - .shutdown = q6afe_dai_shutdown, - .set_sysclk = q6afe_mi2s_set_sysclk, - .set_channel_map = q6dma_set_channel_map, - .hw_params = q6dma_hw_params, -}; - static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) { struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops q6hdmi_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static const struct snd_soc_dai_ops q6i2s_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static const struct snd_soc_dai_ops q6slim_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static const struct snd_soc_dai_ops q6tdm_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_tdm_slot = q6tdm_set_tdm_slot, + .set_channel_map = q6tdm_set_channel_map, + .hw_params = q6tdm_hw_params, +}; + +static const struct snd_soc_dai_ops q6dma_ops = { + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .prepare = q6afe_dai_prepare, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, +}; + static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev) dev_set_drvdata(dev, dai_data); of_q6afe_parse_dai_data(dev, dai_data); - cfg.probe = msm_dai_q6_dai_probe; - cfg.remove = msm_dai_q6_dai_remove; cfg.q6hdmi_ops = &q6hdmi_ops; cfg.q6slim_ops = &q6slim_ops; cfg.q6i2s_ops = &q6i2s_ops; diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 5d44d07acd69..2a2a5bd98110 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -27,7 +27,7 @@ struct apm_graph_mgmt_cmd { #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8) -struct q6apm *g_apm; +static struct q6apm *g_apm; int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode) { diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index 8ee40732ce9e..f486bd639b9f 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -126,7 +126,6 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph, struct audioreach_module_config *cfg); /* read/write related */ -int q6apm_send_eos_nowait(struct q6apm_graph *graph); int q6apm_read(struct q6apm_graph *graph); int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags); @@ -144,7 +143,6 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, /* Callback for graph specific */ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid); -void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv); int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph); bool q6apm_is_adsp_ready(void); diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 5fc8088e63c8..fe0666e9fd23 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = { Q6ASM_FEDAI_DRIVER(8), }; +static const struct snd_soc_dai_ops q6asm_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int of_q6asm_parse_dai_data(struct device *dev, struct q6asm_dai_data *pdata) { @@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev, dai_drv->playback = empty_stream; if (of_property_read_bool(node, "is-compress-dai")) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &q6asm_dai_ops; } return 0; diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index ac937a6bf909..4919001de08b 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, int i; for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) { - q6dsp_audio_fe_dais[i].probe = cfg->probe; - q6dsp_audio_fe_dais[i].remove = cfg->remove; - switch (q6dsp_audio_fe_dais[i].id) { case HDMI_RX: case DISPLAY_PORT_RX: diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index f5f7c64b23a2..57c5f35dfcc5 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -42,6 +42,17 @@ static void sc7180_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7180_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -51,13 +62,14 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) struct snd_jack *jack; int rval; - rval = snd_soc_card_jack_new( - card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->hs_jack, + sc7180_jack_pins, + ARRAY_SIZE(sc7180_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -297,6 +309,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7180_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = { SND_SOC_DAPM_MIC("DMIC", NULL), }; @@ -320,6 +337,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = { SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control), }; +static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { {"Dmic Mux", "Front Mic", "DMIC"}, {"Dmic Mux", "Rear Mic", "DMIC"}, @@ -348,10 +370,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) card->dev = dev; card->dapm_widgets = sc7180_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); + card->controls = sc7180_snd_controls; + card->num_controls = ARRAY_SIZE(sc7180_snd_controls); if (of_property_read_bool(dev->of_node, "dmic-gpios")) { card->dapm_widgets = sc7180_snd_dual_mic_widgets, card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets), + card->controls = sc7180_snd_dual_mic_controls, + card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls), card->dapm_routes = sc7180_snd_dual_mic_audio_route, card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route), data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index 787dd49e03f6..43010e4e2242 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -43,6 +43,17 @@ static void sc7280_jack_free(struct snd_jack *jack) snd_soc_component_set_jack(component, NULL, NULL); } +static struct snd_soc_jack_pin sc7280_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -54,13 +65,15 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) int rval, i; if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &pdata->hs_jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &pdata->hs_jack, + sc7280_jack_pins, + ARRAY_SIZE(sc7280_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headset Jack\n"); @@ -361,6 +374,11 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_kcontrol_new sc7280_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -396,6 +414,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev) card->dapm_widgets = sc7280_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); + card->controls = sc7280_snd_controls; + card->num_controls = ARRAY_SIZE(sc7280_snd_controls); ret = qcom_snd_parse_of(card); if (ret) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 02612af714a8..29d23fe5dfa2 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -42,6 +42,17 @@ struct sdm845_snd_data { struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; }; +static struct snd_soc_jack_pin sdm845_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, @@ -242,12 +253,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) if (!pdata->jack_setup) { - rval = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | - SND_JACK_HEADPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pdata->jack); + rval = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->jack, + sdm845_jack_pins, + ARRAY_SIZE(sdm845_jack_pins)); if (rval < 0) { dev_err(card->dev, "Unable to add Headphone Jack\n"); @@ -539,6 +552,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), }; +static const struct snd_kcontrol_new sdm845_snd_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static void sdm845_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -572,6 +590,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) card->driver_name = DRIVER_NAME; card->dapm_widgets = sdm845_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets); + card->controls = sdm845_snd_controls; + card->num_controls = ARRAY_SIZE(sdm845_snd_controls); card->dev = dev; card->owner = THIS_MODULE; dev_set_drvdata(dev, card); diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 5e52e9d60d44..0f704d22d21b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -41,13 +41,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, - + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_LINE("HDMI", NULL), }; @@ -56,6 +60,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Line Out"), SOC_DAPM_PIN_SWITCH("Int Mic"), SOC_DAPM_PIN_SWITCH("HDMI"), }; diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 575a0b9b01e9..834fbb5cf810 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { + .probe = rockchip_i2s_dai_probe, .hw_params = rockchip_i2s_hw_params, .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, .set_sysclk = rockchip_i2s_set_sysclk, @@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { }; static struct snd_soc_dai_driver rockchip_i2s_dai = { - .probe = rockchip_i2s_dai_probe, .ops = &rockchip_i2s_dai_ops, .symmetric_rate = 1, }; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 166257c6ae14..d3700f3c98e6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { + .probe = rockchip_i2s_tdm_dai_probe, .hw_params = rockchip_i2s_tdm_hw_params, .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, .set_sysclk = rockchip_i2s_tdm_set_sysclk, @@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = { }; static const struct snd_soc_dai_driver i2s_tdm_dai = { - .probe = rockchip_i2s_tdm_dai_probe, .ops = &rockchip_i2s_tdm_dai_ops, }; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 52f9aae60be8..4756cfc23218 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { + .probe = rockchip_pdm_dai_probe, .set_fmt = rockchip_pdm_set_fmt, .trigger = rockchip_pdm_trigger, .hw_params = rockchip_pdm_hw_params, @@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver rockchip_pdm_dai = { - .probe = rockchip_pdm_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 2, @@ -584,7 +584,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) match = of_match_device(rockchip_pdm_match, &pdev->dev); if (match) - pdm->version = (enum rk_pdm_version)match->data; + pdm->version = (uintptr_t)match->data; if (pdm->version == RK_PDM_RK3308) { pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m"); diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index e73a342b7953..ef9fdf0386cb 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -22,6 +22,16 @@ #define DRV_NAME "rockchip-snd-rt5645" static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), @@ -103,11 +113,13 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) int ret; /* Enable Headset and 4 Buttons Jack detection */ - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) { dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); return ret; diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 0b73fe94e4bb..1a24b78e9e02 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops rk_spdif_dai_ops = { + .probe = rk_spdif_dai_probe, .hw_params = rk_spdif_hw_params, .trigger = rk_spdif_trigger, }; static struct snd_soc_dai_driver rk_spdif_dai = { - .probe = rk_spdif_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 7492bb41456c..dd3cd2c9644a 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -620,10 +620,14 @@ static int aries_audio_probe(struct platform_device *pdev) /* Update card-name if provided through DT, else use default name */ snd_soc_of_parse_card_name(card, "model"); - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f3d98abd5f0d..3af48c9b5ab7 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { + .probe = samsung_i2s_dai_probe, + .remove = samsung_i2s_dai_remove, .trigger = i2s_trigger, .hw_params = i2s_hw_params, .set_fmt = i2s_set_fmt, @@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, for (i = 0; i < num_dais; i++) { dai_drv = &priv->dai_drv[i]; - dai_drv->probe = samsung_i2s_dai_probe; - dai_drv->remove = samsung_i2s_dai_remove; - dai_drv->symmetric_rate = 1; dai_drv->ops = &samsung_i2s_dai_ops; diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 5d8118e69359..fafadcef234e 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -225,12 +225,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, } static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_HP("Headset Mic", NULL), SND_SOC_DAPM_MIC("AMIC", NULL), SND_SOC_DAPM_MIC("DMIC", NULL), @@ -255,6 +258,16 @@ static const struct snd_soc_dapm_route audio_paths[] = { }; static struct snd_soc_jack littlemill_headset; +static struct snd_soc_jack_pin littlemill_headset_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; static int littlemill_late_probe(struct snd_soc_card *card) { @@ -281,12 +294,14 @@ static int littlemill_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &littlemill_headset); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &littlemill_headset, + littlemill_headset_pins, + ARRAY_SIZE(littlemill_headset_pins)); if (ret) return ret; diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 106770be6fc5..a79df871ea13 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -22,12 +22,16 @@ static struct snd_soc_jack lowland_headset; static struct snd_soc_jack_pin lowland_headset_pins[] = { { .pin = "Headphone", - .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, + .mask = SND_JACK_HEADPHONE, }, { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE, }, + { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, + }, }; static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) @@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("WM1250 Input"), SOC_DAPM_PIN_SWITCH("WM1250 Output"), SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Line Out"), }; static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Main Speaker", NULL), diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index 6931b9a45b3e..2ec7e16ddfa2 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -38,6 +38,17 @@ struct midas_priv { struct snd_soc_jack headset_jack; }; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate) { struct snd_soc_card *card = rtd->card; @@ -261,6 +272,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { SND_SOC_DAPM_LINE("HDMI", NULL), SND_SOC_DAPM_LINE("FM In", midas_fm_set), + SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias), SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias), @@ -305,11 +317,13 @@ static int midas_late_probe(struct snd_soc_card *card) return ret; } - ret = snd_soc_card_jack_new(card, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, - &priv->headset_jack); + ret = snd_soc_card_jack_new_pins(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, + &priv->headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); if (ret) return ret; @@ -462,10 +476,14 @@ static int midas_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing invalid/unspecified\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing invalid/unspecified\n"); + return ret; + } } cpu = of_get_child_by_name(dev->of_node, "cpu"); diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index a5442592bde4..c93cb5a86426 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -223,19 +223,20 @@ static int odroid_audio_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { + if (of_property_present(dev->of_node, "samsung,audio-widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(card, "samsung,audio-widgets"); if (ret < 0) return ret; } - if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { - ret = snd_soc_of_parse_audio_routing(card, - "samsung,audio-routing"); - if (ret < 0) - return ret; - } + ret = 0; + if (of_property_present(dev->of_node, "audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + else if (of_property_present(dev->of_node, "samsung,audio-routing")) + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) + return ret; card->dai_link = odroid_card_dais; card->num_links = ARRAY_SIZE(odroid_card_dais); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 335fe5cb9cfc..d2cdc5c8e05b 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { - .set_sysclk = s3c_pcm_set_sysclk, - .set_clkdiv = s3c_pcm_set_clkdiv, - .trigger = s3c_pcm_trigger, - .hw_params = s3c_pcm_hw_params, - .set_fmt = s3c_pcm_set_fmt, -}; - static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) { struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai); @@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .probe = s3c_pcm_dai_probe, + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_DAI_DECLARE \ .symmetric_rate = 1, \ - .probe = s3c_pcm_dai_probe, \ .ops = &s3c_pcm_dai_ops, \ .playback = { \ .channels_min = 2, \ diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index d611ec9e5325..5ebf17f3de1e 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev) return ret; } - ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); if (ret < 0) { - dev_err(dev, "Audio routing is not specified or invalid\n"); - return ret; + /* Backwards compatible way */ + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing is not specified or invalid\n"); + return ret; + } } card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 6a522e6dd85a..e29c2fee9521 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = { SND_SOC_POSSIBLE_DAIFMT_DSP_B, }; -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) @@ -1260,13 +1249,13 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name return i; } -static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, - int *is_graph) +static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct device_node *dai_node; - struct device_node *ret; + struct device_node *ports, *node; + int nr = 0; + int i = 0; *is_graph = 0; @@ -1274,26 +1263,53 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, * parse both previous dai (= rcar_sound,dai), and * graph dai (= ports/port) */ - dai_node = of_get_child_by_name(np, RSND_NODE_DAI); - if (dai_node) { - ret = dai_node; - goto of_node_compatible; - } - ret = np; + /* + * Simple-Card + */ + node = of_get_child_by_name(np, RSND_NODE_DAI); + if (!node) + goto audio_graph; - dai_node = of_graph_get_next_endpoint(np, NULL); - if (dai_node) - goto of_node_graph; + of_node_put(node); - return NULL; + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; + + priv->component_dais[i] = of_get_child_count(node); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + of_node_put(node); + break; + } + } + + return nr; + +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")) + continue; + priv->component_dais[i] = of_graph_get_endpoint_count(ports); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + of_node_put(node); + break; + } + } -of_node_graph: *is_graph = 1; -of_node_compatible: - of_node_put(dai_node); - return ret; + return nr; } @@ -1328,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, return 0; } -static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) +static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); int ret; @@ -1355,8 +1370,22 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .pcm_new = rsnd_soc_dai_pcm_new, + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, + .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), +}; + static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, + struct device_node *node_np, + uint32_t node_arg, int dai_i) { struct rsnd_dai_stream *io_playback; @@ -1374,10 +1403,16 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + /* for multi Component */ + rdai->dai_args.np = node_np; + rdai->dai_args.args_count = 1; + rdai->dai_args.args[0] = node_arg; + rdai->priv = priv; drv->name = rdai->name; drv->ops = &rsnd_soc_dai_ops; - drv->pcm_new = rsnd_pcm_new; + drv->id = dai_i; + drv->dai_args = &rdai->dai_args; io_playback->rdai = rdai; io_capture->rdai = rdai; @@ -1441,21 +1476,15 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, static int rsnd_dai_probe(struct rsnd_priv *priv) { - struct device_node *dai_node; - struct device_node *dai_np; struct snd_soc_dai_driver *rdrv; struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; struct rsnd_dai *rdai; - int nr; + int nr = 0; int is_graph; int dai_i; - dai_node = rsnd_dai_of_node(priv, &is_graph); - if (is_graph) - nr = of_graph_get_endpoint_count(dai_node); - else - nr = of_get_child_count(dai_node); - + nr = rsnd_dai_of_node(priv, &is_graph); if (!nr) return -EINVAL; @@ -1473,26 +1502,42 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) */ dai_i = 0; if (is_graph) { - for_each_endpoint_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); - rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + 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")) + continue; + for_each_endpoint_of_node(ports, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } else { - for_each_child_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); + struct device_node *node; + struct device_node *dai_np; + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; - rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); - rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + for_each_child_of_node(node, dai_np) { + __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); + if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + } + dai_i++; } - dai_i++; } } @@ -1922,6 +1967,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_dai_probe, }; int ret, i; + int ci; /* * init priv data @@ -1958,11 +2004,18 @@ static int rsnd_probe(struct platform_device *pdev) /* * asoc register */ - ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, - priv->daidrv, rsnd_rdai_nr(priv)); - if (ret < 0) { - dev_err(dev, "cannot snd dai register\n"); - goto exit_snd_probe; + ci = 0; + for (i = 0; priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, + priv->daidrv + ci, nr); + if (ret < 0) { + dev_err(dev, "cannot snd component register\n"); + goto exit_snd_probe; + } + + ci += nr; } pm_runtime_enable(dev); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 239705d52517..43c0d675cc34 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -545,6 +545,7 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; struct snd_pcm_hw_constraint_list constraint; + struct of_phandle_args dai_args; int max_channels; /* 2ch - 16ch */ int ssi_lane; /* 1lane - 4lane */ @@ -702,6 +703,9 @@ struct rsnd_priv { struct snd_soc_dai_driver *daidrv; struct rsnd_dai *rdai; int rdai_nr; + +#define RSND_MAX_COMPONENT 3 + int component_dais[RSND_MAX_COMPONENT]; }; #define rsnd_priv_to_pdev(priv) ((priv)->pdev) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 142476f1396f..6d693b2ad5a3 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -125,5 +125,78 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) } EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); +#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ + SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) + +/* 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) +{ + unsigned int part_id, link_id, unique_id, mfg_id, version; + int i, j, k; + + for (i = 0; i < link->num_adr; i++) { + u64 adr = link->adr_d[i].adr; + int reported_part_count = 0; + + mfg_id = SDW_MFG_ID(adr); + part_id = SDW_PART_ID(adr); + link_id = SDW_DISCO_LINK_ID(adr); + version = SDW_VERSION(adr); + + for (j = 0; j < num_slaves; 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) + reported_part_count++; + } + + for (j = 0; j < num_slaves; 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) + continue; + + /* find out how many identical parts are expected */ + for (k = 0; k < link->num_adr; k++) { + u64 adr2 = link->adr_d[k].adr; + + if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) + expected_part_count++; + } + + if (reported_part_count == expected_part_count) { + /* + * we have to check unique id + * if there is more than one + * Slave on the link + */ + unique_id = SDW_UNIQUE_ID(adr); + if (reported_part_count == 1 || + ids[j].id.unique_id == unique_id) { + dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); + break; + } + } else { + dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n", + part_id, reported_part_count, expected_part_count, link_id); + } + } + if (j == num_slaves) { + dev_dbg(dev, "Slave part_id %#x not found\n", part_id); + return false; + } + } + return true; +} +EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ALSA SoC ACPI module"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a0bde23f5e6..a5b96c17633a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -238,6 +238,81 @@ static inline void snd_soc_debugfs_exit(void) { } #endif +static int snd_soc_is_match_dai_args(struct of_phandle_args *args1, + struct of_phandle_args *args2) +{ + if (!args1 || !args2) + return 0; + + if (args1->np != args2->np) + return 0; + + for (int i = 0; i < args1->args_count; i++) + if (args1->args[i] != args2->args[i]) + return 0; + + return 1; +} + +static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc) +{ + return !(dlc->dai_args || dlc->name || dlc->of_node); +} + +static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc) +{ + return (dlc->name && dlc->of_node); +} + +static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc) +{ + return !(dlc->dai_args || dlc->dai_name); +} + +static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, + struct snd_soc_dai *dai) +{ + if (!dlc) + return 0; + + if (dlc->dai_args) + return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args); + + if (!dlc->dai_name) + return 1; + + /* see snd_soc_dai_name_get() */ + + if (strcmp(dlc->dai_name, dai->name) == 0) + return 1; + + if (dai->driver->name && + strcmp(dai->driver->name, dlc->dai_name) == 0) + return 1; + + if (dai->component->name && + strcmp(dlc->dai_name, dai->component->name) == 0) + return 1; + + return 0; +} + +const char *snd_soc_dai_name_get(struct snd_soc_dai *dai) +{ + /* see snd_soc_is_matching_dai() */ + if (dai->name) + return dai->name; + + if (dai->driver->name) + return dai->driver->name; + + if (dai->component->name) + return dai->component->name; + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_name_get); + static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { @@ -734,6 +809,19 @@ static struct device_node return of_node; } +struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args) +{ + struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL); + + if (!ret) + return NULL; + + *ret = *args; + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args); + static int snd_soc_is_matching_component( const struct snd_soc_dai_link_component *dlc, struct snd_soc_component *component) @@ -743,6 +831,15 @@ static int snd_soc_is_matching_component( if (!dlc) return 0; + if (dlc->dai_args) { + struct snd_soc_dai *dai; + + for_each_component_dais(component, dai) + if (snd_soc_is_matching_dai(dlc, dai)) + return 1; + return 0; + } + component_of_node = soc_component_to_node(component); if (dlc->of_node && component_of_node != dlc->of_node) @@ -795,18 +892,11 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs */ - for_each_component(component) { - if (!snd_soc_is_matching_component(dlc, component)) - continue; - for_each_component_dais(component, dai) { - if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) - && (!dai->driver->name - || strcmp(dai->driver->name, dlc->dai_name))) - continue; - - return dai; - } - } + for_each_component(component) + if (snd_soc_is_matching_component(dlc, component)) + for_each_component_dais(component, dai) + if (snd_soc_is_matching_dai(dlc, dai)) + return dai; return NULL; } @@ -829,102 +919,100 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { int i; - struct snd_soc_dai_link_component *cpu, *codec, *platform; + struct snd_soc_dai_link_component *dlc; - for_each_link_codecs(link, i, codec) { + /* Codec check */ + for_each_link_codecs(link, i, dlc) { /* * Codec must be specified by 1 of name or OF node, * not both or neither. */ - if (!!codec->name == !!codec->of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; + + if (snd_soc_dlc_component_is_empty(dlc)) + goto component_empty; /* Codec DAI name must be specified */ - if (!codec->dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_dai_is_empty(dlc)) + goto dai_empty; /* * Defer card registration if codec component is not added to * component list. */ - if (!soc_find_component(codec)) { - dev_dbg(card->dev, - "ASoC: codec component %s not found for link %s\n", - codec->name, link->name); - return -EPROBE_DEFER; - } + if (!soc_find_component(dlc)) + goto component_not_find; } - for_each_link_platforms(link, i, platform) { + /* Platform check */ + for_each_link_platforms(link, i, dlc) { /* * Platform may be specified by either name or OF node, but it * can be left unspecified, then no components will be inserted * in the rtdcom list */ - if (!!platform->name == !!platform->of_node) { - dev_err(card->dev, - "ASoC: Neither/both platform name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; + + if (snd_soc_dlc_component_is_empty(dlc)) + goto component_empty; /* * Defer card registration if platform component is not added to * component list. */ - if (!soc_find_component(platform)) { - dev_dbg(card->dev, - "ASoC: platform component %s not found for link %s\n", - platform->name, link->name); - return -EPROBE_DEFER; - } + if (!soc_find_component(dlc)) + goto component_not_find; } - for_each_link_cpus(link, i, cpu) { + /* CPU check */ + for_each_link_cpus(link, i, dlc) { /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI * name alone.. */ - if (cpu->name && cpu->of_node) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } + if (snd_soc_dlc_component_is_invalid(dlc)) + goto component_invalid; - /* - * Defer card registration if cpu dai component is not added to - * component list. - */ - if ((cpu->of_node || cpu->name) && - !soc_find_component(cpu)) { - dev_dbg(card->dev, - "ASoC: cpu component %s not found for link %s\n", - cpu->name, link->name); - return -EPROBE_DEFER; - } - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified - */ - if (!cpu->dai_name && - !(cpu->name || cpu->of_node)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; + if (snd_soc_dlc_component_is_empty(dlc)) { + /* + * At least one of CPU DAI name or CPU device name/node must be specified + */ + if (snd_soc_dlc_dai_is_empty(dlc)) + goto component_dai_empty; + } else { + /* + * Defer card registration if Component is not added + */ + if (!soc_find_component(dlc)) + goto component_not_find; } } return 0; + +component_invalid: + dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name); + return -EINVAL; + +component_empty: + dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name); + return -EINVAL; + +component_not_find: + dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name); + return -EPROBE_DEFER; + +dai_empty: + dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name); + return -EINVAL; + +component_dai_empty: + dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name); + return -EINVAL; } /** @@ -2930,6 +3018,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); +void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus) +{ + platforms->of_node = cpus->of_node; + platforms->dai_args = cpus->dai_args; +} +EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform); + void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, @@ -3235,11 +3331,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu); int snd_soc_get_dai_id(struct device_node *ep) { struct snd_soc_component *component; - struct snd_soc_dai_link_component dlc; + struct snd_soc_dai_link_component dlc = { + .of_node = of_graph_get_port_parent(ep), + }; int ret; - dlc.of_node = of_graph_get_port_parent(ep); - dlc.name = NULL; + /* * For example HDMI case, HDMI has video/sound port, * but ALSA SoC needs sound port number only. @@ -3264,8 +3361,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ struct snd_soc_component *pos; int ret = -EPROBE_DEFER; - dlc->of_node = args->np; - mutex_lock(&client_mutex); for_each_component(pos) { struct device_node *component_of_node = soc_component_to_node(pos); @@ -3304,9 +3399,7 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ id--; } - dlc->dai_name = dai->driver->name; - if (!dlc->dai_name) - dlc->dai_name = pos->name; + dlc->dai_name = snd_soc_dai_name_get(dai); } else if (ret) { /* * if another error than ENOTSUPP is returned go on and @@ -3319,6 +3412,10 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_ break; } + + if (ret == 0) + dlc->of_node = args->np; + mutex_unlock(&client_mutex); return ret; } @@ -3370,6 +3467,24 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, } EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); +struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args) +{ + struct snd_soc_dai *dai; + struct snd_soc_component *component; + + mutex_lock(&client_mutex); + for_each_component(component) { + for_each_component_dais(component, dai) + if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args)) + goto found; + } + dai = NULL; +found: + mutex_unlock(&client_mutex); + return dai; +} +EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args); + static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component) { if (component->of_node) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 02dd64dea179..3f33f0630ad8 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -424,6 +424,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->startup) ret = dai->driver->ops->startup(substream, dai); @@ -439,6 +442,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, int rollback) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return; + if (rollback && !soc_dai_mark_match(dai, substream, startup)) return; @@ -454,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd, int num) { int ret = -ENOTSUPP; - if (dai->driver->compress_new) - ret = dai->driver->compress_new(rtd, num); + if (dai->driver->ops && + dai->driver->ops->compress_new) + ret = dai->driver->ops->compress_new(rtd, num); return soc_dai_ret(dai, ret); } @@ -539,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->probe_order != order) - continue; - if (dai->probed) continue; - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); + if (dai->driver->ops) { + if (dai->driver->ops->probe_order != order) + continue; - if (ret < 0) - return soc_dai_ret(dai, ret); - } + if (dai->driver->ops->probe) { + int ret = dai->driver->ops->probe(dai); + if (ret < 0) + return soc_dai_ret(dai, ret); + } + } dai->probed = 1; } @@ -564,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order) int i, r, ret = 0; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->remove_order != order) + if (!dai->probed) continue; - if (dai->probed && - dai->driver->remove) { - r = dai->driver->remove(dai); - if (r < 0) - ret = r; /* use last error */ - } + if (dai->driver->ops) { + if (dai->driver->ops->remove_order != order) + continue; + if (dai->driver->ops->remove) { + r = dai->driver->ops->remove(dai); + if (r < 0) + ret = r; /* use last error */ + } + } dai->probed = 0; } @@ -586,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd) int i; for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->pcm_new) { - int ret = dai->driver->pcm_new(rtd, dai); + if (dai->driver->ops && + dai->driver->ops->pcm_new) { + int ret = dai->driver->ops->pcm_new(rtd, dai); if (ret < 0) return soc_dai_ret(dai, ret); } @@ -603,6 +615,8 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream) int i, ret; for_each_rtd_dais(rtd, i, dai) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + continue; if (dai->driver->ops && dai->driver->ops->prepare) { ret = dai->driver->ops->prepare(substream, dai); @@ -619,6 +633,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai, { int ret = 0; + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + return 0; + if (dai->driver->ops && dai->driver->ops->trigger) ret = dai->driver->ops->trigger(substream, cmd, dai); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3091e8160bad..f07e83678373 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -916,6 +916,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, return -EINVAL; } } + if (w->no_wname_in_kcontrol_name) + wname_in_long_name = false; if (wname_in_long_name && kcname_in_long_name) { /* diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index f951acb2ce36..b2cc13b9c77b 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -37,7 +37,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) struct snd_soc_jack_pin *pin; unsigned int sync = 0; - if (!jack) + if (!jack || !jack->jack) return; trace_snd_soc_jack_report(jack, mask, status); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8896227e4fb7..3aa6b988cb4b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -38,6 +38,7 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, switch (ret) { case -EPROBE_DEFER: case -ENOTSUPP: + case -EINVAL: break; default: dev_err(rtd->dev, @@ -2466,8 +2467,11 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* there is no point preparing this FE if there are no BEs */ if (list_empty(&fe->dpcm[stream].be_clients)) { - dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n", - fe->dai_link->name); + /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles */ + dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n", + fe->dai_link->name); + dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", + fe->dai_link->name); ret = -EINVAL; goto out; } diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ad08d4f75a7b..e783055b6c3a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, 1 : 0; } +static const struct snd_soc_dai_ops tplg_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, } if (pcm->compress) - dai_drv->compress_new = snd_soc_new_compress; + dai_drv->ops = &tplg_dai_ops; /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 1cb92d6030e3..f2faa08f0c0e 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -2,7 +2,7 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. config SND_SOC_SOF_AMD_TOPLEVEL tristate "SOF support for AMD audio DSPs" @@ -21,6 +21,7 @@ config SND_SOC_SOF_AMD_COMMON select SND_SOC_SOF_PCI_DEV select SND_AMD_ACP_CONFIG select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_ACP_PROBES select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by @@ -33,6 +34,16 @@ config SND_SOC_SOF_AMD_RENOIR help Select this option for SOF support on AMD Renoir platform +config SND_SOC_SOF_AMD_VANGOGH + tristate "SOF support for VANGOGH" + depends on SND_SOC_SOF_PCI + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support + on AMD Vangogh platform. + Say Y if you want to enable SOF on Vangogh. + If unsure select "N". + config SND_SOC_SOF_AMD_REMBRANDT tristate "SOF support for REMBRANDT" depends on SND_SOC_SOF_PCI @@ -42,4 +53,11 @@ config SND_SOC_SOF_AMD_REMBRANDT Say Y if you want to enable SOF on Rembrandt. If unsure select "N". +config SND_SOC_SOF_ACP_PROBES + tristate + select SND_SOC_SOF_DEBUG_PROBES + help + This option is not user-selectable but automatically handled by + 'select' statements at a higher level + endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 5626d13b3e69..f3b375e67a6f 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -2,12 +2,15 @@ # This file is provided under a dual BSD/GPLv2 license. When using or # redistributing this file, you may do so under either license. # -# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o +snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o snd-sof-amd-renoir-objs := pci-rn.o renoir.o snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o +snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o +obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) +=snd-sof-amd-vangogh.o diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index df36b411a12e..3a0c7688dcfe 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -196,6 +196,10 @@ struct snd_sof_dsp_ops sof_acp_common_ops = { .dbg_dump = amd_sof_dump, .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, .dsp_arch_ops = &sof_xtensa_arch_ops, + + /* probe client device registation */ + .register_ipc_clients = acp_probes_register, + .unregister_ipc_clients = acp_probes_unregister, }; EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 920155dee819..a913f1cc4c80 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> */ @@ -49,27 +49,33 @@ #define ACP_CONTROL 0x1004 #define ACP3X_I2S_PIN_CONFIG 0x1400 +#define ACP5X_I2S_PIN_CONFIG 0x1400 #define ACP6X_I2S_PIN_CONFIG 0x1440 /* Registers offsets from ACP_PGFSM block */ #define ACP3X_PGFSM_BASE 0x141C +#define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 +#define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 +#define ACP5X_EXT_INTR_STAT 0x1808 #define ACP6X_EXT_INTR_STAT 0x1A0C #define ACP3X_DSP_SW_INTR_BASE 0x1814 +#define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 #define DSP_SW_INTR_TRIG_OFFSET 0x8 #define ACP_ERROR_STATUS 0x18C4 #define ACP3X_AXI2DAGB_SEM_0 0x1880 +#define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 /* Registers from ACP_SHA block */ @@ -81,6 +87,7 @@ #define ACP_SHA_DMA_CMD_STS 0x1CC0 #define ACP_SHA_DMA_ERR_STATUS 0x1CC4 #define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8 +#define ACP_SHA_DMA_INCLUDE_HDR 0x1CCC #define ACP_SHA_PSP_ACK 0x1C74 #define ACP_SCRATCH_REG_0 0x10000 diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 8a0fc635a997..81a2c096a185 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -155,6 +155,8 @@ out: irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + struct acp_dev_data *adata = sdev->pdata->hw_pdata; unsigned int dsp_msg_write = sdev->debug_box.offset + offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); unsigned int dsp_ack_write = sdev->debug_box.offset + @@ -200,6 +202,30 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } + if (desc->probe_reg_offset) { + u32 val; + u32 posn; + + /* Probe register consists of two parts + * (0-30) bit has cumulative position value + * 31 bit is a synchronization flag between DSP and CPU + * for the position update + */ + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->probe_reg_offset); + if (val & PROBE_STATUS_BIT) { + posn = val & ~PROBE_STATUS_BIT; + if (adata->probe_stream) { + /* Probe related posn value is of 31 bits limited to 2GB + * once wrapped DSP won't send posn interrupt. + */ + adata->probe_stream->cstream_posn = posn; + snd_compr_fragment_elapsed(adata->probe_stream->cstream); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->probe_reg_offset, posn); + ipc_irq = true; + } + } + } + if (!ipc_irq) dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index a4bce5a3ae48..a63c00b53a5e 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. // // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> @@ -158,7 +158,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) int ret; adata = sdev->pdata->hw_pdata; - size_fw = adata->fw_bin_size; + + if (adata->signed_fw_image) + size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; + else + size_fw = adata->fw_bin_size; page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; adata->fw_bin_page_count = page_count; @@ -219,3 +223,34 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) return 0; } EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); + +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata = plat_data->hw_pdata; + int ret; + + ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); + return ret; + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); + } + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, + (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); + + ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); + return ret; + + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); + } + + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, + (void *)adata->fw_dbin->data, adata->fw_dbin->size); + return ret; +} +EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c new file mode 100644 index 000000000000..778cf1a8b610 --- /dev/null +++ b/sound/soc/sof/amd/acp-probes.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com> + +/* + * Probe interface for generic AMD audio ACP DSP block + */ + +#include <linux/module.h> +#include <sound/soc.h> +#include "../sof-priv.h" +#include "../sof-client-probes.h" +#include "../sof-client.h" +#include "../ops.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +static int acp_probes_compr_startup(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai, u32 *stream_id) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream; + struct acp_dev_data *adata; + + adata = sdev->pdata->hw_pdata; + stream = acp_dsp_stream_get(sdev, 0); + if (!stream) + return -ENODEV; + + stream->cstream = cstream; + cstream->runtime->private_data = stream; + + adata->probe_stream = stream; + *stream_id = stream->stream_tag; + + return 0; +} + +static int acp_probes_compr_shutdown(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct acp_dev_data *adata; + int ret; + + ret = acp_dsp_stream_put(sdev, stream); + if (ret < 0) { + dev_err(sdev->dev, "Failed to release probe compress stream\n"); + return ret; + } + + adata = sdev->pdata->hw_pdata; + stream->cstream = NULL; + cstream->runtime->private_data = NULL; + adata->probe_stream = NULL; + + return 0; +} + +static int acp_probes_compr_set_params(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_params *params, + struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); + struct acp_dsp_stream *stream = cstream->runtime->private_data; + unsigned int buf_offset, index; + u32 size; + int ret; + + stream->dmab = cstream->runtime->dma_buffer_p; + stream->num_pages = PFN_UP(cstream->runtime->dma_bytes); + size = cstream->runtime->buffer_size; + + ret = acp_dsp_stream_config(sdev, stream); + if (ret < 0) { + acp_dsp_stream_put(sdev, stream); + return ret; + } + + /* write buffer size of stream in scratch memory */ + + buf_offset = sdev->debug_box.offset + + offsetof(struct scratch_reg_conf, buf_size); + index = stream->stream_tag - 1; + buf_offset = buf_offset + index * 4; + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size); + + return 0; +} + +static int acp_probes_compr_trigger(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + int cmd, struct snd_soc_dai *dai) +{ + /* Nothing to do here, as it is a mandatory callback just defined */ + return 0; +} + +static int acp_probes_compr_pointer(struct sof_client_dev *cdev, + struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp, + struct snd_soc_dai *dai) +{ + struct acp_dsp_stream *stream = cstream->runtime->private_data; + struct snd_soc_pcm_stream *pstream; + + pstream = &dai->driver->capture; + tstamp->copied_total = stream->cstream_posn; + tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); + + return 0; +} + +/* SOF client implementation */ +static const struct sof_probes_host_ops acp_probes_ops = { + .startup = acp_probes_compr_startup, + .shutdown = acp_probes_compr_shutdown, + .set_params = acp_probes_compr_set_params, + .trigger = acp_probes_compr_trigger, + .pointer = acp_probes_compr_pointer, +}; + +int acp_probes_register(struct snd_sof_dev *sdev) +{ + return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops, + sizeof(acp_probes_ops)); +} +EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON); + +void acp_probes_unregister(struct snd_sof_dev *sdev) +{ + sof_client_dev_unregister(sdev, "acp-probes", 0); +} +EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON); + +MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); + diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index afb505461ea1..b2e00a10a03e 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. +// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. // // Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com> // Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> @@ -20,6 +20,22 @@ #include "acp.h" #include "acp-dsp-offset.h" +#define SECURED_FIRMWARE 1 + +const struct dmi_system_id acp_sof_quirk_table[] = { + { + /* Valve Jupiter device */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, + .driver_data = (void *)SECURED_FIRMWARE, + }, + {} +}; +EXPORT_SYMBOL_GPL(acp_sof_quirk_table); + static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) { pci_write_config_dword(dev, 0x60, smn_addr); @@ -28,12 +44,14 @@ static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) return 0; } -static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data) +static int smn_read(struct pci_dev *dev, u32 smn_addr) { + u32 data = 0; + pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, data); + pci_read_config_dword(dev, 0x64, &data); - return 0; + return data; } static void init_dma_descriptor(struct acp_dev_data *adata) @@ -150,15 +168,13 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) { struct snd_sof_dev *sdev = adata->dev; - int timeout; + int ret; u32 data; - for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { - msleep(20); - smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data); - if (data & MBOX_READY_MASK) - return 0; - } + ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US, + ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG); + if (!ret) + return 0; dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK); @@ -177,23 +193,19 @@ static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) static int psp_send_cmd(struct acp_dev_data *adata, int cmd) { struct snd_sof_dev *sdev = adata->dev; - int ret, timeout; + int ret; u32 data; if (!cmd) return -EINVAL; /* Get a non-zero Doorbell value from PSP */ - for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) { - msleep(MBOX_DELAY); - smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data); - if (data) - break; - } + ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, + adata->smn_dev, MP0_C2PMSG_73_REG); - if (!timeout) { + if (ret) { dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG); - return -EINVAL; + return ret; } /* Check if PSP is ready for new command */ @@ -239,6 +251,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } + if (adata->signed_fw_image) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length); @@ -469,8 +484,10 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); int amd_sof_acp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; struct acp_dev_data *adata; const struct sof_amd_acp_desc *chip; + const struct dmi_system_id *dmi_id; unsigned int addr; int ret; @@ -531,6 +548,20 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; sdev->debug_box.size = BOX_SIZE_1024; + adata->signed_fw_image = false; + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) { + adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", + plat_data->fw_filename_prefix, + chip->name); + adata->signed_fw_image = dmi_id->driver_data; + + dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, + adata->fw_data_bin); + } acp_memory_init(sdev); acp_dsp_stream_init(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index dc624f727aa3..19cad4fcf99a 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -3,7 +3,7 @@ * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * - * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved. + * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. * * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> */ @@ -11,6 +11,8 @@ #ifndef __SOF_AMD_ACP_H #define __SOF_AMD_ACP_H +#include <linux/dmi.h> + #include "../sof-priv.h" #include "../sof-audio.h" @@ -32,6 +34,7 @@ #define ACP_DSP_INTR_EN_MASK 0x00000001 #define ACP3X_SRAM_PTE_OFFSET 0x02050000 +#define ACP5X_SRAM_PTE_OFFSET 0x02050000 #define ACP6X_SRAM_PTE_OFFSET 0x03800000 #define PAGE_SIZE_4K_ENABLE 0x2 #define ACP_PAGE_SIZE 0x1000 @@ -40,6 +43,7 @@ #define DSP_FW_RUN_ENABLE 0x01 #define ACP_SHA_RUN 0x01 #define ACP_SHA_RESET 0x02 +#define ACP_SHA_HEADER 0x01 #define ACP_DMA_CH_RST 0x01 #define ACP_DMA_CH_GRACEFUL_RST_EN 0x10 #define ACP_ATU_CACHE_INVALID 0x01 @@ -56,17 +60,19 @@ #define ACP_DSP_TO_HOST_IRQ 0x04 #define ACP_RN_PCI_ID 0x01 +#define ACP_VANGOGH_PCI_ID 0x50 #define ACP_RMB_PCI_ID 0x6F #define HOST_BRIDGE_CZN 0x1630 +#define HOST_BRIDGE_VGH 0x1645 #define HOST_BRIDGE_RMB 0x14B5 #define ACP_SHA_STAT 0x8000 -#define ACP_PSP_TIMEOUT_COUNTER 5 +#define ACP_PSP_TIMEOUT_US 1000000 #define ACP_EXT_INTR_ERROR_STAT 0x20000000 #define MP0_C2PMSG_114_REG 0x3810AC8 #define MP0_C2PMSG_73_REG 0x3810A24 #define MBOX_ACP_SHA_DMA_COMMAND 0x70000 -#define MBOX_DELAY 1000 +#define MBOX_DELAY_US 1000 #define MBOX_READY_MASK 0x80000000 #define MBOX_STATUS_MASK 0xFFFF @@ -77,6 +83,9 @@ #define AMD_STACK_DUMP_SIZE 32 #define SRAM1_SIZE 0x13A000 +#define PROBE_STATUS_BIT BIT(31) + +#define ACP_FIRMWARE_SIGNATURE 0x100 enum clock_source { ACP_CLOCK_96M = 0, @@ -156,10 +165,13 @@ struct acp_dsp_stream { int active; unsigned int reg_offset; size_t posn_offset; + struct snd_compr_stream *cstream; + u64 cstream_posn; }; struct sof_amd_acp_desc { unsigned int rev; + const char *name; unsigned int host_bridge_id; u32 pgfsm_base; u32 ext_intr_stat; @@ -168,24 +180,30 @@ struct sof_amd_acp_desc { u32 hw_semaphore_offset; u32 acp_clkmux_sel; u32 fusion_dsp_offset; + u32 probe_reg_offset; }; /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; + const struct firmware *fw_dbin; /* DMIC device */ struct platform_device *dmic_dev; unsigned int fw_bin_size; unsigned int fw_data_bin_size; + const char *fw_code_bin; + const char *fw_data_bin; u32 fw_bin_page_count; dma_addr_t sha_dma_addr; u8 *bin_buf; dma_addr_t dma_addr; u8 *data_buf; + bool signed_fw_image; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; struct pci_dev *smn_dev; + struct acp_dsp_stream *probe_stream; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -205,6 +223,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev); /* DSP Loader callbacks */ int acp_sof_dsp_run(struct snd_sof_dev *sdev); int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev); int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type); /* Block IO callbacks */ @@ -248,6 +267,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops; extern struct snd_sof_dsp_ops sof_renoir_ops; int sof_renoir_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_vangogh_ops; +int sof_vangogh_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_rembrandt_ops; int sof_rembrandt_ops_init(struct snd_sof_dev *sdev); @@ -273,4 +294,10 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata return desc->chip_info; } + +int acp_probes_register(struct snd_sof_dev *sdev); +void acp_probes_unregister(struct snd_sof_dev *sdev); + +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; +extern const struct dmi_system_id acp_sof_quirk_table[]; #endif diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index 58b3092425f1..9935e457b467 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -25,6 +25,7 @@ #define ACP6x_REG_START 0x1240000 #define ACP6x_REG_END 0x125C000 +#define ACP6X_FUTURE_REG_ACLK_0 0x1854 static const struct sof_amd_acp_desc rembrandt_chip_info = { .rev = 6, @@ -36,6 +37,7 @@ static const struct sof_amd_acp_desc rembrandt_chip_info = { .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP6X_CLKMUX_SEL, .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc rembrandt_desc = { diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 7409e21ce5aa..c72d5d8aff8e 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -25,6 +25,7 @@ #define ACP3x_REG_START 0x1240000 #define ACP3x_REG_END 0x125C000 +#define ACP3X_FUTURE_REG_ACLK_0 0x1860 static const struct sof_amd_acp_desc renoir_chip_info = { .rev = 3, @@ -35,6 +36,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = { .sram_pte_offset = ACP3X_SRAM_PTE_OFFSET, .hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0, .acp_clkmux_sel = ACP3X_CLKMUX_SEL, + .probe_reg_offset = ACP3X_FUTURE_REG_ACLK_0, }; static const struct sof_dev_desc renoir_desc = { diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c new file mode 100644 index 000000000000..d8be42fbcb6d --- /dev/null +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com> + +/*. + * PCI interface for Vangogh ACP device + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <sound/sof.h> +#include <sound/soc-acpi.h> + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP5X_FUTURE_REG_ACLK_0 0x1864 + +static const struct sof_amd_acp_desc vangogh_chip_info = { + .rev = 5, + .name = "vangogh", + .host_bridge_id = HOST_BRIDGE_VGH, + .pgfsm_base = ACP5X_PGFSM_BASE, + .ext_intr_stat = ACP5X_EXT_INTR_STAT, + .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE, + .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0, + .acp_clkmux_sel = ACP5X_CLKMUX_SEL, + .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0, +}; + +static const struct sof_dev_desc vangogh_desc = { + .machines = snd_soc_acpi_amd_vangogh_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &vangogh_chip_info, + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .default_fw_path = { + [SOF_IPC] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-vangogh.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_vangogh_ops, + .ops_init = sof_vangogh_ops_init, +}; + +static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + if (pci->revision != ACP_VANGOGH_PCI_ID) + return -ENODEV; + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +}; + +static void acp_pci_vgh_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id vgh_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&vangogh_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, vgh_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_vgh_driver = { + .name = KBUILD_MODNAME, + .id_table = vgh_pci_ids, + .probe = acp_pci_vgh_probe, + .remove = acp_pci_vgh_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_amd_vgh_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c new file mode 100644 index 000000000000..de15d21aa6d9 --- /dev/null +++ b/sound/soc/sof/amd/vangogh.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Advanced Micro Devices, Inc. +// +// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com> + +/* + * Hardware interface for Audio DSP on Vangogh platform + */ + +#include <linux/platform_device.h> +#include <linux/module.h> + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_HS_INSTANCE 0 +#define I2S_BT_INSTANCE 1 +#define I2S_SP_INSTANCE 2 +#define PDM_DMIC_INSTANCE 3 +#define I2S_HS_VIRTUAL_INSTANCE 4 + +static struct snd_soc_dai_driver vangogh_sof_dai[] = { + [I2S_HS_INSTANCE] = { + .id = I2S_HS_INSTANCE, + .name = "acp-sof-hs", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_BT_INSTANCE] = { + .id = I2S_BT_INSTANCE, + .name = "acp-sof-bt", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_SP_INSTANCE] = { + .id = I2S_SP_INSTANCE, + .name = "acp-sof-sp", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM_DMIC_INSTANCE] = { + .id = PDM_DMIC_INSTANCE, + .name = "acp-sof-dmic", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_HS_VIRTUAL_INSTANCE] = { + .id = I2S_HS_VIRTUAL_INSTANCE, + .name = "acp-sof-hs-virtual", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS-Virtual controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, +}; + +/* Vangogh ops */ +struct snd_sof_dsp_ops sof_vangogh_ops; +EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); + +int sof_vangogh_ops_init(struct snd_sof_dev *sdev) +{ + const struct dmi_system_id *dmi_id; + + /* common defaults */ + memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_vangogh_ops.drv = vangogh_sof_dai; + sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + + dmi_id = dmi_first_match(acp_sof_quirk_table); + if (dmi_id && dmi_id->driver_data) + sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; + + return 0; +} + +MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); +MODULE_DESCRIPTION("VANGOGH SOF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 69c1a370d3b6..9d0107932117 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_LNL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_LUNARLAKE + tristate "SOF support for Lunarlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_LNL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Lunarlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index fdb463c12e91..030574dbc998 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-dai-ops.o hda-bus.o \ skl.o hda-loader-skl.o \ - apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o + apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o snd-sof-intel-hda-mlink-objs := hda-mlink.o @@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-tgl-objs := pci-tgl.o snd-sof-pci-intel-mtl-objs := pci-mtl.o +snd-sof-pci-intel-lnl-objs := pci-lnl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o @@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a95222e53ecf..c6fbf4285262 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index f3513796c189..494ced2b746e 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -7,6 +7,7 @@ #include <sound/pcm_params.h> #include <sound/hdaudio_ext.h> +#include <sound/hda-mlink.h> #include <sound/sof/ipc4/header.h> #include <uapi/sound/sof/header.h> #include "../ipc4-priv.h" @@ -144,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; struct hdac_ext_stream *hext_stream; - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + /* only allocate a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + else + hext_stream = snd_soc_dai_get_dma_data(dai, substream); + if (!hext_stream) return NULL; @@ -159,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + /* only release a stream_tag for the first DAI in the dailink */ + dai = asoc_rtd_to_cpu(rtd, 0); + if (dai == cpu_dai) + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, @@ -219,6 +233,77 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev, return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); } +static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + + format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), + params_format(params), + params_physical_width(params), + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), params_channels(params), params_format(params)); + + return format_val; +} + +static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int format_val; + snd_pcm_format_t format; + unsigned int channels; + unsigned int width; + + channels = params_channels(params); + format = params_format(params); + width = params_physical_width(params); + + if (format == SNDRV_PCM_FORMAT_S16_LE) { + format = SNDRV_PCM_FORMAT_S32_LE; + channels /= 2; + width = 32; + } + + format_val = snd_hdac_calc_stream_format(params_rate(params), channels, + format, + width, + 0); + + dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val, + params_rate(params), channels, format); + + return format_val; +} + +static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_ssp_get_hlink(bus); +} + +static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_dmic_get_hlink(bus); +} + +static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + return hdac_bus_eml_sdw_get_hlink(bus); +} + static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -234,6 +319,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { @@ -297,6 +385,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; + if (pipe_widget->instance_id < 0) + return 0; + mutex_lock(&ipc4_data->pipeline_state_mutex); switch (cmd) { @@ -343,6 +434,28 @@ out: return ret; } +static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, + struct snd_soc_dai *cpu_dai, + struct snd_pcm_substream *substream) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *dai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = dai->private; + struct sof_ipc4_alh_configuration_blob *blob; + + blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; + + /* + * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using + * the multi-gateway firmware configuration. The DMA hardware can take care of + * multiple links without needing any firmware assistance + */ + blob->alh_cfg.device_count = 1; + + return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream); +} + static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -357,6 +470,45 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hlink = hda_get_hlink, }; +static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = ssp_get_hlink, +}; + +static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { + .get_hext_stream = hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = dmic_calc_stream_format, + .get_hlink = dmic_get_hlink, +}; + +static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { + .get_hext_stream = sdw_hda_ipc4_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .pre_trigger = hda_ipc4_pre_trigger, + .trigger = hda_trigger, + .post_trigger = hda_ipc4_post_trigger, + .calc_stream_format = generic_calc_stream_format, + .get_hlink = sdw_get_hlink, +}; + static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { .get_hext_stream = hda_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -372,6 +524,7 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { + struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); switch (cmd) { @@ -379,9 +532,17 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c case SNDRV_PCM_TRIGGER_STOP: { struct snd_sof_dai_config_data data = { 0 }; + int ret; data.dai_data = DMA_CHAN_INVALID; - return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); + ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data); + if (ret < 0) + return ret; + + if (cmd == SNDRV_PCM_TRIGGER_STOP) + return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); + + break; } case SNDRV_PCM_TRIGGER_PAUSE_PUSH: return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); @@ -459,8 +620,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg case SOF_INTEL_IPC4: { struct sof_ipc4_copier *ipc4_copier = sdai->private; + const struct sof_intel_dsp_desc *chip; - if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { + chip = get_chip_info(sdev->pdata); + + switch (ipc4_copier->dai_type) { + case SOF_DAI_INTEL_HDA: + { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; @@ -469,6 +635,22 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg return &hda_ipc4_dma_ops; } + case SOF_DAI_INTEL_SSP: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &ssp_ipc4_dma_ops; + case SOF_DAI_INTEL_DMIC: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &dmic_ipc4_dma_ops; + case SOF_DAI_INTEL_ALH: + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + return &sdw_ipc4_dma_ops; + + default: + break; + } break; } default: diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 3297dea493aa..f3cefd866081 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -10,6 +10,8 @@ #include <sound/pcm_params.h> #include <sound/hdaudio_ext.h> +#include <sound/hda-mlink.h> +#include <sound/hda_register.h> #include <sound/intel-nhlt.h> #include <sound/sof/ipc4/header.h> #include <uapi/sound/sof/header.h> @@ -107,9 +109,8 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai return sdai->platform_private; } -static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, - struct hdac_ext_stream *hext_stream, - struct snd_soc_dai *cpu_dai) +int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream, + struct snd_soc_dai *cpu_dai) { const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); struct sof_intel_hda_stream *hda_stream; @@ -330,6 +331,175 @@ static const struct snd_soc_dai_ops hda_dai_ops = { #endif +static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dai *sdai = swidget->private; + struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private; + + return ipc4_copier; +} + +static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct sof_ipc4_dma_config_tlv *dma_config_tlv; + const struct hda_dai_widget_dma_ops *ops; + struct sof_ipc4_dma_config *dma_config; + struct sof_ipc4_copier *ipc4_copier; + struct hdac_ext_stream *hext_stream; + struct hdac_stream *hstream; + struct snd_sof_dev *sdev; + int stream_id; + int ret; + + ops = hda_dai_get_ops(substream, cpu_dai); + if (!ops) { + dev_err(cpu_dai->dev, "DAI widget ops not set\n"); + return -EINVAL; + } + + /* use HDaudio stream handling */ + ret = hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret); + return ret; + } + + /* get stream_id */ + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) { + dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__); + return -ENODEV; + } + + hstream = &hext_stream->hstream; + stream_id = hstream->stream_tag; + + if (!stream_id) { + dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__); + return -ENODEV; + } + + /* configure TLV */ + ipc4_copier = widget_to_copier(w); + + dma_config_tlv = &ipc4_copier->dma_config_tlv; + dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; + /* dma_config_priv_size is zero */ + dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); + + dma_config = &dma_config_tlv->dma_config; + + dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA; + dma_config->pre_allocated_by_host = 1; + dma_config->dma_channel_id = stream_id - 1; + dma_config->stream_id = stream_id; + dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ + dma_config->dma_priv_config_size = 0; + + return 0; +} + +static int non_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int stream = substream->stream; + + return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); +} + +static const struct snd_soc_dai_ops ssp_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .hw_params = non_hda_dai_hw_params, + .hw_free = hda_dai_hw_free, + .trigger = hda_dai_trigger, + .prepare = non_hda_dai_prepare, +}; + +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + const struct hda_dai_widget_dma_ops *ops; + struct hdac_ext_stream *hext_stream; + struct snd_sof_dev *sdev; + int ret; + + ret = non_hda_dai_hw_params(substream, params, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret); + return ret; + } + + ops = hda_dai_get_ops(substream, cpu_dai); + sdev = widget_to_sdev(w); + hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); + + if (!hext_stream) + return -ENODEV; + + /* in the case of SoundWire we need to program the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + GENMASK(params_channels(params) - 1, 0), + hdac_stream(hext_stream)->stream_tag, + substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id) +{ + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); + struct snd_sof_dev *sdev; + int ret; + + ret = hda_dai_hw_free(substream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); + return ret; + } + + sdev = widget_to_sdev(w); + + /* in the case of SoundWire we need to reset the PCMSyCM registers */ + ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, + 0, 0, substream->stream); + if (ret < 0) { + dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + return hda_dai_trigger(substream, cmd, cpu_dai); +} + static int hda_dai_suspend(struct hdac_bus *bus) { struct snd_soc_pcm_runtime *rtd; @@ -384,7 +554,42 @@ static int hda_dai_suspend(struct hdac_bus *bus) return 0; } -#endif +static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "SSP")) + ops->drv[i].ops = &ssp_dai_ops; + } + } +} + +static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) +{ + const struct sof_intel_dsp_desc *chip; + int i; + + chip = get_chip_info(sdev->pdata); + + if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { + for (i = 0; i < ops->num_drv; i++) { + if (strstr(ops->drv[i].name, "DMIC")) + ops->drv[i].ops = &dmic_dai_ops; + } + } +} + +#else + +static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} +static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} + +#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) { @@ -399,6 +604,9 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) #endif } + ssp_set_dai_drv_ops(sdev, ops); + dmic_set_dai_drv_ops(sdev, ops); + if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index b7cbf66badf5..b592e687a87a 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -331,14 +331,19 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask) return !!(val & cmdsync_mask); } -static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num) +static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid) { - u32 val; + return readw(lsdiid); +} + +static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num) +{ + u16 val; - val = readl(lsdiid); + val = readw(lsdiid); val |= BIT(dev_num); - writel(val, lsdiid); + writew(val, lsdiid); } static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan, @@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK); +int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) +{ + struct hdac_ext2_link *h2link; + struct hdac_ext_link *hlink; + + h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); + if (!h2link) + return -ENODEV; + + hlink = &h2link->hext_link; + + *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink)); + + return 0; +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK); + int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { struct hdac_ext2_link *h2link; @@ -781,6 +802,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, { struct hdac_ext2_link *h2link; u16 __iomem *pcmsycm; + int hchan; + int lchan; u16 val; h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW); @@ -791,17 +814,25 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, h2link->instance_offset * sublink + AZX_REG_SDW_SHIM_PCMSyCM(y); + if (channel_mask) { + hchan = __fls(channel_mask); + lchan = __ffs(channel_mask); + } else { + hchan = 0; + lchan = 0; + } + mutex_lock(&h2link->eml_lock); - hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask), + hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan, stream_id, dir); mutex_unlock(&h2link->eml_lock); val = readw(pcmsycm); - dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n", - channel_mask, stream_id, dir, val); + dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n", + sublink, channel_mask, stream_id, dir, val); return 0; } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b13acb959653..0b0087abcc50 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -869,8 +869,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; } - /* create capture streams */ - for (i = 0; i < num_capture; i++) { + /* create capture and playback streams */ + for (i = 0; i < num_total; i++) { struct sof_intel_hda_stream *hda_stream; hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), @@ -909,69 +909,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) hstream->index = i; sd_offset = SOF_STREAM_SD_OFFSET(hstream); hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i + 1; hstream->opened = false; hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_CAPTURE; - /* memory alloc for stream BDL */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - HDA_DSP_BDL_SIZE, &hstream->bdl); - if (ret < 0) { - dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); - return -ENOMEM; - } - hstream->posbuf = (__le32 *)(bus->posbuf.area + - (hstream->index) * 8); - - list_add_tail(&hstream->list, &bus->stream_list); - } - - /* create playback streams */ - for (i = num_capture; i < num_total; i++) { - struct sof_intel_hda_stream *hda_stream; - - hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), - GFP_KERNEL); - if (!hda_stream) - return -ENOMEM; - - hda_stream->sdev = sdev; - - hext_stream = &hda_stream->hext_stream; - - if (sdev->bar[HDA_DSP_PP_BAR]) { - hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; - - hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + - SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + - SOF_HDA_PPLC_INTERVAL * i; - } - - hstream = &hext_stream->hstream; - - /* do we support SPIB */ - if (sdev->bar[HDA_DSP_SPIB_BAR]) { - hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_SPIB; - - hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + - SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + - SOF_HDA_SPIB_MAXFIFO; + if (i < num_capture) { + hstream->stream_tag = i + 1; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; + } else { + hstream->stream_tag = i - num_capture + 1; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; } - hstream->bus = bus; - hstream->sd_int_sta_mask = 1 << i; - hstream->index = i; - sd_offset = SOF_STREAM_SD_OFFSET(hstream); - hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; - hstream->stream_tag = i - num_capture + 1; - hstream->opened = false; - hstream->running = false; - hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; - /* mem alloc for stream BDL */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, HDA_DSP_BDL_SIZE, &hstream->bdl); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 64bebe1a72bb..15e6779efaa3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev) BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); interface_mask[1] = BIT(SOF_DAI_INTEL_HDA); break; + case SOF_INTEL_ACE_2_0: + interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | + BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH); + interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */ + break; default: break; } @@ -107,6 +112,34 @@ struct sdw_intel_ops sdw_callback = { .params_stream = sdw_params_stream, }; +static int sdw_ace2x_params_stream(struct device *dev, + struct sdw_intel_stream_params_data *params_data) +{ + return sdw_hda_dai_hw_params(params_data->substream, + params_data->hw_params, + params_data->dai, + params_data->link_id); +} + +static int sdw_ace2x_free_stream(struct device *dev, + struct sdw_intel_stream_free_data *free_data) +{ + return sdw_hda_dai_hw_free(free_data->substream, + free_data->dai, + free_data->link_id); +} + +static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +{ + return sdw_hda_dai_trigger(substream, cmd, dai); +} + +static struct sdw_intel_ops sdw_ace2x_callback = { + .params_stream = sdw_ace2x_params_stream, + .free_stream = sdw_ace2x_free_stream, + .trigger = sdw_ace2x_trigger, +}; + void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) { struct sof_intel_hda_dev *hdev; @@ -174,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.shim_base = hdev->desc->sdw_shim_base; res.alh_base = hdev->desc->sdw_alh_base; res.ext = false; + res.ops = &sdw_callback; } else { /* * retrieve eml_lock needed to protect shared registers @@ -191,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) */ res.hw_ops = &sdw_intel_lnl_hw_ops; res.ext = true; + res.ops = &sdw_ace2x_callback; + } res.irq = sdev->ipc_irq; res.handle = hdev->info.handle; res.parent = sdev->dev; - res.ops = &sdw_callback; + res.dev = sdev->dev; res.clock_stop_quirks = sdw_clock_stop_quirks; res.hbus = sof_to_bus(sdev); @@ -363,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return sdw_intel_thread(irq, context); } -static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) { - u32 interface_mask = hda_get_interface_mask(sdev); struct sof_intel_hda_dev *hdev; - if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) - return false; - hdev = sdev->pdata->hw_pdata; if (hdev->sdw && snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -380,6 +412,21 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) return false; } +static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + u32 interface_mask = hda_get_interface_mask(sdev); + const struct sof_intel_dsp_desc *chip; + + if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) + return false; + + chip = get_chip_info(sdev->pdata); + if (chip && chip->check_sdw_wakeen_irq) + return chip->check_sdw_wakeen_irq(sdev); + + return false; +} + void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -1429,83 +1476,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) -#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \ - SDW_MFG_ID_MASK | SDW_PART_ID_MASK)) - -/* Check if all Slaves defined on the link can be found */ -static bool link_slaves_found(struct snd_sof_dev *sdev, - const struct snd_soc_acpi_link_adr *link, - struct sdw_intel_ctx *sdw) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct sdw_intel_slave_id *ids = sdw->ids; - int num_slaves = sdw->num_slaves; - unsigned int part_id, link_id, unique_id, mfg_id, version; - int i, j, k; - - for (i = 0; i < link->num_adr; i++) { - u64 adr = link->adr_d[i].adr; - int reported_part_count = 0; - - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - link_id = SDW_DISCO_LINK_ID(adr); - version = SDW_VERSION(adr); - - for (j = 0; j < num_slaves; 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) - reported_part_count++; - } - - for (j = 0; j < num_slaves; 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) - continue; - - /* find out how many identical parts are expected */ - for (k = 0; k < link->num_adr; k++) { - u64 adr2 = link->adr_d[k].adr; - - if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr)) - expected_part_count++; - } - - if (reported_part_count == expected_part_count) { - /* - * we have to check unique id - * if there is more than one - * Slave on the link - */ - unique_id = SDW_UNIQUE_ID(adr); - if (reported_part_count == 1 || - ids[j].id.unique_id == unique_id) { - dev_dbg(bus->dev, "found %x at link %d\n", - part_id, link_id); - break; - } - } else { - dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n", - part_id, reported_part_count, expected_part_count, link_id); - } - } - if (j == num_slaves) { - dev_dbg(bus->dev, - "Slave %x not found\n", - part_id); - return false; - } - } - return true; -} - static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -1549,7 +1519,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * Try next machine if any expected Slaves * are not found on this link. */ - if (!link_slaves_found(sdev, link, hdev->sdw)) + if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, + hdev->sdw->ids, + hdev->sdw->num_slaves)) break; } /* Found if all Slaves are checked */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3f7c6fb05e5d..5c517ec57d4a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev); int hda_sdw_startup(struct snd_sof_dev *sdev); void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); +bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev); void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); @@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } +static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) +{ + return false; +} + static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { } @@ -824,6 +830,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) #endif +int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai, + int link_id); + +int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai); + /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; int hda_dsp_dais_suspend(struct snd_sof_dev *sdev); @@ -845,6 +863,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_mtl_ops; int sof_mtl_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_lnl_ops; +int sof_lnl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc apl_chip_info; @@ -856,6 +876,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc mtl_chip_info; +extern const struct sof_intel_dsp_desc lnl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) @@ -963,5 +984,7 @@ const struct hda_dai_widget_dma_ops * hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, struct snd_sof_dai_config_data *data); +int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream, + struct snd_soc_dai *cpu_dai); #endif diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 0f249efc6a5a..7ac10167a90d 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c new file mode 100644 index 000000000000..db94b45e53af --- /dev/null +++ b/sound/soc/sof/intel/lnl.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. + +/* + * Hardware interface for audio DSP on LunarLake. + */ + +#include <linux/firmware.h> +#include <sound/hda_register.h> +#include <sound/sof/ipc4/header.h> +#include <trace/events/sof_intel.h> +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" +#include <sound/hda-mlink.h> + +/* LunarLake ops */ +struct snd_sof_dsp_ops sof_lnl_ops; +EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +/* this helps allows the DSP to setup DMIC/SSP */ +static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus) +{ + int ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true); + if (ret < 0) + return ret; + + ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true); + if (ret < 0) + return ret; + + return 0; +} + +static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_probe(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + + ret = hda_dsp_runtime_resume(sdev); + if (ret < 0) + return ret; + + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); +} + +int sof_lnl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* probe */ + sof_lnl_ops.probe = lnl_hda_dsp_probe; + + /* shutdown */ + sof_lnl_ops.shutdown = hda_dsp_shutdown; + + /* doorbell */ + sof_lnl_ops.irq_thread = mtl_ipc_irq_thread; + + /* ipc */ + sof_lnl_ops.send_msg = mtl_ipc_send_msg; + sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + + /* debug */ + sof_lnl_ops.debug_map = lnl_dsp_debugfs; + sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs); + sof_lnl_ops.dbg_dump = mtl_dsp_dump; + sof_lnl_ops.ipc_dump = mtl_ipc_dump; + + /* pre/post fw run */ + sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run; + sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run; + + /* parse platform specific extended manifest */ + sof_lnl_ops.parse_platform_ext_manifest = NULL; + + /* dsp core get/put */ + /* TODO: add core_get and core_put */ + + /* PM */ + sof_lnl_ops.resume = lnl_hda_dsp_resume; + sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume; + + sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, &sof_lnl_ops); + + sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4; + + return 0; +}; +EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); + +/* Check if an SDW IRQ occurred */ +static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(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); +} + +const struct sof_intel_dsp_desc lnl_chip_info = { + .cores_num = 5, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .enable_sdw_irq = lnl_enable_sdw_irq, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_2_0, +}; +EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 30fe77fd87bf..b84ca58da9d5 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return false; } -static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; @@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) } /* pre fw run operations */ -static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; u32 dsphfpwrsts; @@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } -static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { int ret; @@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } -static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; u32 romdbgsts; @@ -495,7 +495,7 @@ err: return ret; } -static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; @@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } -static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } -static void mtl_ipc_dump(struct snd_sof_dev *sdev) +void mtl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; @@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } -static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream) +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { struct hdac_stream *hstream = substream->runtime->private_data; u32 llp_l, llp_u; @@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = mtl_enable_sdw_irq, .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, .power_down_dsp = mtl_power_down_dsp, diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 2794fe6e8139..02181490f12a 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -82,10 +82,28 @@ #define MTL_DSP_REG_HfIMRIS1 0x162088 #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) +bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); +int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); + void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev); void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev); -bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable); -int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev); +void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + int mtl_power_down_dsp(struct snd_sof_dev *sdev); +int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); + +irqreturn_t mtl_ipc_irq_thread(int irq, void *context); + +int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + +void mtl_ipc_dump(struct snd_sof_dev *sdev); + +u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream); diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 69cad5a6bc72..460f87f25dac 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -85,12 +85,8 @@ static const struct sof_dev_desc glk_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */ - .driver_data = (unsigned long)&bxt_desc}, - { PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */ - .driver_data = (unsigned long)&bxt_desc}, - { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */ - .driver_data = (unsigned long)&glk_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_APL, &bxt_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_GML, &glk_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index 8895508a0be6..e2c50e7b0aa7 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -120,16 +120,11 @@ static const struct sof_dev_desc cml_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */ - .driver_data = (unsigned long)&cnl_desc}, - { PCI_DEVICE(0x8086, 0xa348), /* CNL-H */ - .driver_data = (unsigned long)&cfl_desc}, - { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */ - .driver_data = (unsigned long)&cml_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cfl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cml_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cml_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &cml_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 5fb5a820693e..0a65df3ed9e2 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -86,14 +86,10 @@ static const struct sof_dev_desc jsl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */ - .driver_data = (unsigned long)&icl_desc}, - { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */ - .driver_data = (unsigned long)&icl_desc}, - { PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */ - .driver_data = (unsigned long)&jsl_desc}, - { PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */ - .driver_data = (unsigned long)&jsl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &jsl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c new file mode 100644 index 000000000000..1b12c280edb4 --- /dev/null +++ b/sound/soc/sof/intel/pci-lnl.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2023 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc lnl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_lnl_machines, + .alt_machines = snd_soc_acpi_intel_lnl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &lnl_chip_info, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .dspless_mode_supported = true, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "sof-lnl.ri", + }, + .nocodec_tplg_filename = "sof-lnl-nocodec.tplg", + .ops = &sof_lnl_ops, + .ops_init = sof_lnl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_lnl_driver = { + .name = "sof-audio-pci-intel-lnl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_lnl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index e276e1e37fed..7868b0827e84 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -52,8 +52,7 @@ static const struct sof_dev_desc mtl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x7E28), /* MTL */ - .driver_data = (unsigned long)&mtl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index 5e69af6eed34..a6588b138a8c 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -69,10 +69,8 @@ static struct sof_dev_desc kbl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc}, - /* KBL */ - { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &kbl_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index ca37ff1bbd2a..d688f9373fb2 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -284,36 +284,21 @@ static const struct sof_dev_desc rpl_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ - .driver_data = (unsigned long)&tgl_desc}, - { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */ - .driver_data = (unsigned long)&tglh_desc}, - { PCI_DEVICE(0x8086, 0x4b55), /* EHL */ - .driver_data = (unsigned long)&ehl_desc}, - { PCI_DEVICE(0x8086, 0x4b58), /* EHL */ - .driver_data = (unsigned long)&ehl_desc}, - { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */ - .driver_data = (unsigned long)&adls_desc}, - { PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */ - .driver_data = (unsigned long)&rpls_desc}, - { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ - .driver_data = (unsigned long)&adl_desc}, - { PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */ - .driver_data = (unsigned long)&rpl_desc}, - { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ - .driver_data = (unsigned long)&adl_n_desc}, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tglh_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adls_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &rpls_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 8c22a00266c0..4ae4fe17cc0b 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -225,8 +225,7 @@ static const struct sof_dev_desc tng_desc = { /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { - { PCI_DEVICE(0x8086, 0x119a), - .driver_data = (unsigned long)&tng_desc}, + { PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) }, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 207df48e27cf..9515d753c816 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -189,6 +189,7 @@ struct sof_intel_dsp_desc { int (*read_sdw_lcount)(struct snd_sof_dev *sdev); void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable); bool (*check_sdw_irq)(struct snd_sof_dev *sdev); + bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); int (*power_down_dsp)(struct snd_sof_dev *sdev); int (*disable_interrupts)(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 8e2b07e1612b..bb9f20253c99 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, @@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = { .read_sdw_lcount = hda_sdw_check_lcount_common, .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, + .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, .power_down_dsp = hda_power_down_dsp, diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c index 35da85a45a9a..bd07f0472efd 100644 --- a/sound/soc/sof/ipc3-dtrace.c +++ b/sound/soc/sof/ipc3-dtrace.c @@ -196,15 +196,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user return -EINVAL; } - string = kmalloc(count + 1, GFP_KERNEL); - if (!string) - return -ENOMEM; - - if (copy_from_user(string, from, count)) { - ret = -EFAULT; - goto error; - } - string[count] = '\0'; + string = memdup_user_nul(from, count); + if (IS_ERR(string)) + return PTR_ERR(string); ret = trace_filter_parse(sdev, string, &num_elems, &elems); if (ret < 0) diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 304faf6425ab..cb58ee8c158a 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -309,6 +309,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = private->dai_config->afe.channels; channels->max = private->dai_config->afe.channels; + snd_mask_none(fmt); + + switch (private->dai_config->afe.format) { + case SOF_IPC_FRAME_S16_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case SOF_IPC_FRAME_S24_4LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + break; + case SOF_IPC_FRAME_S32_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(component->dev, "Not available format!\n"); + return -EINVAL; + } + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 2c5aac31e8b0..fb40378ad084 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -312,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) } else { if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS)) ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); - if (msg->reply_size) + if (reply_data && msg->reply_size) /* copy the data returned from DSP */ memcpy(reply_data, msg->reply_data, msg->reply_size); @@ -567,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev, /* create read-only cc_version debugfs to store compiler version info */ /* use local copy of the cc_version to prevent data corruption */ if (sdev->first_boot) { - sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size, - GFP_KERNEL); - + sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL); if (!sdev->cc_version) return -ENOMEM; - memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size); ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version, cc->ext_hdr.hdr.size, "cc_version", 0444); @@ -1001,7 +998,7 @@ void sof_ipc3_do_rx_work(struct snd_sof_dev *sdev, struct sof_ipc_cmd_hdr *hdr, ipc3_log_header(sdev->dev, "ipc rx", hdr->cmd); - if (hdr->size < sizeof(hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) { + if (hdr->size < sizeof(*hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) { dev_err(sdev->dev, "The received message size is invalid: %u\n", hdr->size); return; diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0c905bd0fab4..db19cd03ecad 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state /* trigger a single pipeline */ if (trigger_list->count == 1) - return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state); + return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0], + state); primary = state; primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); @@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size); } -int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state) +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state) { struct sof_ipc4_msg msg = {{ 0 }}; u32 primary; - dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state); + dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state); primary = state; - primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id); + primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id); primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); @@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, * for the first time */ if (spipe->started_count == spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_RESET: /* RESET if the pipeline is neither running nor paused */ if (!spipe->started_count && !spipe->paused_count) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; case SOF_IPC4_PIPE_PAUSED: /* Pause the pipeline only when its started_count is 1 more than paused_count */ if (spipe->paused_count == (spipe->started_count - 1)) - trigger_list->pipeline_ids[trigger_list->count++] = + trigger_list->pipeline_instance_ids[trigger_list->count++] = pipe_widget->instance_id; break; default: @@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, /* set state for pipeline if it was just triggered */ for (i = 0; i < trigger_list->count; i++) { - if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) { + if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) { pipeline->state = state; break; } @@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); /* allocate memory for the pipeline data */ - trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), - GFP_KERNEL); + trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids, + pipeline_list->count), GFP_KERNEL); if (!trigger_list) return -ENOMEM; @@ -708,6 +709,9 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, struct snd_sof_pcm *spcm; spcm = snd_sof_find_spcm_dai(component, rtd); + if (!spcm) + return -EINVAL; + time_info = spcm->stream[substream->stream].private; /* delay calculation is not supported by current fw_reg ABI */ if (!time_info) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a4e1a70b607d..633f6040d712 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1731,6 +1731,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, *ipc_config_size = ipc_size; + /* update pipeline memory usage */ + sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); + /* copy IPC data */ memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); if (gtw_cfg_config_length) @@ -1743,8 +1746,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, gtw_cfg_config_length, &ipc4_copier->dma_config_tlv, dma_config_tlv_size); - /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); + /* + * Restore gateway config length now that IPC payload is prepared. This avoids + * counting the DMA CONFIG TLV multiple times + */ + copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4; return 0; } @@ -2319,6 +2325,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline->mem_usage = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); + swidget->instance_id = -EINVAL; } else { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 6dcf14886e85..d75f17f4749c 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -144,11 +144,11 @@ struct sof_ipc4_pipeline { /** * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data * @count: Number of pipelines to be triggered - * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered + * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered */ struct ipc4_pipeline_set_state_data { u32 count; - DECLARE_FLEX_ARRAY(u32, pipeline_ids); + DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids); } __packed; /** diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 3e0ea0e109e2..f587edf9e0a7 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -111,6 +111,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) dev_dbg(dev, "DMA %pR\n", &res); + adsp->pa_shared_dram = (phys_addr_t)res.start; + adsp->shared_size = resource_size(&res); + if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { + dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", + (u32)adsp->pa_shared_dram); + return -EINVAL; + } + ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -244,23 +252,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) { struct device *dev = &pdev->dev; struct mtk_adsp_chip_info *adsp = data; - u32 shared_size; /* remap shared-dram base to be non-cachable */ - shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; - adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; - if (adsp->va_dram) { - adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; - } else { - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "ioremap failed for shared DRAM\n"); - return -ENOMEM; - } + adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, + adsp->shared_size); + if (!adsp->shared_dram) { + dev_err(dev, "failed to ioremap base %pa size %#x\n", + adsp->shared_dram, adsp->shared_size); + return -ENOMEM; } - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, shared_size); + + dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", + adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); return 0; } @@ -307,9 +310,12 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) return -ENOMEM; } - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, - priv->adsp->pa_dram, - priv->adsp->dramsize); + priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM]; + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev, + priv->adsp->pa_dram, + priv->adsp->dramsize); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", &priv->adsp->pa_dram, priv->adsp->dramsize); diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index ea21ef176c42..c56a85854d92 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -146,6 +146,9 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev) struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev); struct sof_ipc4_msg msg; + if (!mentry) + return -ENODEV; + msg.primary = mentry->id; msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE); msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); @@ -197,6 +200,9 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev, struct sof_ipc4_msg msg; int i, ret; + if (!mentry) + return -ENODEV; + /* The sof_probe_point_desc and sof_ipc4_probe_point structs * are of same size and even the integers are the same in the * same order, and similar meaning, but since there is no @@ -247,6 +253,9 @@ static int ipc4_probes_points_remove(struct sof_client_dev *cdev, u32 *probe_point_ids; int i, ret; + if (!mentry) + return -ENODEV; + probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids), GFP_KERNEL); if (!probe_point_ids) diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 8d9e9d5f40e4..740b637822db 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = { .owner = THIS_MODULE, }; +static const struct snd_soc_dai_ops sof_probes_dai_ops = { + .compress_new = snd_soc_new_compress, +}; + static struct snd_soc_dai_driver sof_probes_dai_drv[] = { { .name = "Probe Extraction CPU DAI", - .compress_new = snd_soc_new_compress, + .ops = &sof_probes_dai_ops, .cops = &sof_probes_compr_ops, .capture = { .stream_name = "Probe Extraction", @@ -523,6 +527,7 @@ static void sof_probes_client_remove(struct auxiliary_device *auxdev) static const struct auxiliary_device_id sof_probes_client_id_table[] = { { .name = "snd_sof.hda-probes", }, + { .name = "snd_sof.acp-probes", }, {}, }; MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 698129dccc7d..a3a3af252259 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1117,10 +1117,11 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, { struct snd_soc_card *card = scomp->card; struct snd_soc_pcm_runtime *rtd; + const char *sname = w->sname; struct snd_soc_dai *cpu_dai; int i, stream; - if (!w->sname) + if (!sname) return; if (w->id == snd_soc_dapm_dai_out) @@ -1133,7 +1134,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || - strcmp(w->sname, rtd->dai_link->stream_name)) + strcmp(sname, rtd->dai_link->stream_name)) continue; for_each_rtd_cpu_dais(rtd, i, cpu_dai) @@ -1366,6 +1367,20 @@ err: return ret; } +static int get_w_no_wname_in_long_name(void *elem, void *object, u32 offset) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + struct snd_soc_dapm_widget *w = object; + + w->no_wname_in_kcontrol_name = !!le32_to_cpu(velem->value); + return 0; +} + +static const struct sof_topology_token dapm_widget_tokens[] = { + {SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME, SND_SOC_TPLG_TUPLE_TYPE_BOOL, + get_w_no_wname_in_long_name, 0} +}; + /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1396,6 +1411,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ida_init(&swidget->output_queue_ida); ida_init(&swidget->input_queue_ida); + ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, ARRAY_SIZE(dapm_widget_tokens), + priv->array, le32_to_cpu(priv->size)); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n", + w->name); + goto widget_free; + } + ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens, ARRAY_SIZE(comp_pin_tokens), priv->array, le32_to_cpu(priv->size)); @@ -2157,6 +2180,8 @@ static int sof_complete(struct snd_soc_component *scomp) struct snd_sof_widget *pipe_widget = spipe->pipe_widget; struct snd_sof_widget *swidget; + pipe_widget->instance_id = -EINVAL; + /* Update the scheduler widget's IPC structure */ if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) { ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget); diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 5f5a6ca7dbda..8c117794b028 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { - .startup = jh7110_tdm_startup, - .hw_params = jh7110_tdm_hw_params, - .trigger = jh7110_tdm_trigger, - .set_fmt = jh7110_tdm_set_dai_fmt, -}; - static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) { struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai); @@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = { + .probe = jh7110_tdm_dai_probe, + .startup = jh7110_tdm_startup, + .hw_params = jh7110_tdm_hw_params, + .trigger = jh7110_tdm_trigger, + .set_fmt = jh7110_tdm_set_dai_fmt, +}; + #define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000 #define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = { .formats = JH7110_TDM_FORMATS, }, .ops = &jh7110_tdm_dai_ops, - .probe = jh7110_tdm_dai_probe, .symmetric_rate = 1, }; @@ -634,10 +634,9 @@ err_pm_disable: return ret; } -static int jh7110_tdm_dev_remove(struct platform_device *pdev) +static void jh7110_tdm_dev_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static const struct of_device_id jh7110_tdm_of_match[] = { @@ -661,7 +660,7 @@ static struct platform_driver jh7110_tdm_driver = { .pm = pm_ptr(&jh7110_tdm_pm_ops), }, .probe = jh7110_tdm_probe, - .remove = jh7110_tdm_dev_remove, + .remove_new = jh7110_tdm_dev_remove, }; module_platform_driver(jh7110_tdm_driver); diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index a4d74d1e3c24..2c21a86421e6 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) return sti_uniperiph_dai_create_ctrl(dai); } -static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { +static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = { .probe = sti_uniperiph_dai_probe, }; +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .ops = &sti_uniperiph_dai_ops, +}; + static const struct snd_soc_component_driver sti_uniperiph_dai_component = { .name = "sti_cpu_dai", .suspend = sti_uniperiph_suspend, diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 387130701960..06a42130f5e4 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { }; static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { + .probe = stm32_i2s_dai_probe, .set_sysclk = stm32_i2s_set_sysclk, .set_fmt = stm32_i2s_set_dai_fmt, .startup = stm32_i2s_startup, @@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; - dai_ptr->probe = stm32_i2s_dai_probe; dai_ptr->ops = &stm32_i2s_pcm_dai_ops; dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 271ec5b3378d..42d67b7a68e8 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) } static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { + .probe = stm32_sai_dai_probe, + .set_sysclk = stm32_sai_set_sysclk, + .set_fmt = stm32_sai_set_dai_fmt, + .set_tdm_slot = stm32_sai_set_dai_tdm_slot, + .startup = stm32_sai_startup, + .hw_params = stm32_sai_hw_params, + .trigger = stm32_sai_trigger, + .shutdown = stm32_sai_shutdown, + .pcm_new = stm32_sai_pcm_new, +}; + +static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = { + .probe = stm32_sai_dai_probe, .set_sysclk = stm32_sai_set_sysclk, .set_fmt = stm32_sai_set_dai_fmt, .set_tdm_slot = stm32_sai_set_dai_tdm_slot, @@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = { }; static struct snd_soc_dai_driver stm32_sai_playback_dai = { - .probe = stm32_sai_dai_probe, - .pcm_new = stm32_sai_pcm_new, .id = 1, /* avoid call to fmt_single_name() */ .playback = { .channels_min = 1, @@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { }; static struct snd_soc_dai_driver stm32_sai_capture_dai = { - .probe = stm32_sai_dai_probe, .id = 1, /* avoid call to fmt_single_name() */ .capture = { .channels_min = 1, @@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = { SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, - .ops = &stm32_sai_pcm_dai_ops, + .ops = &stm32_sai_pcm_dai_ops2, }; static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index a4066f271f2d..a359b528b26b 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { + .probe = stm32_spdifrx_dai_probe, .startup = stm32_spdifrx_startup, .hw_params = stm32_spdifrx_hw_params, .trigger = stm32_spdifrx_trigger, @@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { { - .probe = stm32_spdifrx_dai_probe, .capture = { .stream_name = "CPU-Capture", .channels_min = 1, diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 55328850aef5..f0a5fd901101 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops dummy_dai_ops = { + .probe = sun4i_codec_dai_probe, +}; + static struct snd_soc_dai_driver dummy_cpu_dai = { .name = "sun4i-codec-cpu-dai", - .probe = sun4i_codec_dai_probe, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .ops = &dummy_dai_ops, }; static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 669d712bbe9f..5124b6c9ceb4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, return 0; } -static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { - .hw_params = sun4i_i2s_hw_params, - .set_fmt = sun4i_i2s_set_fmt, - .set_sysclk = sun4i_i2s_set_sysclk, - .set_tdm_slot = sun4i_i2s_set_tdm_slot, - .trigger = sun4i_i2s_trigger, -}; - static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { + .probe = sun4i_i2s_dai_probe, + .hw_params = sun4i_i2s_hw_params, + .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, + .trigger = sun4i_i2s_trigger, +}; + #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_driver sun4i_i2s_dai = { - .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", .channels_min = 1, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index ff18d4113aac..b849bb7cf58e 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = { + .probe = sun4i_spdif_soc_dai_probe, .startup = sun4i_spdif_startup, .trigger = sun4i_spdif_trigger, .hw_params = sun4i_spdif_hw_params, @@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { .rates = SUN4I_RATES, .formats = SUN4I_FORMATS, }, - .probe = sun4i_spdif_soc_dai_probe, .ops = &sun4i_spdif_dai_ops, .name = "spdif", }; @@ -718,7 +718,7 @@ static const struct dev_pm_ops sun4i_spdif_pm = { static struct platform_driver sun4i_spdif_driver = { .driver = { .name = "sun4i-spdif", - .of_match_table = of_match_ptr(sun4i_spdif_of_match), + .of_match_table = sun4i_spdif_of_match, .pm = &sun4i_spdif_pm, }, .probe = sun4i_spdif_probe, diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index c10439b9e0a2..2599683a582d 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = { + .probe = sun50i_dmic_soc_dai_probe, .startup = sun50i_dmic_startup, .trigger = sun50i_dmic_trigger, .hw_params = sun50i_dmic_hw_params, @@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = { .formats = SUN50I_DMIC_FORMATS, .sig_bits = 21, }, - .probe = sun50i_dmic_soc_dai_probe, .ops = &sun50i_dmic_dai_ops, .name = "dmic", }; diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index a4073a746ae3..e713feca25fa 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { - .trigger = tegra20_ac97_trigger, -}; - static int tegra20_ac97_probe(struct snd_soc_dai *dai) { struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); @@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = { + .probe = tegra20_ac97_probe, + .trigger = tegra20_ac97_trigger, +}; + static struct snd_soc_dai_driver tegra20_ac97_dai = { .name = "tegra-ac97-pcm", - .probe = tegra20_ac97_probe, .playback = { .stream_name = "PCM Playback", .channels_min = 2, @@ -328,8 +328,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) goto err; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err_clk_put; diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index d38b58305c6b..f11618e8f13e 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { + .probe = tegra20_i2s_probe, .set_fmt = tegra20_i2s_set_fmt, .hw_params = tegra20_i2s_hw_params, .trigger = tegra20_i2s_trigger, @@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { - .probe = tegra20_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index d034803695a0..b0670aa4d967 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { + .probe = tegra20_spdif_probe, .hw_params = tegra20_spdif_hw_params, .trigger = tegra20_spdif_trigger, .startup = tegra20_spdif_startup, @@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = { static struct snd_soc_dai_driver tegra20_spdif_dai = { .name = "tegra20-spdif", - .probe = tegra20_spdif_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 6868508585a0..9f9334e48049 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd, } } -static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { - .hw_params = tegra_admaif_hw_params, - .trigger = tegra_admaif_trigger, -}; - static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { + .probe = tegra_admaif_dai_probe, + .hw_params = tegra_admaif_hw_params, + .trigger = tegra_admaif_trigger, +}; + #define DAI(dai_name) \ { \ .name = dai_name, \ - .probe = tegra_admaif_dai_probe, \ .playback = { \ .stream_name = dai_name " Playback", \ .channels_min = 1, \ diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 644280603095..81eaece51130 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { + .probe = tegra30_i2s_probe, .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, @@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = { }; static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { - .probe = tegra30_i2s_probe, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 983d69b951b0..544cb3da50eb 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -257,18 +257,7 @@ static struct platform_driver davinci_evm_driver = { }, }; -static int __init evm_init(void) -{ - return platform_driver_register(&davinci_evm_driver); -} - -static void __exit evm_exit(void) -{ - platform_driver_unregister(&davinci_evm_driver); -} - -module_init(evm_init); -module_exit(evm_exit); +module_platform_driver(davinci_evm_driver); MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 97dd1634b6be..07c8b2259208 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .shutdown = davinci_i2s_shutdown, - .prepare = davinci_i2s_prepare, - .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, - .set_fmt = davinci_i2s_set_dai_fmt, - .set_clkdiv = davinci_i2s_dai_set_clkdiv, - -}; - static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); @@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .probe = davinci_i2s_dai_probe, + .shutdown = davinci_i2s_shutdown, + .prepare = davinci_i2s_prepare, + .trigger = davinci_i2s_trigger, + .hw_params = davinci_i2s_hw_params, + .set_fmt = davinci_i2s_set_dai_fmt, + .set_clkdiv = davinci_i2s_dai_set_clkdiv, + +}; + static struct snd_soc_dai_driver davinci_i2s_dai = { - .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 172fea764a31..7e7d665a5504 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, } } -static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { - .startup = davinci_mcasp_startup, - .shutdown = davinci_mcasp_shutdown, - .trigger = davinci_mcasp_trigger, - .delay = davinci_mcasp_delay, - .hw_params = davinci_mcasp_hw_params, - .set_fmt = davinci_mcasp_set_dai_fmt, - .set_clkdiv = davinci_mcasp_set_clkdiv, - .set_sysclk = davinci_mcasp_set_sysclk, - .set_tdm_slot = davinci_mcasp_set_tdm_slot, -}; - static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .probe = davinci_mcasp_dai_probe, + .startup = davinci_mcasp_startup, + .shutdown = davinci_mcasp_shutdown, + .trigger = davinci_mcasp_trigger, + .delay = davinci_mcasp_delay, + .hw_params = davinci_mcasp_hw_params, + .set_fmt = davinci_mcasp_set_dai_fmt, + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, + .set_tdm_slot = davinci_mcasp_set_tdm_slot, +}; + #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver davinci_mcasp_dai[] = { { .name = "davinci-mcasp.0", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "IIS Playback", .channels_min = 1, @@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, { .name = "davinci-mcasp.1", - .probe = davinci_mcasp_dai_probe, .playback = { .stream_name = "DIT Playback", .channels_min = 1, diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index 825c70a443da..5b5eccf303ab 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } -static const struct snd_soc_dai_ops omap_dmic_dai_ops = { - .startup = omap_dmic_dai_startup, - .shutdown = omap_dmic_dai_shutdown, - .hw_params = omap_dmic_dai_hw_params, - .prepare = omap_dmic_dai_prepare, - .trigger = omap_dmic_dai_trigger, - .set_sysclk = omap_dmic_set_dai_sysclk, -}; - static int omap_dmic_probe(struct snd_soc_dai *dai) { struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); @@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_dmic_dai_ops = { + .probe = omap_dmic_probe, + .remove = omap_dmic_remove, + .startup = omap_dmic_dai_startup, + .shutdown = omap_dmic_dai_shutdown, + .hw_params = omap_dmic_dai_hw_params, + .prepare = omap_dmic_dai_prepare, + .trigger = omap_dmic_dai_trigger, + .set_sysclk = omap_dmic_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_dmic_dai = { .name = "omap-dmic", - .probe = omap_dmic_probe, - .remove = omap_dmic_remove, .capture = { .channels_min = 2, .channels_max = 6, @@ -488,12 +488,10 @@ static int asoc_dmic_probe(struct platform_device *pdev) dmic->dma_data.filter_data = "up_link"; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - dmic->io_base = devm_ioremap_resource(&pdev->dev, res); + dmic->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); if (IS_ERR(dmic->io_base)) return PTR_ERR(dmic->io_base); - ret = devm_snd_soc_register_component(&pdev->dev, &omap_dmic_component, &omap_dmic_dai, 1); diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 21fa7b978799..fdabed5133e8 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -70,8 +70,8 @@ static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) fck_src = clk_get(mcbsp->dev, src); if (IS_ERR(fck_src)) { - dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); - return -EINVAL; + dev_info(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); + return 0; } pm_runtime_put_sync(mcbsp->dev); @@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, return err; } -static const struct snd_soc_dai_ops mcbsp_dai_ops = { - .startup = omap_mcbsp_dai_startup, - .shutdown = omap_mcbsp_dai_shutdown, - .prepare = omap_mcbsp_dai_prepare, - .trigger = omap_mcbsp_dai_trigger, - .delay = omap_mcbsp_dai_delay, - .hw_params = omap_mcbsp_dai_hw_params, - .set_fmt = omap_mcbsp_dai_set_dai_fmt, - .set_clkdiv = omap_mcbsp_dai_set_clkdiv, - .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, -}; - static int omap_mcbsp_probe(struct snd_soc_dai *dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); @@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops mcbsp_dai_ops = { + .probe = omap_mcbsp_probe, + .remove = omap_mcbsp_remove, + .startup = omap_mcbsp_dai_startup, + .shutdown = omap_mcbsp_dai_shutdown, + .prepare = omap_mcbsp_dai_prepare, + .trigger = omap_mcbsp_dai_trigger, + .delay = omap_mcbsp_dai_delay, + .hw_params = omap_mcbsp_dai_hw_params, + .set_fmt = omap_mcbsp_dai_set_dai_fmt, + .set_clkdiv = omap_mcbsp_dai_set_clkdiv, + .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, +}; + static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = omap_mcbsp_probe, - .remove = omap_mcbsp_remove, .playback = { .channels_min = 1, .channels_max = 16, diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index 0b18a7bfd3fd..d7d9f708f1fd 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { - .startup = omap_mcpdm_dai_startup, - .shutdown = omap_mcpdm_dai_shutdown, - .hw_params = omap_mcpdm_dai_hw_params, - .prepare = omap_mcpdm_prepare, -}; - static int omap_mcpdm_probe(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); @@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) return 0; } +static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { + .probe = omap_mcpdm_probe, + .remove = omap_mcpdm_remove, + .startup = omap_mcpdm_dai_startup, + .shutdown = omap_mcpdm_dai_shutdown, + .hw_params = omap_mcpdm_dai_hw_params, + .prepare = omap_mcpdm_prepare, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, +}; + #ifdef CONFIG_PM_SLEEP static int omap_mcpdm_suspend(struct snd_soc_component *component) { @@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component) #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_probe, - .remove = omap_mcpdm_remove, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .remove_order = SND_SOC_COMP_ORDER_EARLY, .playback = { .channels_min = 1, .channels_max = 5, @@ -563,8 +563,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dma_data[0].filter_data = "dn_link"; mcpdm->dma_data[1].filter_data = "up_link"; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); + mcpdm->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); if (IS_ERR(mcpdm->io_base)) return PTR_ERR(mcpdm->io_base); diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 4e8d5f7532ba..7c5188477b7c 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops uniphier_aio_i2s_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .set_fmt = uniphier_aio_set_fmt, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops); - -const struct snd_soc_dai_ops uniphier_aio_spdif_ops = { - .set_sysclk = uniphier_aio_set_sysclk, - .set_pll = uniphier_aio_set_pll, - .startup = uniphier_aio_startup, - .shutdown = uniphier_aio_shutdown, - .hw_params = uniphier_aio_hw_params, - .hw_free = uniphier_aio_hw_free, - .prepare = uniphier_aio_prepare, -}; -EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops); - -int uniphier_aio_dai_probe(struct snd_soc_dai *dai) +static int uniphier_aio_dai_probe(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); int i; @@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai) +static int uniphier_aio_dai_remove(struct snd_soc_dai *dai) { struct uniphier_aio *aio = uniphier_priv(dai); @@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai) return 0; } -EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove); + +static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) +{ + int ret; + + ret = uniphier_aio_dai_probe(dai); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); + if (ret < 0) + return ret; + ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); + if (ret < 0) + return ret; + + return 0; +} + +const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = { + .probe = uniphier_aio_ld11_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2); + +const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .set_fmt = uniphier_aio_set_fmt, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops); + +const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = { + .probe = uniphier_aio_pxs2_probe, + .remove = uniphier_aio_dai_remove, + .set_sysclk = uniphier_aio_set_sysclk, + .set_pll = uniphier_aio_set_pll, + .startup = uniphier_aio_startup, + .shutdown = uniphier_aio_shutdown, + .hw_params = uniphier_aio_hw_params, + .hw_free = uniphier_aio_hw_free, + .prepare = uniphier_aio_prepare, + .compress_new = snd_soc_new_compress, +}; +EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2); static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) { diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 7b3cf5d751f6..15dbded63804 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMIN2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .capture = { .stream_name = AUD_NAME_PCMIN2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HPCMOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 8, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_PCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops, }, { .name = AUD_NAME_EPCMOUT2, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_EPCMOUT3, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_EPCMOUT3, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_ld11_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_ld11_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_ld11_ops2, }, }; diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index 899904f7ffd6..305cb2a1253d 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = { [AUD_PLL_HSC0] = { .enable = true, }, }; -static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) -{ - int ret; - - ret = uniphier_aio_dai_probe(dai); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); - if (ret < 0) - return ret; - - return 0; -} - static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { { .name = AUD_GNAME_HDMI, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HPCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_LINE, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_GNAME_AUX, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_PCMOUT2, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_i2s_ops, + .ops = &uniphier_aio_i2s_pxs2_ops, }, { .name = AUD_NAME_HIECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_HIECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_IECOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, .playback = { .stream_name = AUD_NAME_IECOUT1, .formats = SNDRV_PCM_FMTBIT_S32_LE, @@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = { .channels_min = 2, .channels_max = 2, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops, }, { .name = AUD_NAME_HIECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_HIECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, { .name = AUD_NAME_IECCOMPOUT1, - .probe = uniphier_aio_pxs2_probe, - .remove = uniphier_aio_dai_remove, - .compress_new = snd_soc_new_compress, .playback = { .stream_name = AUD_NAME_IECCOMPOUT1, .channels_min = 1, .channels_max = 1, }, - .ops = &uniphier_aio_spdif_ops, + .ops = &uniphier_aio_spdif_pxs2_ops2, }, }; diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h index 0b03571aa9f0..09ccb47337fd 100644 --- a/sound/soc/uniphier/aio.h +++ b/sound/soc/uniphier/aio.h @@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai) int uniphier_aiodma_soc_register_platform(struct platform_device *pdev); extern const struct snd_compress_ops uniphier_aio_compress_ops; -int uniphier_aio_dai_probe(struct snd_soc_dai *dai); -int uniphier_aio_dai_remove(struct snd_soc_dai *dai); int uniphier_aio_probe(struct platform_device *pdev); int uniphier_aio_remove(struct platform_device *pdev); -extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops; -extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops; +extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2; u64 aio_rb_cnt(struct uniphier_aio_sub *sub); u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub); diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 44e88dad8584..cde0dd8e2569 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { { + .probe = ux500_msp_dai_of_probe, .set_sysclk = ux500_msp_dai_set_dai_sysclk, .set_fmt = ux500_msp_dai_set_dai_fmt, .set_tdm_slot = ux500_msp_dai_set_tdm_slot, @@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = { }; static struct snd_soc_dai_driver ux500_msp_dai_drv = { - .probe = ux500_msp_dai_of_probe, .playback.channels_min = UX500_MSP_MIN_CHANNELS, .playback.channels_max = UX500_MSP_MAX_CHANNELS, .playback.rates = UX500_I2S_RATES, diff --git a/tools/testing/kunit/configs/all_tests.config b/tools/testing/kunit/configs/all_tests.config index 0393940c706a..b8adb59455ef 100644 --- a/tools/testing/kunit/configs/all_tests.config +++ b/tools/testing/kunit/configs/all_tests.config @@ -35,3 +35,8 @@ CONFIG_DAMON_DBGFS=y CONFIG_SECURITY=y CONFIG_SECURITY_APPARMOR=y + +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TOPOLOGY_BUILD=y |