diff options
21 files changed, 761 insertions, 421 deletions
diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt deleted file mode 100644 index 94584c96c4ae..000000000000 --- a/Documentation/devicetree/bindings/sound/da7213.txt +++ /dev/null @@ -1,45 +0,0 @@ -Dialog Semiconductor DA7212/DA7213 Audio Codec bindings - -====== - -Required properties: -- compatible : Should be "dlg,da7212" or "dlg,da7213" -- reg: Specifies the I2C slave address - -Optional properties: -- clocks : phandle and clock specifier for codec MCLK. -- clock-names : Clock name string for 'clocks' attribute, should be "mclk". - -- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1 - [<1600>, <2200>, <2500>, <3000>] -- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2 - [<1600>, <2200>, <2500>, <3000>] -- dlg,dmic-data-sel : DMIC channel select based on clock edge. - ["lrise_rfall", "lfall_rrise"] -- dlg,dmic-samplephase : When to sample audio from DMIC. - ["on_clkedge", "between_clkedge"] -- dlg,dmic-clkrate : DMIC clock frequency (Hz). - [<1500000>, <3000000>] - - - VDDA-supply : Regulator phandle for Analogue power supply - - VDDMIC-supply : Regulator phandle for Mic Bias - - VDDIO-supply : Regulator phandle for I/O power supply - -====== - -Example: - - codec_i2c: da7213@1a { - compatible = "dlg,da7213"; - reg = <0x1a>; - - clocks = <&clks 201>; - clock-names = "mclk"; - - dlg,micbias1-lvl = <2500>; - dlg,micbias2-lvl = <2500>; - - dlg,dmic-data-sel = "lrise_rfall"; - dlg,dmic-samplephase = "between_clkedge"; - dlg,dmic-clkrate = <3000000>; - }; diff --git a/Documentation/devicetree/bindings/sound/dlg,da7213.yaml b/Documentation/devicetree/bindings/sound/dlg,da7213.yaml new file mode 100644 index 000000000000..c2dede1e82ff --- /dev/null +++ b/Documentation/devicetree/bindings/sound/dlg,da7213.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/dlg,da7213.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dialog Semiconductor DA7212/DA7213 Audio Codec + +maintainers: + - Support Opensource <support.opensource@diasemi.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - dlg,da7212 + - dlg,da7213 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: mclk + + "#sound-dai-cells": + const: 0 + + dlg,micbias1-lvl: + description: Voltage (mV) for Mic Bias 1 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1600, 2200, 2500, 3000 ] + + dlg,micbias2-lvl: + description: Voltage (mV) for Mic Bias 2 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1600, 2200, 2500, 3000 ] + + dlg,dmic-data-sel: + description: DMIC channel select based on clock edge + enum: [ lrise_rfall, lfall_rrise ] + + dlg,dmic-samplephase: + description: When to sample audio from DMIC + enum: [ on_clkedge, between_clkedge ] + + dlg,dmic-clkrate: + description: DMIC clock frequency (Hz) + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1500000, 3000000 ] + + VDDA-supply: + description: Analogue power supply + + VDDIO-supply: + description: I/O power supply + + VDDMIC-supply: + description: Mic Bias + + VDDSP-supply: + description: Speaker supply + + ports: + $ref: audio-graph-port.yaml#/definitions/ports + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "dlg,da7213"; + reg = <0x1a>; + + clocks = <&clks 201>; + clock-names = "mclk"; + + #sound-dai-cells = <0>; + + dlg,micbias1-lvl = <2500>; + dlg,micbias2-lvl = <2500>; + + dlg,dmic-data-sel = "lrise_rfall"; + dlg,dmic-samplephase = "between_clkedge"; + dlg,dmic-clkrate = <3000000>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml new file mode 100644 index 000000000000..5eb6f5812cf2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,imx-audio-es8328.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,imx-audio-es8328.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX audio complex with ES8328 codec + +maintainers: + - Shawn Guo <shawnguo@kernel.org> + - Sascha Hauer <s.hauer@pengutronix.de> + +allOf: + - $ref: sound-card-common.yaml# + +properties: + compatible: + const: fsl,imx-audio-es8328 + + model: + $ref: /schemas/types.yaml#/definitions/string + description: The user-visible name of this sound complex + + ssi-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the i.MX SSI controller + + jack-gpio: + description: Optional GPIO for headphone jack + maxItems: 1 + + audio-amp-supply: + description: Power regulator for speaker amps + + audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle to the ES8328 audio codec + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. Each entry + is a pair of strings, the first being the connection's sink, the second + being the connection's source. Valid names could be power supplies, + ES8328 pins, and the jacks on the board: + + Power supplies: + * audio-amp + + ES8328 pins: + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * LINPUT2 + * RINPUT1 + * RINPUT2 + * Mic PGA + + Board connectors: + * Headphone + * Speaker + * Mic Jack + + mux-int-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The internal port of the i.MX audio muxer (AUDMUX) + enum: [1, 2, 7] + default: 1 + + mux-ext-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The external port of the i.MX audio muxer (AUDMIX) + enum: [3, 4, 5, 6] + default: 3 + +required: + - compatible + - model + - ssi-controller + - jack-gpio + - audio-amp-supply + - audio-codec + - audio-routing + - mux-int-port + - mux-ext-port + +unevaluatedProperties: false + +examples: + - | + sound { + compatible = "fsl,imx-audio-es8328"; + model = "imx-audio-es8328"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + jack-gpio = <&gpio5 15 0>; + audio-amp-supply = <®_audio_amp>; + audio-routing = + "Speaker", "LOUT2", + "Speaker", "ROUT2", + "Speaker", "audio-amp", + "Headphone", "ROUT1", + "Headphone", "LOUT1", + "LINPUT1", "Mic Jack", + "RINPUT1", "Mic Jack", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <3>; + }; diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt deleted file mode 100644 index 07b68ab206fb..000000000000 --- a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt +++ /dev/null @@ -1,60 +0,0 @@ -Freescale i.MX audio complex with ES8328 codec - -Required properties: -- compatible : "fsl,imx-audio-es8328" -- model : The user-visible name of this sound complex -- ssi-controller : The phandle of the i.MX SSI controller -- jack-gpio : Optional GPIO for headphone jack -- audio-amp-supply : Power regulator for speaker amps -- audio-codec : The phandle of the ES8328 audio codec -- audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, ES8328 - pins, and the jacks on the board: - - Power supplies: - * audio-amp - - ES8328 pins: - * LOUT1 - * LOUT2 - * ROUT1 - * ROUT2 - * LINPUT1 - * LINPUT2 - * RINPUT1 - * RINPUT2 - * Mic PGA - - Board connectors: - * Headphone - * Speaker - * Mic Jack -- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) -- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX) - -Note: The AUDMUX port numbering should start at 1, which is consistent with -hardware manual. - -Example: - -sound { - compatible = "fsl,imx-audio-es8328"; - model = "imx-audio-es8328"; - ssi-controller = <&ssi1>; - audio-codec = <&codec>; - jack-gpio = <&gpio5 15 0>; - audio-amp-supply = <®_audio_amp>; - audio-routing = - "Speaker", "LOUT2", - "Speaker", "ROUT2", - "Speaker", "audio-amp", - "Headphone", "ROUT1", - "Headphone", "LOUT1", - "LINPUT1", "Mic Jack", - "RINPUT1", "Mic Jack", - "Mic Jack", "Mic Bias"; - mux-int-port = <1>; - mux-ext-port = <3>; -}; diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt deleted file mode 100644 index 47878a6df608..000000000000 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt +++ /dev/null @@ -1,53 +0,0 @@ -PCM512x and TAS575x audio CODECs/amplifiers - -These devices support both I2C and SPI (configured with pin strapping -on the board). The TAS575x devices only support I2C. - -Required properties: - - - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141", - "ti,pcm5142", "ti,pcm5242", "ti,tas5754" or "ti,tas5756" - - - reg : the I2C address of the device for I2C, the chip select - number for SPI. - - - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the - device, as covered in bindings/regulator/regulator.txt - -Optional properties: - - - clocks : A clock specifier for the clock connected as SCLK. If this - is absent the device will be configured to clock from BCLK. If pll-in - and pll-out are specified in addition to a clock, the device is - configured to accept clock input on a specified gpio pin. - - - pll-in, pll-out : gpio pins used to connect the pll using <1> - through <6>. The device will be configured for clock input on the - given pll-in pin and PLL output on the given pll-out pin. An - external connection from the pll-out pin to the SCLK pin is assumed. - Caution: the TAS-desvices only support gpios 1,2 and 3 - -Examples: - - pcm5122: pcm5122@4c { - compatible = "ti,pcm5122"; - reg = <0x4c>; - - AVDD-supply = <®_3v3_analog>; - DVDD-supply = <®_1v8>; - CPVDD-supply = <®_3v3>; - }; - - - pcm5142: pcm5142@4c { - compatible = "ti,pcm5142"; - reg = <0x4c>; - - AVDD-supply = <®_3v3_analog>; - DVDD-supply = <®_1v8>; - CPVDD-supply = <®_3v3>; - - clocks = <&sck>; - pll-in = <3>; - pll-out = <6>; - }; diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml new file mode 100644 index 000000000000..6ad451549036 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc-sndcard.yaml @@ -0,0 +1,205 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,apq8016-sbc-sndcard.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm APQ8016 and similar sound cards + +maintainers: + - Srinivas Kandagatla <srinivas.kandagatla@linaro.org> + - Stephan Gerhold <stephan@gerhold.net> + +properties: + compatible: + enum: + - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard + + reg: + items: + - description: Microphone I/O mux register address + - description: Speaker I/O mux register address + + reg-names: + items: + - const: mic-iomux + - const: spkr-iomux + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: + A list of the connections between audio components. Each entry is a + pair of strings, the first being the connection's sink, the second + being the connection's source. Valid names could be power supplies, + MicBias of codec and the jacks on the board. + + aux-devs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + + model: + $ref: /schemas/types.yaml#/definitions/string + description: User visible long sound card name + + pin-switches: + description: List of widget names for which pin switches should be created. + $ref: /schemas/types.yaml#/definitions/string-array + + widgets: + description: User specified audio sound widgets. + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + +patternProperties: + ".*-dai-link$": + description: + Each subnode represents a dai link. Subnodes of each dai links would be + cpu/codec dais. + + type: object + + properties: + link-name: + description: Indicates dai-link name and PCM stream name. + $ref: /schemas/types.yaml#/definitions/string + maxItems: 1 + + cpu: + description: Holds subnode which indicates cpu dai. + type: object + additionalProperties: false + + properties: + sound-dai: + maxItems: 1 + + platform: + description: Holds subnode which indicates platform dai. + type: object + additionalProperties: false + + properties: + sound-dai: + maxItems: 1 + + codec: + description: Holds subnode which indicates codec dai. + type: object + additionalProperties: false + + properties: + sound-dai: + minItems: 1 + maxItems: 8 + + required: + - link-name + - cpu + + additionalProperties: false + +required: + - compatible + - reg + - reg-names + - model + +additionalProperties: false + +examples: + - | + #include <dt-bindings/sound/qcom,lpass.h> + sound@7702000 { + compatible = "qcom,apq8016-sbc-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "DB410c"; + audio-routing = + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; + pinctrl-names = "default", "sleep"; + + quaternary-dai-link { + link-name = "ADV7533"; + cpu { + sound-dai = <&lpass MI2S_QUATERNARY>; + }; + codec { + sound-dai = <&adv_bridge 0>; + }; + }; + + primary-dai-link { + link-name = "WCD"; + cpu { + sound-dai = <&lpass MI2S_PRIMARY>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + + tertiary-dai-link { + link-name = "WCD-Capture"; + cpu { + sound-dai = <&lpass MI2S_TERTIARY>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; + }; + }; + }; + + - | + #include <dt-bindings/sound/qcom,q6afe.h> + #include <dt-bindings/sound/qcom,q6asm.h> + sound@7702000 { + compatible = "qcom,msm8916-qdsp6-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "msm8916"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; + audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; + aux-devs = <&speaker_amp>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cdc_pdm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + primary-dai-link { + link-name = "Primary MI2S"; + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index c9076dcd44c1..1d3acdc0c733 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -27,9 +27,7 @@ properties: - qcom,sm8650-sndcard - const: qcom,sm8450-sndcard - enum: - - qcom,apq8016-sbc-sndcard - qcom,apq8096-sndcard - - qcom,msm8916-qdsp6-sndcard - qcom,qcm6490-idp-sndcard - qcom,qcs6490-rb3gen2-sndcard - qcom,qrb5165-rb5-sndcard @@ -58,18 +56,6 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name - pin-switches: - description: List of widget names for which pin switches should be created. - $ref: /schemas/types.yaml#/definitions/string-array - - widgets: - description: User specified audio sound widgets. - $ref: /schemas/types.yaml#/definitions/non-unique-string-array - - # Only valid for some compatibles (see allOf if below) - reg: true - reg-names: true - patternProperties: ".*-dai-link$": description: @@ -122,34 +108,6 @@ required: - compatible - model -allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,apq8016-sbc-sndcard - - qcom,msm8916-qdsp6-sndcard - then: - properties: - reg: - items: - - description: Microphone I/O mux register address - - description: Speaker I/O mux register address - reg-names: - items: - - const: mic-iomux - - const: spkr-iomux - required: - - compatible - - model - - reg - - reg-names - else: - properties: - reg: false - reg-names: false - additionalProperties: false examples: @@ -231,98 +189,3 @@ examples: }; }; }; - - - | - #include <dt-bindings/sound/qcom,lpass.h> - sound@7702000 { - compatible = "qcom,apq8016-sbc-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - - model = "DB410c"; - audio-routing = - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS External1"; - - pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; - pinctrl-names = "default", "sleep"; - - quaternary-dai-link { - link-name = "ADV7533"; - cpu { - sound-dai = <&lpass MI2S_QUATERNARY>; - }; - codec { - sound-dai = <&adv_bridge 0>; - }; - }; - - primary-dai-link { - link-name = "WCD"; - cpu { - sound-dai = <&lpass MI2S_PRIMARY>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - - tertiary-dai-link { - link-name = "WCD-Capture"; - cpu { - sound-dai = <&lpass MI2S_TERTIARY>; - }; - codec { - sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; - }; - }; - }; - - - | - #include <dt-bindings/sound/qcom,q6afe.h> - #include <dt-bindings/sound/qcom,q6asm.h> - sound@7702000 { - compatible = "qcom,msm8916-qdsp6-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - - model = "msm8916"; - widgets = - "Speaker", "Speaker", - "Headphone", "Headphones"; - pin-switches = "Speaker"; - audio-routing = - "Speaker", "Speaker Amp OUT", - "Speaker Amp IN", "HPH_R", - "Headphones", "HPH_L", - "Headphones", "HPH_R", - "AMIC1", "MIC BIAS Internal1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS Internal3"; - aux-devs = <&speaker_amp>; - - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&cdc_pdm_lines_act>; - pinctrl-1 = <&cdc_pdm_lines_sus>; - - mm1-dai-link { - link-name = "MultiMedia1"; - cpu { - sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; - }; - }; - - primary-dai-link { - link-name = "Primary MI2S"; - cpu { - sound-dai = <&q6afedai PRIMARY_MI2S_RX>; - }; - platform { - sound-dai = <&q6routing>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml index 8b9695f5decc..f4610eaed1e1 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml @@ -87,6 +87,10 @@ properties: '#sound-dai-cells': const: 0 + port: + $ref: audio-graph-port.yaml#/definitions/port-base + description: Connection to controller providing I2S signals + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml b/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml new file mode 100644 index 000000000000..21ea9ff5a2bb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,pcm512x.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,pcm512x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PCM512x and TAS575x audio CODECs/amplifiers + +maintainers: + - Animesh Agarwal <animeshagarwal28@gmail.com> + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - ti,pcm5121 + - ti,pcm5122 + - ti,pcm5141 + - ti,pcm5142 + - ti,pcm5242 + - ti,tas5754 + - ti,tas5756 + + reg: + maxItems: 1 + + AVDD-supply: true + + DVDD-supply: true + + CPVDD-supply: true + + clocks: + maxItems: 1 + description: A clock specifier for the clock connected as SCLK. If this is + absent the device will be configured to clock from BCLK. If pll-in and + pll-out are specified in addition to a clock, the device is configured to + accept clock input on a specified gpio pin. + + '#sound-dai-cells': + const: 0 + + pll-in: + description: GPIO pin used to connect the pll using <1> through <6>. The + device will be configured for clock input on the given pll-in pin. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 6 + + pll-out: + description: GPIO pin used to connect the pll using <1> through <6>. The + device will be configured for PLL output on the given pll-out pin. An + external connection from the pll-out pin to the SCLK pin is assumed. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 6 + +required: + - compatible + - reg + - AVDD-supply + - DVDD-supply + - CPVDD-supply + +if: + properties: + compatible: + contains: + enum: + - ti,tas5754 + - ti,tas5756 + +then: + properties: + pll-in: + maximum: 3 + + pll-out: + maximum: 3 + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@4c { + compatible = "ti,pcm5142"; + reg = <0x4c>; + AVDD-supply = <®_3v3_analog>; + DVDD-supply = <®_1v8>; + CPVDD-supply = <®_3v3>; + #sound-dai-cells = <0>; + clocks = <&sck>; + pll-in = <3>; + pll-out = <6>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 42decde38320..88a40557db32 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6500,6 +6500,7 @@ F: Documentation/devicetree/bindings/regulator/da92*.txt F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml F: Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml F: Documentation/devicetree/bindings/sound/da[79]*.txt +F: Documentation/devicetree/bindings/sound/dlg,da7213.yaml F: Documentation/devicetree/bindings/thermal/dlg,da9062-thermal.yaml F: Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml F: Documentation/hwmon/da90??.rst diff --git a/include/sound/soc.h b/include/sound/soc.h index a8e66bbf932b..e844f6afc5b5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1209,8 +1209,9 @@ struct snd_soc_pcm_runtime { bool initialized; + /* CPU/Codec/Platform */ int num_components; - struct snd_soc_component *components[]; /* CPU/Codec/Platform */ + struct snd_soc_component *components[] __counted_by(num_components); }; /* see soc_new_pcm_runtime() */ diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index 94a66a325303..29891c1f6bec 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -323,15 +323,15 @@ static int cs42l42_sdw_read_prop(struct sdw_slave *peripheral) prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; /* DP1 - capture */ - ports[0].num = CS42L42_SDW_CAPTURE_PORT, - ports[0].type = SDW_DPN_FULL, - ports[0].ch_prep_timeout = 10, + ports[0].num = CS42L42_SDW_CAPTURE_PORT; + ports[0].type = SDW_DPN_FULL; + ports[0].ch_prep_timeout = 10; prop->src_dpn_prop = &ports[0]; /* DP2 - playback */ - ports[1].num = CS42L42_SDW_PLAYBACK_PORT, - ports[1].type = SDW_DPN_FULL, - ports[1].ch_prep_timeout = 10, + ports[1].num = CS42L42_SDW_PLAYBACK_PORT; + ports[1].type = SDW_DPN_FULL; + ports[1].ch_prep_timeout = 10; prop->sink_dpn_prop = &ports[1]; return 0; diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index b246694ebb4f..60877116c0ef 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -805,6 +805,7 @@ static void es8326_jack_button_handler(struct work_struct *work) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2); button_to_report = 0; } + es8326_disable_micbias(es8326->component); } mutex_unlock(&es8326->lock); } @@ -878,7 +879,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x00); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x00); - es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x10); @@ -897,6 +897,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) dev_dbg(comp->dev, "button pressed\n"); regmap_write(es8326->regmap, ES8326_INT_SOURCE, (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + es8326_enable_micbias(es8326->component); queue_delayed_work(system_wq, &es8326->button_press_work, 10); goto exit; } @@ -1067,6 +1068,7 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f); regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff); + es8326_disable_micbias(es8326->component); msleep(200); regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 73a588289408..76900274acf3 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2297,36 +2297,37 @@ static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); u32 enable = ucontrol->value.integer.value[0]; u32 spk_tx_id = mixer->shift; + u32 dai_id = widget->shift; if (enable) { if (spk_tx_id == WSA_MACRO_TX0 && !test_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { set_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]++; } if (spk_tx_id == WSA_MACRO_TX1 && !test_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { set_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]++; } } else { if (spk_tx_id == WSA_MACRO_TX0 && test_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { clear_bit(WSA_MACRO_TX0, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]--; } if (spk_tx_id == WSA_MACRO_TX1 && test_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + &wsa->active_ch_mask[dai_id])) { clear_bit(WSA_MACRO_TX1, - &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); - wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + &wsa->active_ch_mask[dai_id]); + wsa->active_ch_cnt[dai_id]--; } } snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index f50f196d700d..ce2e88e066f3 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2828,7 +2828,9 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component) } if (dev->of_node) { - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw); + if (ret) + return ret; } else { ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw, init.name, dev_name(dev)); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index a5e05c05fd3d..b4beb587e916 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -682,7 +682,6 @@ struct wsa881x_priv { * For backwards compatibility. */ unsigned int sd_n_val; - int version; int active_ports; bool port_prepared[WSA881X_MAX_SWR_PORTS]; bool port_enable[WSA881X_MAX_SWR_PORTS]; @@ -693,7 +692,6 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) struct regmap *rm = wsa881x->regmap; unsigned int val = 0; - regmap_read(rm, WSA881X_CHIP_ID1, &wsa881x->version); regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0, ARRAY_SIZE(wsa881x_rev_2_0)); diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 9dc2e4d96b10..f0520a896706 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -438,8 +438,6 @@ struct wsa883x_priv { struct gpio_desc *sd_n; bool port_prepared[WSA883X_MAX_SWR_PORTS]; bool port_enable[WSA883X_MAX_SWR_PORTS]; - int version; - int variant; int active_ports; int dev_mode; int comp_offset; @@ -999,33 +997,36 @@ static const struct reg_sequence reg_init[] = { {WSA883X_GMAMP_SUP1, 0xE2}, }; -static void wsa883x_init(struct wsa883x_priv *wsa883x) +static int wsa883x_init(struct wsa883x_priv *wsa883x) { struct regmap *regmap = wsa883x->regmap; - int variant, version; + int variant, version, ret; - regmap_read(regmap, WSA883X_OTP_REG_0, &variant); - wsa883x->variant = variant & WSA883X_ID_MASK; + ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); + if (ret) + return ret; + variant = variant & WSA883X_ID_MASK; - regmap_read(regmap, WSA883X_CHIP_ID0, &version); - wsa883x->version = version; + ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version); + if (ret) + return ret; - switch (wsa883x->variant) { + switch (variant) { case WSA8830: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n", - wsa883x->version); + version); break; case WSA8835: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n", - wsa883x->version); + version); break; case WSA8832: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n", - wsa883x->version); + version); break; case WSA8835_V2: dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n", - wsa883x->version); + version); break; default: break; @@ -1036,12 +1037,14 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x) /* Initial settings */ regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init)); - if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) { + if (variant == WSA8830 || variant == WSA8832) { wsa883x->comp_offset = COMP_OFFSET3; regmap_update_bits(regmap, WSA883X_DRE_CTL_0, WSA883X_DRE_OFFSET_MASK, wsa883x->comp_offset); } + + return 0; } static int wsa883x_update_status(struct sdw_slave *slave, @@ -1050,7 +1053,7 @@ static int wsa883x_update_status(struct sdw_slave *slave, struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) - wsa883x_init(wsa883x); + return wsa883x_init(wsa883x); return 0; } diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index d3d09c3bab2d..ac927be93264 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -703,7 +703,6 @@ struct wsa884x_priv { struct reset_control *sd_reset; bool port_prepared[WSA884X_MAX_SWR_PORTS]; bool port_enable[WSA884X_MAX_SWR_PORTS]; - unsigned int variant; int active_ports; int dev_mode; bool hw_init; @@ -1475,7 +1474,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) unsigned int variant = 0; if (!regmap_read(wsa884x->regmap, WSA884X_OTP_REG_0, &variant)) - wsa884x->variant = variant & WSA884X_OTP_REG_0_ID_MASK; + variant = variant & WSA884X_OTP_REG_0_ID_MASK; regmap_multi_reg_write(wsa884x->regmap, wsa884x_reg_init, ARRAY_SIZE(wsa884x_reg_init)); @@ -1484,7 +1483,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK, WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER); /* Assume that compander is enabled by default unless it is haptics sku */ - if (wsa884x->variant == WSA884X_OTP_ID_WSA8845H) + if (variant == WSA884X_OTP_ID_WSA8845H) wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK, WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB); else diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 8b323fb19925..db00704e206d 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1108,9 +1108,7 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data) err_headset_codec: of_node_put(speaker_codec); err_speaker_codec: - if (hdmi_codec) - of_node_put(hdmi_codec); - + of_node_put(hdmi_codec); return ret; } diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index 9d103646973a..d0bf0487bf1b 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -52,6 +52,7 @@ #define SSIFCR_RIE BIT(2) #define SSIFCR_TFRST BIT(1) #define SSIFCR_RFRST BIT(0) +#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST) #define SSIFSR_TDC_MASK 0x3f #define SSIFSR_TDC_SHIFT 24 @@ -130,6 +131,14 @@ struct rz_ssi_priv { bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */ bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ bool dma_rt; + + /* Full duplex communication support */ + struct { + unsigned int rate; + unsigned int channels; + unsigned int sample_width; + unsigned int sample_bits; + } hw_params_cache; }; static void rz_ssi_dma_complete(void *data); @@ -208,6 +217,11 @@ static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, return ret; } +static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) +{ + return strm->substream && strm->running; +} + static void rz_ssi_stream_init(struct rz_ssi_stream *strm, struct snd_pcm_substream *substream) { @@ -303,13 +317,53 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, return 0; } +static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) +{ + int timeout; + + /* Disable irqs */ + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | + SSICR_RUIEN | SSICR_ROIEN, 0); + rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0); + + /* Clear all error flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, + (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | + SSISR_RUIRQ), 0); + + /* Wait for idle */ + timeout = 100; + while (--timeout) { + if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ) + break; + udelay(1); + } + + if (!timeout) + dev_info(ssi->dev, "timeout waiting for SSI idle\n"); + + /* Hold FIFOs in reset */ + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, + SSIFCR_TFRST | SSIFCR_RFRST); +} + static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); + bool is_full_duplex; u32 ssicr, ssifcr; + is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture); ssicr = rz_ssi_reg_readl(ssi, SSICR); - ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF; + ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); + if (!is_full_duplex) { + ssifcr &= ~0xF; + } else { + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + rz_ssi_set_idle(ssi); + ssifcr &= ~SSIFCR_FIFO_RST; + } /* FIFO interrupt thresholds */ if (rz_ssi_is_dma_enabled(ssi)) @@ -322,10 +376,14 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) /* enable IRQ */ if (is_play) { ssicr |= SSICR_TUIEN | SSICR_TOIEN; - ssifcr |= SSIFCR_TIE | SSIFCR_RFRST; + ssifcr |= SSIFCR_TIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_RFRST; } else { ssicr |= SSICR_RUIEN | SSICR_ROIEN; - ssifcr |= SSIFCR_RIE | SSIFCR_TFRST; + ssifcr |= SSIFCR_RIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_TFRST; } rz_ssi_reg_writel(ssi, SSICR, ssicr); @@ -337,7 +395,11 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) SSISR_RUIRQ), 0); strm->running = 1; - ssicr |= is_play ? SSICR_TEN : SSICR_REN; + if (is_full_duplex) + ssicr |= SSICR_TEN | SSICR_REN; + else + ssicr |= is_play ? SSICR_TEN : SSICR_REN; + rz_ssi_reg_writel(ssi, SSICR, ssicr); return 0; @@ -345,10 +407,12 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { - int timeout; - strm->running = 0; + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) + return 0; + /* Disable TX/RX */ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); @@ -356,30 +420,7 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) if (rz_ssi_is_dma_enabled(ssi)) dmaengine_terminate_async(strm->dma_ch); - /* Disable irqs */ - rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | - SSICR_RUIEN | SSICR_ROIEN, 0); - rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0); - - /* Clear all error flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, - (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ), 0); - - /* Wait for idle */ - timeout = 100; - while (--timeout) { - if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ) - break; - udelay(1); - } - - if (!timeout) - dev_info(ssi->dev, "timeout waiting for SSI idle\n"); - - /* Hold FIFOs in reset */ - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, - SSIFCR_TFRST | SSIFCR_RFRST); + rz_ssi_set_idle(ssi); return 0; } @@ -512,66 +553,90 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) static irqreturn_t rz_ssi_interrupt(int irq, void *data) { - struct rz_ssi_stream *strm = NULL; + struct rz_ssi_stream *strm_playback = NULL; + struct rz_ssi_stream *strm_capture = NULL; struct rz_ssi_priv *ssi = data; u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); if (ssi->playback.substream) - strm = &ssi->playback; - else if (ssi->capture.substream) - strm = &ssi->capture; - else + strm_playback = &ssi->playback; + if (ssi->capture.substream) + strm_capture = &ssi->capture; + + if (!strm_playback && !strm_capture) return IRQ_HANDLED; /* Left over TX/RX interrupt */ if (irq == ssi->irq_int) { /* error or idle */ - if (ssisr & SSISR_TUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_TOIRQ) - strm->oerr_num++; - if (ssisr & SSISR_RUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_ROIRQ) - strm->oerr_num++; - - if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ | - SSISR_ROIRQ)) { - /* Error handling */ - /* You must reset (stop/restart) after each interrupt */ - rz_ssi_stop(ssi, strm); - - /* Clear all flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | - SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ, 0); - - /* Add/remove more data */ - strm->transfer(ssi, strm); - - /* Resume */ - rz_ssi_start(ssi, strm); + bool is_stopped = false; + int i, count; + + if (rz_ssi_is_dma_enabled(ssi)) + count = 4; + else + count = 1; + + if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ)) + is_stopped = true; + + if (ssi->capture.substream && is_stopped) { + if (ssisr & SSISR_RUIRQ) + strm_capture->uerr_num++; + if (ssisr & SSISR_ROIRQ) + strm_capture->oerr_num++; + + rz_ssi_stop(ssi, strm_capture); } + + if (ssi->playback.substream && is_stopped) { + if (ssisr & SSISR_TUIRQ) + strm_playback->uerr_num++; + if (ssisr & SSISR_TOIRQ) + strm_playback->oerr_num++; + + rz_ssi_stop(ssi, strm_playback); + } + + /* Clear all flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ | + SSISR_ROIRQ | SSISR_RUIRQ, 0); + + /* Add/remove more data */ + if (ssi->capture.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_capture->transfer(ssi, strm_capture); + } + + if (ssi->playback.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_playback->transfer(ssi, strm_playback); + } + + /* Resume */ + if (ssi->playback.substream && is_stopped) + rz_ssi_start(ssi, &ssi->playback); + if (ssi->capture.substream && is_stopped) + rz_ssi_start(ssi, &ssi->capture); } - if (!strm->running) + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) return IRQ_HANDLED; /* tx data empty */ - if (irq == ssi->irq_tx) - strm->transfer(ssi, &ssi->playback); + if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback)) + strm_playback->transfer(ssi, &ssi->playback); /* rx data full */ - if (irq == ssi->irq_rx) { - strm->transfer(ssi, &ssi->capture); + if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) { + strm_capture->transfer(ssi, &ssi->capture); rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); } if (irq == ssi->irq_rt) { - struct snd_pcm_substream *substream = strm->substream; - - if (rz_ssi_stream_is_play(ssi, substream)) { - strm->transfer(ssi, &ssi->playback); + if (ssi->playback.substream) { + strm_playback->transfer(ssi, &ssi->playback); } else { - strm->transfer(ssi, &ssi->capture); + strm_capture->transfer(ssi, &ssi->capture); rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); } } @@ -731,9 +796,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Soft Reset */ - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); - rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); - udelay(5); + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) { + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); + rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); + udelay(5); + } rz_ssi_stream_init(strm, substream); @@ -824,14 +892,41 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + if (ssi->hw_params_cache.rate != rate || + ssi->hw_params_cache.channels != channels || + ssi->hw_params_cache.sample_width != sample_width || + ssi->hw_params_cache.sample_bits != sample_bits) + return false; + + return true; +} + +static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + ssi->hw_params_cache.rate = rate; + ssi->hw_params_cache.channels = channels; + ssi->hw_params_cache.sample_width = sample_width; + ssi->hw_params_cache.sample_bits = sample_bits; +} + static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); unsigned int sample_bits = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); if (sample_bits != 16) { dev_err(ssi->dev, "Unsupported sample width: %d\n", @@ -845,8 +940,20 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return rz_ssi_clk_setup(ssi, params_rate(params), - params_channels(params)); + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) { + if (rz_ssi_is_valid_hw_params(ssi, rate, channels, + strm->sample_width, sample_bits)) + return 0; + + dev_err(ssi->dev, "Full duplex needs same HW params\n"); + return -EINVAL; + } + + rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, + sample_bits); + + return rz_ssi_clk_setup(ssi, rate, channels); } static const struct snd_soc_dai_ops rz_ssi_dai_ops = { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 724fe1f033b5..80bacea6bb90 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -326,8 +326,8 @@ static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, } /* see for_each_rtd_components */ - rtd->components[rtd->num_components] = component; - rtd->num_components++; + rtd->num_components++; // increment flex array count at first + rtd->components[rtd->num_components - 1] = component; return 0; } @@ -494,7 +494,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_component *component; struct device *dev; int ret; int stream; @@ -521,10 +520,10 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( * for rtd */ rtd = devm_kzalloc(dev, - sizeof(*rtd) + - sizeof(component) * (dai_link->num_cpus + - dai_link->num_codecs + - dai_link->num_platforms), + struct_size(rtd, components, + dai_link->num_cpus + + dai_link->num_codecs + + dai_link->num_platforms), GFP_KERNEL); if (!rtd) { device_unregister(dev); |