summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-03 16:20:52 +0100
committerMark Brown <broonie@kernel.org>2026-07-03 16:20:52 +0100
commit73f0667220a40b4130f3ed25613ebb48967310c9 (patch)
treeb6931e370fa7d3d1f0421ac3760c772bcc19336a
parenta36ec651038d3a9c92d2b0373f28c177d791df30 (diff)
parentdbde3bfa3d31eb57c505ca3f577f118f8cf695c5 (diff)
downloadlinux-next-73f0667220a40b4130f3ed25613ebb48967310c9.tar.gz
linux-next-73f0667220a40b4130f3ed25613ebb48967310c9.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml240
-rw-r--r--Documentation/devicetree/bindings/sound/cs35l36.txt168
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml53
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml22
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml59
-rw-r--r--Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt24
-rw-r--r--include/sound/soc_sdw_utils.h31
-rw-r--r--include/sound/sof/dai.h1
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c2
-rw-r--r--sound/soc/amd/acp/acp-sdw-sof-mach.c2
-rw-r--r--sound/soc/au1x/psc-ac97.c4
-rw-r--r--sound/soc/codecs/Kconfig30
-rw-r--r--sound/soc/codecs/es8328.c5
-rw-r--r--sound/soc/codecs/es8389.c236
-rw-r--r--sound/soc/codecs/es8389.h11
-rw-r--r--sound/soc/codecs/hdac_hda.c4
-rw-r--r--sound/soc/codecs/hdac_hdmi.c10
-rw-r--r--sound/soc/codecs/max98090.c1
-rw-r--r--sound/soc/codecs/rt1320-sdw.c816
-rw-r--r--sound/soc/codecs/rt1320-sdw.h12
-rw-r--r--sound/soc/codecs/rt5677.c17
-rw-r--r--sound/soc/codecs/rt700-sdw.c6
-rw-r--r--sound/soc/codecs/sma1303.c2
-rw-r--r--sound/soc/codecs/tlv320aic26.c6
-rw-r--r--sound/soc/fsl/fsl_asrc.c10
-rw-r--r--sound/soc/fsl/fsl_audmix.c35
-rw-r--r--sound/soc/fsl/fsl_easrc.c36
-rw-r--r--sound/soc/fsl/fsl_esai.c16
-rw-r--r--sound/soc/fsl/fsl_spdif.c8
-rw-r--r--sound/soc/fsl/fsl_ssi.c13
-rw-r--r--sound/soc/fsl/fsl_xcvr.c29
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c25
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c69
-rw-r--r--sound/soc/fsl/mpc5200_dma.c56
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c34
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c1
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c67
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c59
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c5
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c9
-rw-r--r--sound/soc/intel/avs/apl.c8
-rw-r--r--sound/soc/intel/avs/control.c7
-rw-r--r--sound/soc/intel/avs/core.c4
-rw-r--r--sound/soc/intel/avs/debug.h10
-rw-r--r--sound/soc/intel/avs/debugfs.c19
-rw-r--r--sound/soc/intel/avs/ipc.c59
-rw-r--r--sound/soc/intel/avs/loader.c15
-rw-r--r--sound/soc/intel/avs/path.c30
-rw-r--r--sound/soc/intel/avs/utils.c45
-rw-r--r--sound/soc/intel/boards/sof_sdw.c2
-rw-r--r--sound/soc/loongson/loongson_card.c171
-rw-r--r--sound/soc/loongson/loongson_i2s_plat.c42
-rw-r--r--sound/soc/mediatek/Kconfig2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/aiu-encoder-i2s.c281
-rw-r--r--sound/soc/meson/aiu-formatter-i2s.c104
-rw-r--r--sound/soc/meson/aiu.c32
-rw-r--r--sound/soc/meson/aiu.h4
-rw-r--r--sound/soc/meson/g12a-toacodec.c2
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c2
-rw-r--r--sound/soc/meson/gx-formatter.c282
-rw-r--r--sound/soc/meson/gx-formatter.h56
-rw-r--r--sound/soc/meson/gx-interface.h48
-rw-r--r--sound/soc/meson/t9015.c6
-rw-r--r--sound/soc/renesas/fsi.c9
-rw-r--r--sound/soc/samsung/aries_wm8994.c1
-rw-r--r--sound/soc/samsung/i2s.c25
-rw-r--r--sound/soc/samsung/spdif.c8
-rw-r--r--sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c4
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c7
-rw-r--r--sound/soc/sof/ipc4-topology.c2
-rw-r--r--sound/soc/sof/topology.c12
-rw-r--r--sound/soc/ti/j721e-evm.c4
75 files changed, 2612 insertions, 933 deletions
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
new file mode 100644
index 000000000000..2a142b32acf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
@@ -0,0 +1,240 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs35l36.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS35L36 Speaker Amplifier
+
+maintainers:
+ - David Rhodes <drhodes@opensource.cirrus.com>
+ - patches@opensource.cirrus.com
+
+description:
+ CS35L36 is a boosted mono Class D amplifier
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - cirrus,cs35l36
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ VA-supply:
+ description: Voltage regulator of analog internal section
+
+ VP-supply:
+ description: Voltage regulator of boost converter
+
+ reset-gpios:
+ maxItems: 1
+
+ cirrus,boost-ctl-millivolt:
+ description: Boost converter output voltage (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2550
+ maximum: 12000
+
+ cirrus,boost-peak-milliamp:
+ description: Boost-converter peak current limit (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 4500
+ minimum: 1600
+ maximum: 4500
+
+ cirrus,boost-ind-nanohenry:
+ description: Initial inductor estimation reference value (1000=1μH, 1200=1.2μH)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1000
+
+ cirrus,multi-amp-mode:
+ description: Hi-Z ASP port when more than one amplifier in system
+ type: boolean
+
+ cirrus,boost-ctl-select:
+ description: Boost converter control source selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # Control Port
+ - 1 # Class
+ - 2 # Sync
+
+ cirrus,amp-pcm-inv:
+ description: Invert incoming PCM data when true
+ type: boolean
+
+ cirrus,imon-pol-inv:
+ description: Invert polarity of outbound IMON feedback when true
+ type: boolean
+
+ cirrus,vmon-pol-inv:
+ description: Invert polarity of outbound VMON feedback when true
+ type: boolean
+
+ cirrus,dcm-mode-enable:
+ description: Enable boost converter automatic Discontinuous Conduction Mode
+ type: boolean
+
+ cirrus,weak-fet-disable:
+ description: Reduce output driver strength in Weak-FET Drive Mode when true
+ type: boolean
+
+ cirrus,classh-wk-fet-delay-ms:
+ description: Weak-FET entry delay
+ default: 100
+ enum: [0, 5, 10, 50, 100, 200, 500, 1000]
+
+ cirrus,classh-weak-fet-thld-millivolt:
+ description: Weak-FET drive threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700]
+
+ cirrus,temp-warn-threshold:
+ description: Overtemperature warning threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 2
+ enum:
+ - 0 # 105°C
+ - 1 # 115°C
+ - 2 # 125°C
+ - 3 # 135°C
+
+ cirrus,irq-drive-select:
+ description: Interrupt output driver type
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # open-drain
+ - 1 # push-pull
+
+ cirrus,irq-gpio-select:
+ description: Programmable IRQ pin selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # PDM_DATA/SWIRE_SD/INT
+ - 1 # GPIO
+
+ cirrus,vpbr-config:
+ $ref: "#/$defs/vpbr-config"
+
+$defs:
+ vpbr-config:
+ description: Brownout prevention configuration sub-node
+ type: object
+ additionalProperties: false
+
+ properties:
+ cirrus,vpbr-en:
+ description: VBST brownout prevention enable
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 0
+ enum:
+ - 0 # disabled
+ - 1 # enabled
+
+ cirrus,vpbr-thld:
+ description: Initial VPBR threshold voltage
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2
+ maximum: 31
+
+ cirrus,vpbr-atk-rate:
+ description: Attenuation attack step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-atk-vol:
+ description: VP brownout prevention step size
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-max-attn:
+ description: Maximum attenuation during VP brownout prevention (dB)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+
+ cirrus,vpbr-wait:
+ description: Delay between brownout clearance and attenuation release (ms)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # 10
+ - 1 # 100
+ - 2 # 250
+ - 3 # 500
+
+ cirrus,vpbr-rel-rate:
+ description: Attenuation release step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-mute-en:
+ description: Mute audio if maximum attenuation reached
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - VA-supply
+ - cirrus,boost-ctl-millivolt
+ - cirrus,boost-peak-milliamp
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec@40 {
+ compatible = "cirrus,cs35l36";
+ reg = <0x40>;
+ VA-supply = <&dummy_vreg>;
+ VP-supply = <&dummy_vreg>;
+ reset-gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ cirrus,boost-ind-nanohenry = <1000>;
+ cirrus,boost-ctl-millivolt = <10000>;
+ cirrus,boost-peak-milliamp = <4500>;
+ cirrus,boost-ctl-select = <0>;
+ cirrus,classh-wk-fet-delay-ms = <100>;
+ cirrus,classh-weak-fet-thld-millivolt = <100>;
+ cirrus,temp-warn-threshold = <1>;
+ cirrus,multi-amp-mode;
+ cirrus,irq-drive-select = <1>;
+ cirrus,irq-gpio-select = <1>;
+
+ cirrus,vpbr-config {
+ cirrus,vpbr-en = <0>;
+ cirrus,vpbr-thld = <5>;
+ cirrus,vpbr-atk-rate = <2>;
+ cirrus,vpbr-atk-vol = <1>;
+ cirrus,vpbr-max-attn = <9>;
+ cirrus,vpbr-wait = <1>;
+ cirrus,vpbr-rel-rate = <5>;
+ cirrus,vpbr-mute-en = <0>;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt
deleted file mode 100644
index d34117b8558e..000000000000
--- a/Documentation/devicetree/bindings/sound/cs35l36.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-CS35L36 Speaker Amplifier
-
-Required properties:
-
- - compatible : "cirrus,cs35l36"
-
- - reg : the I2C address of the device for I2C
-
- - VA-supply, VP-supply : power supplies for the device,
- as covered in
- Documentation/devicetree/bindings/regulator/regulator.txt.
-
- - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost
- converter's output voltage in mV. The range is from 2550mV to 12000mV with
- increments of 50mV.
- (Default) VP
-
- - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA.
- Configures the peak current by monitoring the current through the boost FET.
- Range starts at 1600mA and goes to a maximum of 4500mA with increments of
- 50mA.
- (Default) 4.50 Amps
-
- - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value.
- Seeds the digital boost converter's inductor estimation block with the initial
- inductance value to reference.
-
- 1000 = 1uH (Default)
- 1200 = 1.2uH
-
-Optional properties:
- - cirrus,multi-amp-mode : Boolean to determine if there are more than
- one amplifier in the system. If more than one it is best to Hi-Z the ASP
- port to prevent bus contention on the output signal
-
- - cirrus,boost-ctl-select : Boost converter control source selection.
- Selects the source of the BST_CTL target VBST voltage for the boost
- converter to generate.
- 0x00 - Control Port Value
- 0x01 - Class H Tracking (Default)
- 0x10 - MultiDevice Sync Value
-
- - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming
- PCM data
-
- - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound IMON feedback data
-
- - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound VMON feedback data
-
- - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable.
- This enables the digital boost converter to operate in a low power
- (Discontinuous Conduction) mode during low loading conditions.
-
- - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is
- reduced when operating in a Weak-FET Drive Mode and must not be used to drive
- a large load.
-
- - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay
- (in ms) before the Class H algorithm switches to the weak-FET voltage
- (after the audio falls and remains below the value specified in WKFET_AMP_THLD).
-
- 0 = 0ms
- 1 = 5ms
- 2 = 10ms
- 3 = 50ms
- 4 = 100ms (Default)
- 5 = 200ms
- 6 = 500ms
- 7 = 1000ms
-
- - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold.
- Configures the signal threshold at which the PWM output stage enters
- weak-FET operation. The range is 50mV to 700mV in 50mV increments.
-
- - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold.
- Configures the threshold at which the overtemperature warning condition occurs.
- When the threshold is met, the overtemperature warning attenuation is applied
- and the TEMP_WARN_EINT interrupt status bit is set.
- If TEMP_WARN_MASK = 0, INTb is asserted.
-
- 0 = 105C
- 1 = 115C
- 2 = 125C (Default)
- 3 = 135C
-
- - cirrus,irq-drive-select : Selects the driver type of the selected interrupt
- output.
-
- 0 = Open-drain
- 1 = Push-pull (Default)
-
- - cirrus,irq-gpio-select : Selects the pin to serve as the programmable
- interrupt output.
-
- 0 = PDM_DATA / SWIRE_SD / INT (Default)
- 1 = GPIO
-
-Optional properties for the "cirrus,vpbr-config" Sub-node
-
- - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the
- VBST brownout prevention algorithm is enabled or disabled.
-
- 0 = VBST brownout prevention disabled (default)
- 1 = VBST brownout prevention enabled
-
- See Section 7.31.1 VPBR Config for configuration options & further details
-
- - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout
- threshold voltage
-
- - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the
- amount delay between consecutive volume attenuation steps when a brownout
- condition is present and the VP brownout condition is in an attacking state.
-
- - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP
- brownout prevention attacking attenuation step size when operating in either
- digital volume or analog gain modes.
-
- - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention
- can apply to the audio signal.
-
- - cirrus,vpbr-wait : Configures the delay time between a brownout condition
- no longer being present and the VP brownout prevention entering an attenuation
- release state.
-
- - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay
- between consecutive volume attenuation release steps when a brownout condition
- is not longer present and the VP brownout is in an attenuation release state.
-
- - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value
- is reached, the error condition still remains, and this bit is set, the audio
- is muted.
-
-Example:
-
-cs35l36: cs35l36@40 {
- compatible = "cirrus,cs35l36";
- reg = <0x40>;
- VA-supply = <&dummy_vreg>;
- VP-supply = <&dummy_vreg>;
- reset-gpios = <&gpio0 54 0>;
- interrupt-parent = <&gpio8>;
- interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
-
- cirrus,boost-ind-nanohenry = <1000>;
- cirrus,boost-ctl-millivolt = <10000>;
- cirrus,boost-peak-milliamp = <4500>;
- cirrus,boost-ctl-select = <0x00>;
- cirrus,weak-fet-delay = <0x04>;
- cirrus,weak-fet-thld = <0x01>;
- cirrus,temp-warn-threshold = <0x01>;
- cirrus,multi-amp-mode;
- cirrus,irq-drive-select = <0x01>;
- cirrus,irq-gpio-select = <0x01>;
-
- cirrus,vpbr-config {
- cirrus,vpbr-en = <0x00>;
- cirrus,vpbr-thld = <0x05>;
- cirrus,vpbr-atk-rate = <0x02>;
- cirrus,vpbr-atk-vol = <0x01>;
- cirrus,vpbr-max-attn = <0x09>;
- cirrus,vpbr-wait = <0x01>;
- cirrus,vpbr-rel-rate = <0x05>;
- cirrus,vpbr-mute-en = <0x00>;
- };
-};
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
index 61e8babed402..dc7f4afbb777 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
@@ -8,19 +8,22 @@ title: Loongson 7axxx/2kxxx ASoC audio sound card driver
maintainers:
- Yingkun Meng <mengyingkun@loongson.cn>
+ - Binbin Zhou <zhoubinbin@loongson.cn>
description:
The binding describes the sound card present in loongson
7axxx/2kxxx platform. The sound card is an ASoC component
which uses Loongson I2S controller to transfer the audio data.
+allOf:
+ - $ref: sound-card-common.yaml#
+
properties:
compatible:
- const: loongson,ls-audio-card
-
- model:
- $ref: /schemas/types.yaml#/definitions/string
- description: User specified audio sound card name
+ enum:
+ - loongson,ls-audio-card # Loongson-2K1000/Loongson-2K2000/LS7A
+ - loongson,ls2k0300-forever-pi-audio-card # CTCISZ Forever Pi
+ - loongson,ls2k0300-dl2k0300b-audio-card # ATK-DL2K0300B
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
@@ -45,14 +48,25 @@ properties:
required:
- sound-dai
+ spkr-en-gpios:
+ maxItems: 1
+ description: The GPIO that enables the speakers
+
+ hp-ctl-gpios:
+ maxItems: 1
+ description: The GPIO that control the headphones
+
+ hp-det-gpios:
+ maxItems: 1
+ description: The GPIO that detect headphones are plugged in
+
required:
- compatible
- - model
- mclk-fs
- cpu
- codec
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -68,3 +82,28 @@ examples:
sound-dai = <&es8323>;
};
};
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ sound {
+ compatible = "loongson,ls2k0300-dl2k0300b-audio-card";
+ model = "loongson-audio";
+ mclk-fs = <512>;
+ hp-det-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>;
+ spkr-en-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>;
+ hp-ctl-gpios = <&gpio 87 GPIO_ACTIVE_HIGH>;
+ audio-routing =
+ "Headphone", "LOUT1",
+ "Headphone", "ROUT1",
+ "Speaker", "LOUT2",
+ "Speaker", "ROUT2";
+
+ cpu {
+ sound-dai = <&i2s>;
+ };
+
+ codec {
+ sound-dai = <&es8388>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
index da79510bb2d9..51e23c189f7a 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
@@ -14,9 +14,12 @@ allOf:
properties:
compatible:
- const: loongson,ls2k1000-i2s
+ enum:
+ - loongson,ls2k0300-i2s
+ - loongson,ls2k1000-i2s
reg:
+ minItems: 1
items:
- description: Loongson I2S controller Registers.
- description: APB DMA config register for Loongson I2S controller.
@@ -49,6 +52,23 @@ required:
unevaluatedProperties: false
+if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k1000-i2s
+
+then:
+ properties:
+ reg:
+ minItems: 2
+
+else:
+ properties:
+ reg:
+ maxItems: 1
+
examples:
- |
#include <dt-bindings/clock/loongson,ls2k-clk.h>
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
new file mode 100644
index 000000000000..1b7451655476
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mtk-btcvsd-snd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek ALSA BT SCO CVSD/MSBC
+
+maintainers:
+ - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+properties:
+ compatible:
+ const: mediatek,mtk-btcvsd-snd
+
+ reg:
+ items:
+ - description: PKV region
+ - description: SRAM_BANK2 region
+
+ interrupts:
+ items:
+ - description: BT-SCO interrupt
+
+ mediatek,infracfg:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the infracfg controller
+
+ mediatek,offset:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Array of register offsets and masks
+ items:
+ - description: infra_misc_offset
+ - description: infra_conn_bt_cvsd_mask
+ - description: cvsd_mcu_read_offset
+ - description: cvsd_mcu_write_offset
+ - description: cvsd_packet_indicator_offset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - mediatek,infracfg
+ - mediatek,offset
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mtk-btcvsd-snd@18000000 {
+ compatible = "mediatek,mtk-btcvsd-snd";
+ reg = <0x18000000 0x1000>,
+ <0x18080000 0x8000>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,infracfg = <&infrasys>;
+ mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
deleted file mode 100644
index 679e44839b48..000000000000
--- a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Mediatek ALSA BT SCO CVSD/MSBC Driver
-
-Required properties:
-- compatible = "mediatek,mtk-btcvsd-snd";
-- reg: register location and size of PKV and SRAM_BANK2
-- interrupts: should contain BTSCO interrupt
-- mediatek,infracfg: the phandles of INFRASYS
-- mediatek,offset: Array contains of register offset and mask
- infra_misc_offset,
- infra_conn_bt_cvsd_mask,
- cvsd_mcu_read_offset,
- cvsd_mcu_write_offset,
- cvsd_packet_indicator_offset
-
-Example:
-
- mtk-btcvsd-snd@18000000 {
- compatible = "mediatek,mtk-btcvsd-snd";
- reg=<0 0x18000000 0 0x1000>,
- <0 0x18080000 0 0x8000>;
- interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
- mediatek,infracfg = <&infrasys>;
- mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
- };
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 79c21966220b..9b28e9aef4f1 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -44,6 +44,18 @@
struct asoc_sdw_codec_info;
+struct asoc_sdw_mc_private {
+ struct snd_soc_card card;
+ struct snd_soc_jack sdw_headset;
+ struct device *headset_codec_dev; /* only one headset per card */
+ struct device *amp_dev1, *amp_dev2;
+ bool append_dai_type;
+ bool ignore_internal_dmic;
+ void *private;
+ unsigned long mc_quirk;
+ int codec_info_list_count;
+};
+
struct asoc_sdw_dai_info {
const bool direction[2]; /* playback & capture support */
const char *codec_name;
@@ -88,25 +100,13 @@ struct asoc_sdw_codec_info {
int (*codec_card_late_probe)(struct snd_soc_card *card);
- int (*count_sidecar)(struct snd_soc_card *card,
+ int (*count_sidecar)(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int (*add_sidecar)(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
struct snd_soc_codec_conf **codec_conf);
};
-struct asoc_sdw_mc_private {
- struct snd_soc_card card;
- struct snd_soc_jack sdw_headset;
- struct device *headset_codec_dev; /* only one headset per card */
- struct device *amp_dev1, *amp_dev2;
- bool append_dai_type;
- bool ignore_internal_dmic;
- void *private;
- unsigned long mc_quirk;
- int codec_info_list_count;
-};
-
struct asoc_sdw_endpoint {
struct list_head list;
@@ -182,7 +182,8 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_get_dai_type(u32 type);
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
@@ -235,7 +236,7 @@ int asoc_sdw_es9356_amp_init(struct snd_soc_card *card,
int asoc_sdw_es9356_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* CS AMP support */
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 36809f712723..0b6a6ba6489a 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -90,6 +90,7 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
SOF_DAI_AMD_SDW, /**< AMD ACP SDW */
+ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */
};
/* general purpose DAI configuration */
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index e8b6819cc4b4..9726a9d33ec6 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -432,7 +432,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
if (!soc_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs);
if (ret < 0)
return ret;
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index a423853f3a97..963ce6fd4012 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -303,7 +303,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
if (!sof_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs);
if (ret < 0)
return ret;
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 94698e08a513..0f9d80883116 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -210,9 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
- int chans, t, stype = substream->stream;
-
- chans = params_channels(params);
+ int t, stype = substream->stream;
r = ro = __raw_readl(AC97_CFG(pscdata));
stat = __raw_readl(AC97_STAT(pscdata));
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 252f683be3c1..f90a0d4c77ea 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -615,8 +615,8 @@ config SND_SOC_AK4613
depends on I2C
config SND_SOC_AK4619
- tristate "AKM AK4619 CODEC"
- depends on I2C
+ tristate "AKM AK4619 CODEC"
+ depends on I2C
config SND_SOC_AK4642
tristate "AKM AK4642 CODEC"
@@ -1201,16 +1201,16 @@ config SND_SOC_JZ4725B_CODEC
will be called snd-soc-jz4725b-codec.
config SND_SOC_JZ4760_CODEC
- depends on MACH_INGENIC || COMPILE_TEST
- depends on OF
- select REGMAP
- tristate "Ingenic JZ4760 internal CODEC"
- help
- Enable support for the internal CODEC found in the JZ4760 SoC
- from Ingenic.
+ depends on MACH_INGENIC || COMPILE_TEST
+ depends on OF
+ select REGMAP
+ tristate "Ingenic JZ4760 internal CODEC"
+ help
+ Enable support for the internal CODEC found in the JZ4760 SoC
+ from Ingenic.
- This driver can also be built as a module. If so, the module
- will be called snd-soc-jz4760-codec.
+ This driver can also be built as a module. If so, the module
+ will be called snd-soc-jz4760-codec.
config SND_SOC_JZ4770_CODEC
depends on MACH_INGENIC || COMPILE_TEST
@@ -1888,7 +1888,7 @@ config SND_SOC_RT5670
depends on I2C
config SND_SOC_RT5677
- tristate
+ tristate "Realtek RT5677 Codec"
depends on I2C
select REGMAP_I2C
select REGMAP_IRQ
@@ -2296,8 +2296,8 @@ config SND_SOC_TLV320ADC3XXX
depends on I2C
depends on GPIOLIB
help
- Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
- ADCs.
+ Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
+ ADCs.
config SND_SOC_TLV320AIC23
tristate
@@ -2893,7 +2893,7 @@ config SND_SOC_TPA6130A2
depends on I2C
config SND_SOC_LPASS_MACRO_COMMON
- tristate
+ tristate
config SND_SOC_LPASS_WSA_MACRO
depends on COMMON_CLK
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 9838fe42cb6f..aaa6646ad4c5 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
{ "Mic Bias", NULL, "Mic Bias Gen" },
+ { "LINPUT1", NULL, "Mic Bias" },
+ { "RINPUT1", NULL, "Mic Bias" },
+ { "LINPUT2", NULL, "Mic Bias" },
+ { "RINPUT2", NULL, "Mic Bias" },
+
{ "Left Mixer", NULL, "Left DAC" },
{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
{ "Left Mixer", "Right Playback Switch", "Right DAC" },
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 3484c87853cb..0c7567e2ffc2 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -36,6 +36,10 @@ struct es8389_private {
unsigned int sysclk;
int mastermode;
+ u8 hpfl;
+ u8 hpfr;
+ u32 hpf_freq;
+ u32 capture_rate;
u8 mclk_src;
u8 vddd;
int version;
@@ -50,10 +54,29 @@ static const char * const es8389_core_supplies[] = {
static bool es8389_volatile_register(struct device *dev,
unsigned int reg)
{
- if ((reg <= 0xff))
- return true;
- else
+ switch (reg) {
+ case ES8389_ADCL_VOL:
+ case ES8389_ADCR_VOL:
+ case ES8389_MIC1_GAIN:
+ case ES8389_MIC2_GAIN:
+ case ES8389_DACL_VOL:
+ case ES8389_DACR_VOL:
+ case ES8389_ALC_ON:
+ case ES8389_ALC_CTL:
+ case ES8389_ALC_TARGET:
+ case ES8389_ALC_GAIN:
+ case ES8389_ADC_MUTE:
+ case ES8389_OSR_VOL:
+ case ES8389_DAC_INV:
+ case ES8389_MIX_VOL:
+ case ES8389_DAC_MIX:
+ case ES8389_ADC_RESET:
+ case ES8389_ADC_MODE:
+ case ES8389_DMIC_EN:
return false;
+ default:
+ return true;
+ }
}
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@@ -63,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0);
static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0);
static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0);
+static const u32 hpf_table[10][10] = {
+ {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496},
+ {754, 495, 368, 306, 274, 259, 251, 247, 246, 244},
+ {624, 368, 243, 182, 151, 136, 128, 124, 123, 121},
+ {559, 306, 182, 120, 90, 75, 68, 63, 62, 60},
+ {527, 274, 151, 90, 60, 45, 38, 33, 32, 31},
+ {511, 259, 136, 75, 45, 30, 23, 19, 18, 17},
+ {502, 251, 128, 68, 38, 23, 16, 13, 11, 11},
+ {498, 247, 124, 63, 33, 19, 13, 10, 8, 8},
+ {497, 246, 123, 62, 32, 18, 11, 8, 8, 0},
+ {496, 244, 121, 60, 31, 17, 11, 8, 0, 0}
+};
+
+static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out)
+{
+ int best_row = -1, best_col = -1;
+ u32 min_diff = U32_MAX;
+ u32 f, diff;
+ int i, j;
+
+ if ((target_hz > 1020) | (target_hz < 0))
+ return false;
+
+ for (i = 0; i < 10; i++) {
+ for (j = i; j < 10; j++) {
+ f = hpf_table[i][j];
+
+ diff = (target_hz > f) ? (target_hz - f) : (f - target_hz);
+ if (diff < min_diff) {
+ min_diff = diff;
+ best_row = i;
+ best_col = j;
+ *out = f;
+ }
+ }
+ }
+
+ *hpf1 = best_col + ES8389_HPF_OFFSET;
+ *hpf2 = best_row + ES8389_HPF_OFFSET;
+
+ return true;
+}
+
+static int es8389_hpf_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = es8389->hpf_freq;
+ return 0;
+}
+
+static int es8389_hpf_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ u32 freq;
+ bool hpf;
+
+ if (es8389->hpf_freq == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (es8389->capture_rate) {
+ freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate;
+
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf)
+ return -EBUSY;
+
+ if (es8389->hpf_freq != ucontrol->value.integer.value[0])
+ dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained."
+ "the frequency has been set to the closest value, %u Hz\n",
+ es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq);
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
+ } else {
+ es8389->hpf_freq = ucontrol->value.integer.value[0];
+ dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n");
+ }
+
+ return 1;
+}
+
static int es8389_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -143,6 +252,16 @@ static const struct soc_enum alc_ramprate =
static const struct soc_enum alc_winsize =
SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize);
+static const char *const es8389_adcl_mux_txt[] = {
+ "Normal",
+ "ADC2 channel to ADC1 channel",
+};
+
+static const char *const es8389_adcr_mux_txt[] = {
+ "Normal",
+ "ADC1 channel to ADC2 channel",
+};
+
static const char *const es8389_outl_mux_txt[] = {
"Normal",
"DAC2 channel to DAC1 channel",
@@ -170,6 +289,20 @@ static const unsigned int es8389_pga_values[] = {
1, 5, 6
};
+static const struct soc_enum es8389_adcl_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5,
+ ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcl_mux_controls =
+ SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum);
+
+static const struct soc_enum es8389_adcr_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4,
+ ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcr_mux_controls =
+ SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum);
+
static const struct soc_enum es8389_outl_mux_enum =
SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5,
ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt);
@@ -240,6 +373,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = {
SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0),
SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv),
SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0),
+ SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0,
+ es8389_hpf_get, es8389_hpf_set),
SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv),
SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv),
@@ -298,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = {
&es8389_adc_mixer_controls[0],
ARRAY_SIZE(es8389_adc_mixer_controls)),
SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls),
SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls),
SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls),
@@ -311,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = {
{"ADCL", NULL, "PGAL"},
{"ADCR", NULL, "PGAR"},
+ {"INPUTL MUX", "Normal", "ADCL"},
+ {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"},
+ {"INPUTR MUX", "Normal", "ADCR"},
+ {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"},
+
{"ADC Mixer", "DACL ADCL Mixer", "DACL"},
{"ADC Mixer", "DACR ADCR Mixer", "DACR"},
- {"ADC Mixer", NULL, "ADCL"},
- {"ADC Mixer", NULL, "ADCR"},
+ {"ADC Mixer", NULL, "INPUTL MUX"},
+ {"ADC Mixer", NULL, "INPUTR MUX"},
{"ADC MUX", "AMIC", "ADC Mixer"},
{"ADC MUX", "DMIC", "DMIC"},
@@ -415,52 +557,54 @@ static const struct _coeff_div coeff_div[] = {
{36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2},
{375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0},
- {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
- {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
+ {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2},
- {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
+ {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2},
+ {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0},
};
static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
@@ -564,6 +708,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
int coeff, ret;
u8 dmic_enable, state = 0;
unsigned int regv;
+ u32 freq;
+ bool hpf;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -590,7 +736,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
if (es8389->mclk_src == ES8389_SCLK_PIN) {
regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK,
- ES8389_MCLK_SOURCE, es8389->mclk_src);
+ ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK);
es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params);
}
@@ -641,6 +787,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
dev_warn(component->dev, "Clock coefficients do not match");
}
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ es8389->capture_rate = params_rate(params);
+ freq = (es8389->hpf_freq * 48000) / params_rate(params);
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf) {
+ dev_err(component->dev, "The HPF frequency is invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int es8389_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ es8389->capture_rate = 0;
+
return 0;
}
@@ -721,8 +889,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE,
0x03, 0x00);
} else {
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a);
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE,
0x03, 0x00);
}
@@ -738,6 +906,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
static const struct snd_soc_dai_ops es8389_ops = {
.hw_params = es8389_pcm_hw_params,
+ .hw_free = es8389_pcm_hw_free,
.set_fmt = es8389_set_dai_fmt,
.set_sysclk = es8389_set_dai_sysclk,
.set_tdm_slot = es8389_set_tdm_slot,
@@ -771,7 +940,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_read(es8389->regmap, ES8389_MAX_REGISTER, &reg);
es8389->version = reg;
- regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56);
regmap_write(es8389->regmap, ES8389_RESET, 0x7E);
regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38);
regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64);
@@ -823,7 +992,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04);
regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01);
regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00);
- regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00);
+ regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10);
regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F);
regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F);
regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0);
@@ -861,13 +1030,13 @@ static int es8389_resume(struct snd_soc_component *component)
regcache_cache_only(es8389->regmap, false);
regcache_cache_bypass(es8389->regmap, true);
regmap_read(es8389->regmap, ES8389_RESET, &regv);
- regcache_cache_bypass(es8389->regmap, false);
if (regv == 0xff)
es8389_init(component);
else
es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+ regcache_cache_bypass(es8389->regmap, false);
regcache_sync(es8389->regmap);
return 0;
@@ -913,6 +1082,7 @@ static int es8389_probe(struct snd_soc_component *component)
return ret;
}
+ es8389->hpf_freq = ES8389_HPF_DEFAULT;
es8389_init(component);
es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h
index d21e72f876a6..de39e9bf96e9 100644
--- a/sound/soc/codecs/es8389.h
+++ b/sound/soc/codecs/es8389.h
@@ -106,6 +106,9 @@
#define ES8389_MIC_SEL_MASK (7 << 4)
#define ES8389_MIC_DEFAULT (1 << 4)
+#define ES8389_HPF_DEFAULT 16
+#define ES8389_HPF_OFFSET 4
+
#define ES8389_MASTER_MODE_EN (1 << 0)
#define ES8389_TDM_OFF (0 << 0)
@@ -116,9 +119,11 @@
#define ES8389_TDM_SLOT (0x70 << 0)
#define ES8389_TDM_SHIFT 4
-#define ES8389_MCLK_SOURCE (1 << 6)
-#define ES8389_MCLK_PIN (1 << 6)
-#define ES8389_SCLK_PIN (0 << 6)
+#define ES8389_MCLK_MASK (3 << 6)
+#define ES8389_MCLK_FROM_SCLK (1 << 6)
+#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN
+#define ES8389_MCLK_PIN 0
+#define ES8389_SCLK_PIN 1
/* ES8389_FMT */
#define ES8389_S24_LE (0 << 5)
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 680e341aa7f1..1ab5f8a26e03 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -642,10 +642,8 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
- if (ret < 0) {
+ if (ret < 0)
dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
- return ret;
- }
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 3220f9226e0b..38073a70fa61 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1866,8 +1866,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
- if (hdmi_priv == NULL)
+ if (hdmi_priv == NULL) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENOMEM;
+ }
snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
@@ -1876,8 +1878,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
hdmi_priv->hdev = hdev;
- if (!hdac_id)
+ if (!hdac_id) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENODEV;
+ }
if (hdac_id->driver_data)
hdmi_priv->drv_data =
@@ -1902,6 +1906,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
if (ret < 0) {
dev_err(&hdev->dev,
"Failed in parse and map nid with err: %d\n", ret);
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+ snd_hdac_display_power(hdev->bus, hdev->addr, false);
return ret;
}
snd_hdac_refresh_widgets(hdev);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index da416329b038..bccce322ccc3 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
*
* @component: MAX98090 component
* @jack: jack to report detection events on
+ * @data: can be used if codec driver need extra data for configuring jack
*
* Enable microphone detection via IRQ on the MAX98090. If GPIOs are
* being used to bring out signals to the processor then only platform
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 1e930b27c67a..18d7ebff505f 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -410,6 +410,402 @@ static const struct reg_sequence rt1321_blind_write[] = {
{ 0x41001988, 0x03 },
};
+static const struct reg_sequence rt1321_va1_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x0000d73c, 0xb7 },
+ { 0x0000d73d, 0xd7 },
+ { 0x0000d73e, 0x00 },
+ { 0x0000d73f, 0x10 },
+ { 0x1000cd56, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2df80, 0x00 },
+ { 0x3fc2df81, 0x00 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x0000d541, 0x40 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000c570, 0x08 },
+ { 0x0000d714, 0x17 },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c8, 0x03 },
+ { 0x20009012, 0x00 },
+ { 0x0000dd08, 0x17 },
+ { 0x0000dd09, 0x0e },
+ { 0x0000dd0a, 0x17 },
+ { 0x0000dd0b, 0x0e },
+ { 0x0000c570, 0x08 },
+ { 0x0000d471, 0x3a },
+ { 0x0000db00, 0x00 },
+ { 0x0000db01, 0x00 },
+ { 0x0000db02, 0x73 },
+ { 0x0000db03, 0x00 },
+ { 0x0000db04, 0x00 },
+ { 0x0000db05, 0x00 },
+ { 0x0000db06, 0x00 },
+ { 0x0000db07, 0x00 },
+ { 0x0000db08, 0x7f },
+ { 0x0000db09, 0x00 },
+ { 0x0000db1a, 0x00 },
+ { 0x0000db1b, 0x00 },
+ { 0x0000db19, 0x00 },
+};
+
+static const struct reg_sequence rt1321_va2_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x10008000, 0x67 },
+ { 0x10008001, 0x80 },
+ { 0x10008002, 0x00 },
+ { 0x10008003, 0x00 },
+ { 0x1000cd56, 0x00 },
+ { 0x0000d486, 0x43 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfa3, 0x00 },
+ { 0x3fc2dfa2, 0x00 },
+ { 0x3fc2dfa1, 0x00 },
+ { 0x3fc2dfa0, 0x00 },
+ { 0x3fc2df80, 0x10 },
+ { 0x3fc2df81, 0x20 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x3fc2df84, 0x50 },
+ { 0x3fc2df85, 0x19 },
+ { 0x3fc2df86, 0x00 },
+ { 0x3fc2df87, 0x00 },
+ { 0x3fc2df88, 0x52 },
+ { 0x3fc2df89, 0x23 },
+ { 0x3fc2df8a, 0x00 },
+ { 0x3fc2df8b, 0x00 },
+ { 0x3fc2df8c, 0xe0 },
+ { 0x3fc2df8d, 0x2e },
+ { 0x3fc2df8e, 0x00 },
+ { 0x3fc2df8f, 0x00 },
+ { 0x3fc2df90, 0xe0 },
+ { 0x3fc2df91, 0x2e },
+ { 0x3fc2df92, 0x00 },
+ { 0x3fc2df93, 0x00 },
+ { 0x3fc2df94, 0x01 },
+ { 0x3fc2df95, 0x08 },
+ { 0x3fc2df96, 0x00 },
+ { 0x3fc2df97, 0x00 },
+ { 0x3fc2df40, 0x80 },
+ { 0x3fc2df41, 0xbb },
+ { 0x3fc2df42, 0x00 },
+ { 0x3fc2df43, 0x00 },
+ { 0x3fc2df44, 0xc0 },
+ { 0x3fc2df45, 0x99 },
+ { 0x3fc2df46, 0x01 },
+ { 0x3fc2df47, 0x00 },
+ { 0x3fc2df48, 0x00 },
+ { 0x3fc2df49, 0x00 },
+ { 0x3fc2df4a, 0x00 },
+ { 0x3fc2df4b, 0x00 },
+ { 0x3fc2df4c, 0x00 },
+ { 0x3fc2df4d, 0x00 },
+ { 0x3fc2df4e, 0x00 },
+ { 0x3fc2df4f, 0x00 },
+ { 0x3fc2df50, 0x01 },
+ { 0x3fc2df51, 0x00 },
+ { 0x3fc2df52, 0x00 },
+ { 0x3fc2df53, 0x00 },
+ { 0x3fc2df54, 0x01 },
+ { 0x3fc2df55, 0x00 },
+ { 0x3fc2df56, 0x00 },
+ { 0x3fc2df57, 0x00 },
+ { 0x3fc2df58, 0x00 },
+ { 0x3fc2df59, 0x00 },
+ { 0x3fc2df5a, 0x00 },
+ { 0x3fc2df5b, 0x00 },
+ { 0x3fc2df5c, 0x01 },
+ { 0x3fc2df5d, 0x00 },
+ { 0x3fc2df5e, 0x00 },
+ { 0x3fc2df5f, 0x00 },
+ { 0x3fc2df60, 0x00 },
+ { 0x3fc2df61, 0x00 },
+ { 0x3fc2df62, 0x00 },
+ { 0x3fc2df63, 0x00 },
+ { 0x3fc2df64, 0x00 },
+ { 0x3fc2df65, 0x00 },
+ { 0x3fc2df66, 0x00 },
+ { 0x3fc2df67, 0x10 },
+ { 0x3fc2df68, 0x01 },
+ { 0x3fc2df69, 0x00 },
+ { 0x3fc2df6a, 0x00 },
+ { 0x3fc2df6b, 0x00 },
+ { 0x3fc2df6c, 0x01 },
+ { 0x3fc2df6d, 0x00 },
+ { 0x3fc2df6e, 0x00 },
+ { 0x3fc2df6f, 0x00 },
+ { 0x3fc2df70, 0x04 },
+ { 0x3fc2df71, 0x00 },
+ { 0x3fc2df72, 0x00 },
+ { 0x3fc2df73, 0x00 },
+ { 0x3fc2df74, 0x01 },
+ { 0x3fc2df75, 0x00 },
+ { 0x3fc2df76, 0x00 },
+ { 0x3fc2df77, 0x00 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000d714, 0x17 },
+ { 0x0000dd0b, 0x0d },
+ { 0x0000dd0a, 0xff },
+ { 0x0000dd09, 0x0d },
+ { 0x0000dd08, 0xff },
+ { 0x0000c5fb, 0x12 },
+ { 0x0000c570, 0x08 },
+};
+
static const struct reg_default rt1320_reg_defaults[] = {
{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
@@ -497,10 +893,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x20003000 ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x20005800 ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x20009000 ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc000c0 ... 0x3fc2dfc8:
case 0x3fe00000 ... 0x3fe36fff:
/* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
@@ -596,15 +997,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
case 0x1000c000 ... 0x1000dfff:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x2000300e ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x2000580e ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x2000900e ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc2ab80 ... 0x3fc2ac4c:
case 0x3fc2b780:
case 0x3fc2bf80 ... 0x3fc2bf83:
case 0x3fc2bfc0 ... 0x3fc2bfc8:
- case 0x3fc2d300 ... 0x3fc2d354:
+ case 0x3fc2d300 ... 0x3fc2d3cc:
case 0x3fc2dfc0 ... 0x3fc2dfc8:
case 0x3fe2e000 ... 0x3fe2e003:
case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
@@ -892,6 +1298,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320)
return 0;
}
+static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ unsigned int fw_status_addr, fw_ready;
+ unsigned int dspfw_run;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
+ break;
+ case RT1321_DEV_ID:
+ fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
+ fw_ready &= 0x1;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_read(rt1320->regmap, 0xf01e, &dspfw_run);
+ dspfw_run &= 0x1;
+ fw_ready = (!dspfw_run && fw_ready);
+ }
+
+ if (fw_ready) {
+ dev_dbg(dev, "%s, DSP FW was already\n", __func__);
+ return 1;
+ }
+
+ dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
+ return 0;
+}
+
static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps)
{
struct device *dev = &rt1320->sdw_slave->dev;
@@ -982,6 +1424,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_
if (!tempbuf)
return -ENOMEM;
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2)
+ paramid += 0x0bff0000;
+
paramhr.moudleid = 1;
paramhr.commandtype = cmdid;
/* 8 is "sizeof(paramid) + sizeof(paramlength)" */
@@ -1120,45 +1565,73 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320)
l_calir0, l_calir0_lo, r_calir0, r_calir0_lo);
}
+static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ int l_targetpostgain, r_targetpostgain;
+ unsigned long long factor = (1 << 12);
+ int l_pilotgain[9], r_pilotgain[9];
+ const int postgain_step = 234;
+ int targetGain;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ targetGain = -320000;
+ break;
+ case RT1321_DEV_ID:
+ targetGain = -420000;
+ if (rt1320->version_id == RT1321_VA0)
+ targetGain = -320000;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain));
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain));
+ dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]);
+
+ /* calculate pilot tone gain */
+ l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor;
+ r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor;
+
+ /* calculate post gain to meet target gain */
+ l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step;
+ r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step;
+ l_targetpostgain = 0xfff - l_targetpostgain;
+ r_targetpostgain = 0xfff - r_targetpostgain;
+ dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain);
+
+ regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff);
+ regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff);
+
+ return 0;
+}
+
static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = &rt1320->sdw_slave->dev;
struct rt1320_datafixpoint audfixpoint[2];
unsigned int reg_c5fb, reg_c570, reg_cd00;
- unsigned int vol_reg[4], fw_ready;
+ unsigned int vol_reg[4];
unsigned long long l_meanr0, r_meanr0;
- unsigned int fw_status_addr;
int l_re[5], r_re[5];
int ret, tmp;
unsigned long long factor = (1 << 27);
unsigned short l_advancegain, r_advancegain;
unsigned int delay_s = 7; /* delay seconds for the calibration */
+ int dspfw_status;
if (!rt1320->component)
return;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
- /* set volume 0dB */
regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]);
regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]);
regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]);
regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]);
- regmap_write(rt1320->regmap, 0xdd0b, 0x0f);
- regmap_write(rt1320->regmap, 0xdd0a, 0xff);
- regmap_write(rt1320->regmap, 0xdd09, 0x0f);
- regmap_write(rt1320->regmap, 0xdd08, 0xff);
-
regmap_read(rt1320->regmap, 0xc5fb, &reg_c5fb);
regmap_read(rt1320->regmap, 0xc570, &reg_c570);
regmap_read(rt1320->regmap, 0xcd00, &reg_cd00);
@@ -1171,9 +1644,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
goto _finish_;
}
@@ -1184,8 +1656,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- if (rt1320->dev_id == RT1320_DEV_ID)
- regmap_write(rt1320->regmap, 0xc5fb, 0x00);
+ /* fine tune pilot tone output */
+ ret = rt1320_pilot_tone_output(rt1320);
+ if (ret < 0) {
+ dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__);
+ goto _finish_;
+ }
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x12);
+ }
+
+ regmap_write(rt1320->regmap, 0xc5fb, 0x00);
regmap_write(rt1320->regmap, 0xc570, 0x0b);
regmap_write(rt1320->regmap, 0xcd00, 0xc5);
@@ -1246,6 +1729,11 @@ _finish_:
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03);
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ }
+
/* advance gain will be set when R0 load, not here */
regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]);
regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]);
@@ -1312,6 +1800,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
max_addr = 0x10007fff;
break;
case RT1321_DEV_ID:
+ if (rt1320->version_id == RT1321_VA2)
+ return;
+
filename = RT1321_VA_MCU_PATCH;
min_addr = 0x10008000;
max_addr = 0x10008fff;
@@ -1382,30 +1873,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320)
static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0)
{
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int factor = (1 << 22), fw_ready;
+ unsigned int factor = (1 << 22);
int l_t0_data[38], r_t0_data[38];
- unsigned int fw_status_addr;
-
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
+ int dspfw_status;
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _exit_;
}
@@ -1483,22 +1961,48 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
request_firmware(&rae_fw, rae_filename, dev);
if (rae_fw) {
- /* RAE CRC clear */
- regmap_write(rt1320->regmap, 0xe80b, 0x0f);
-
- /* RAE stop & CRC disable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
-
- while (--retry) {
- regmap_read(rt1320->regmap, 0xe83f, &value);
- if (value & 0x40)
- break;
- usleep_range(1000, 1100);
- }
- if (!retry && !(value & 0x40)) {
- dev_err(dev, "%s: RAE is not ready to load\n", __func__);
- release_firmware(rae_fw);
- return -ETIMEDOUT;
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0xe80b, 0x0f);
+ /* RAE stop & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0xe83f, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ release_firmware(rae_fw);
+ return -ETIMEDOUT;
+ }
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0x2000300e, 0xc0);
+ regmap_write(rt1320->regmap, 0x2000300f, 0x0f);
+ /* RAE stop & Phase sync & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00);
+ /* check whether write state is ready */
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0x20003043, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ release_firmware(rae_fw);
+ return -ETIMEDOUT;
+ }
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
}
dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size);
@@ -1559,18 +2063,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
goto _exit_;
}
- /* RAE CRC enable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
-
- /* RAE update */
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
-
- /* RAE run */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
-
- regmap_read(rt1320->regmap, 0xe80b, &value);
- dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
+ regmap_read(rt1320->regmap, 0xe80b, &value);
+ dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01);
+ /* Phase sync eanble */
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ break;
+ }
rt1320->rae_update_done = true;
@@ -1598,8 +2118,7 @@ struct rt1320_dspfwheader {
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component);
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int val, i, fw_offset, fw_ready;
- unsigned int fw_status_addr;
+ unsigned int val, i, fw_offset;
struct rt1320_dspfwheader *fwheader;
struct rt1320_imageinfo *ptr_img;
struct sdw_bpt_section sec[10];
@@ -1610,20 +2129,10 @@ struct rt1320_dspfwheader {
unsigned int hdr_size = 0;
const char *dmi_vendor, *dmi_product, *dmi_sku;
int len_vendor, len_product, len_sku;
+ unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */
+ unsigned char has_0x3fc00000 = 0;
char filename[512];
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME);
dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
@@ -1653,17 +2162,12 @@ struct rt1320_dspfwheader {
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (fw_ready) {
+ if (rt1320_dspfw_status(rt1320)) {
dev_dbg(dev, "%s, DSP FW was already\n", __func__);
rt1320->fw_load_done = true;
goto _exit_;
}
- /* change to IRAM */
- regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
-
request_firmware(&fw, filename, dev);
if (fw) {
fwheader = (struct rt1320_dspfwheader *)fw->data;
@@ -1709,9 +2213,11 @@ struct rt1320_dspfwheader {
dev_fw_match = true;
break;
case RT1321_DEV_ID:
- if (ptr_img->addr == 0x3fc00000)
- if (fw_data[9] == '1')
+ if (ptr_img->addr == 0x3fc00000) {
+ if (fw_data[7] == '1')
dev_fw_match = true;
+ has_0x3fc00000 = 1;
+ }
break;
default:
dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
@@ -1721,6 +2227,22 @@ struct rt1320_dspfwheader {
fw_offset += ptr_img->size;
}
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) {
+ /*
+ * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000,
+ * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA.
+ */
+ if (!has_0x3fc00000) {
+ boot_mode = 1;
+ dev_fw_match = true;
+ }
+ dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM"));
+ }
+
+ /* change to IRAM */
+ if (!boot_mode)
+ regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
+
if (dev_fw_match) {
dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__);
rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num;
@@ -1743,24 +2265,39 @@ struct rt1320_dspfwheader {
goto _exit_;
}
- /* run RAM code */
- regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
- val |= 0x8;
- regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
-
- /* clear frame counter */
switch (rt1320->dev_id) {
case RT1320_DEV_ID:
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00);
break;
case RT1321_DEV_ID:
+ if (!boot_mode) {
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2dfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2dfc0, val);
+ }
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00);
+ /* enable handshake */
+ regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00);
+ regmap_write(rt1320->regmap, 0xd470, 0xad);
+ /* minimum phase settings */
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ regmap_write(rt1320->regmap, 0x20003003, 0x31);
+ regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00);
+ regmap_write(rt1320->regmap, 0xc5b3, 0x01);
+ regmap_write(rt1320->regmap, 0xc052, 0x11);
break;
}
@@ -1843,14 +2380,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
static void rt1321_preset(struct rt1320_sdw_priv *rt1320)
{
+ const struct reg_sequence *blindwrite;
unsigned int i, reg, val, delay;
+ unsigned int array_size;
- for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) {
- reg = rt1321_blind_write[i].reg;
- val = rt1321_blind_write[i].def;
- delay = rt1321_blind_write[i].delay_us;
+ switch (rt1320->version_id) {
+ case RT1321_VA0:
+ blindwrite = rt1321_blind_write;
+ array_size = ARRAY_SIZE(rt1321_blind_write);
+ break;
+ case RT1321_VA1:
+ blindwrite = rt1321_va1_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va1_blind_write);
+ break;
+ case RT1321_VA2:
+ blindwrite = rt1321_va2_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va2_blind_write);
+ break;
+ default:
+ dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n",
+ __func__, rt1320->version_id);
+ return;
+ }
- if (reg == 0x3fc2dfc3)
+ for (i = 0; i < array_size; i++) {
+ reg = blindwrite[i].reg;
+ val = blindwrite[i].def;
+ delay = blindwrite[i].delay_us;
+
+ if (reg == 0x1000cd56)
rt1320_load_mcu_patch(rt1320);
regmap_write(rt1320->regmap, reg, val);
@@ -1892,6 +2450,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val);
regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp);
rt1320->dev_id = (val << 8) | tmp;
+
+ /* This is a workaround that reads the value twice to obtain the correct result. */
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ val = (val << 8) | tmp;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ if (rt1320->version_id == 0x01)
+ rt1320->version_id = RT1321_VA2;
+ else if (val == RT1321_DEV_HV_VA0_ID)
+ rt1320->version_id = RT1321_VA0;
+ else if (val == RT1321_DEV_HV_VA1_ID)
+ rt1320->version_id = RT1321_VA1;
+ else
+ dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id);
+ }
}
regmap_read(rt1320->regmap,
@@ -2326,25 +2902,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = regmap_get_device(rt1320->regmap);
- unsigned int fw_status_addr;
- unsigned int fw_ready;
+ int dspfw_status;
int ret = 0;
if (!rt1320->r0_l_reg || !rt1320->r0_r_reg)
return -EINVAL;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return -EINVAL;
- }
-
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
@@ -2353,9 +2916,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
goto _timeout_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _timeout_;
}
@@ -2458,7 +3020,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!rt1320->hw_init)
return 0;
- ret = pm_runtime_resume(component->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -2469,6 +3031,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!ucontrol->value.integer.value[0])
rt1320->fw_load_done = false;
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index a7b573883dd0..bc0f78e03529 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -17,12 +17,17 @@
#define RT1320_DEV_ID 0x6981
#define RT1321_DEV_ID 0x7045
+#define RT1321_DEV_HV_VA0_ID 0x6997
+#define RT1321_DEV_HV_VA1_ID 0x7071
/* imp-defined registers */
#define RT1320_DEV_VERSION_ID_1 0xc404
#define RT1320_DEV_ID_1 0xc405
#define RT1320_DEV_ID_0 0xc406
+#define RT1320_HV_DEV_ID_0 0xf622
+#define RT1320_HV_DEV_ID_1 0xf623
+
#define RT1320_POWER_STATE 0xc560
#define RT1321_PATCH_MAIN_VER 0x1000cffe
@@ -94,6 +99,12 @@ enum rt1320_version_id {
RT1320_VC,
};
+enum rt1321_version_id {
+ RT1321_VA0,
+ RT1321_VA1,
+ RT1321_VA2,
+};
+
#define RT1320_VER_B_ID 0x07392238
#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin"
#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin"
@@ -121,6 +132,7 @@ struct rt1320_datafixpoint {
int invrs;
};
+/* FW parameter id 1300 */
typedef struct FwPara_HwSwGain {
unsigned int SwAdvGain;
unsigned int SwBasGain;
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index ac084ca008f3..73fc008d558a 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -6,6 +6,7 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/fs.h>
@@ -4767,6 +4768,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
return rt5677_update_gpio_bits(rt5677, offset, m, v);
}
+static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3;
+ unsigned int bank = offset / 5;
+ unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2;
+ int ret;
+
+ ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift));
+ if (ret < 0)
+ return ret;
+
+ return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
/*
* Configures the GPIO as
* 0 - floating
@@ -4834,6 +4850,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
static const struct gpio_chip rt5677_template_chip = {
.label = RT5677_DRV_NAME,
.owner = THIS_MODULE,
+ .get_direction = rt5677_gpio_get_direction,
.direction_output = rt5677_gpio_direction_out,
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index a451d5d1f8ab..bb449f08e30c 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -458,10 +458,8 @@ static void rt700_sdw_remove(struct sdw_slave *slave)
{
struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
- if (rt700->hw_init) {
- cancel_delayed_work_sync(&rt700->jack_detect_work);
- cancel_delayed_work_sync(&rt700->jack_btn_check_work);
- }
+ cancel_delayed_work_sync(&rt700->jack_detect_work);
+ cancel_delayed_work_sync(&rt700->jack_btn_check_work);
pm_runtime_disable(&slave->dev);
}
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index 7fce60de5e5f..15758eb13f8c 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -1777,6 +1777,8 @@ static void sma1303_i2c_remove(struct i2c_client *client)
struct sma1303_priv *sma1303 =
(struct sma1303_priv *) i2c_get_clientdata(client);
+ if (sma1303->attr_grp)
+ sysfs_remove_group(sma1303->kobj, sma1303->attr_grp);
cancel_delayed_work_sync(&sma1303->check_fault_work);
}
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index e5dfb3d752a3..84e954311c1b 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component)
return 0;
}
+static void aic26_remove(struct snd_soc_component *component)
+{
+ device_remove_file(component->dev, &dev_attr_keyclick);
+}
+
static const struct snd_soc_component_driver aic26_soc_component_dev = {
.probe = aic26_probe,
+ .remove = aic26_remove,
.controls = aic26_snd_controls,
.num_controls = ARRAY_SIZE(aic26_snd_controls),
.dapm_widgets = tlv320aic26_dapm_widgets,
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 5fda9b647c70..0b28bcfa47fe 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -222,10 +222,9 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *asrc = pair->asrc;
struct device *dev = &asrc->pdev->dev;
- unsigned long lock_flags;
int i, ret = 0;
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
if (asrc->pair[i] != NULL)
@@ -250,8 +249,6 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
pair->index = index;
}
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
-
return ret;
}
@@ -265,19 +262,16 @@ static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
{
struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
- unsigned long lock_flags;
/* Make sure the pair is disabled */
regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), 0);
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
asrc->channel_avail += pair->channels;
asrc->pair[index] = NULL;
pair->error = 0;
-
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
}
/**
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index f819f33ec46b..d4140e170edf 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -286,7 +286,6 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai);
- unsigned long lock_flags;
/* Capture stream shall not be handled */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -296,16 +295,14 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms |= BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms |= BIT(dai->driver->id);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms &= ~BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms &= ~BIT(dai->driver->id);
break;
default:
return -EINVAL;
@@ -457,6 +454,9 @@ static const struct of_device_id fsl_audmix_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_audmix_ids);
+static int fsl_audmix_runtime_resume(struct device *dev);
+static int fsl_audmix_runtime_suspend(struct device *dev);
+
static int fsl_audmix_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -488,13 +488,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = fsl_audmix_runtime_resume(dev);
+ if (ret)
+ goto err_disable_pm;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* To enable regmap cache only when runtime PM enabled */
+ pm_runtime_put(dev);
ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
fsl_audmix_dai,
ARRAY_SIZE(fsl_audmix_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
/*
@@ -506,12 +518,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
}
return 0;
+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(dev))
+ fsl_audmix_runtime_suspend(dev);
err_disable_pm:
pm_runtime_disable(dev);
return ret;
@@ -522,6 +537,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)
struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_audmix_runtime_suspend(&pdev->dev);
if (priv->pdev)
platform_device_unregister(priv->pdev);
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 114a6c0b6b73..edfd943197a0 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1025,7 +1025,6 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
struct device *dev;
- unsigned long lock_flags;
int ret;
if (!easrc)
@@ -1053,9 +1052,8 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
if (ret)
return ret;
- spin_lock_irqsave(&easrc->lock, lock_flags);
- ret = fsl_easrc_config_slot(easrc, ctx->index);
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ ret = fsl_easrc_config_slot(easrc, ctx->index);
if (ret)
return ret;
@@ -1301,13 +1299,12 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *easrc = ctx->asrc;
struct device *dev;
- unsigned long lock_flags;
int ret = 0;
int i;
dev = &easrc->pdev->dev;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
if (easrc->pair[i])
@@ -1331,8 +1328,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
easrc->channel_avail -= channels;
}
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
-
return ret;
}
@@ -1343,7 +1338,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
*/
static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
{
- unsigned long lock_flags;
struct fsl_asrc *easrc;
if (!ctx)
@@ -1351,14 +1345,12 @@ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
easrc = ctx->asrc;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
fsl_easrc_release_slot(easrc, ctx->index);
easrc->channel_avail += ctx->channels;
easrc->pair[ctx->index] = NULL;
-
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
}
/*
@@ -2292,15 +2284,13 @@ static int fsl_easrc_runtime_suspend(struct device *dev)
{
struct fsl_asrc *easrc = dev_get_drvdata(dev);
struct fsl_easrc_priv *easrc_priv = easrc->private;
- unsigned long lock_flags;
regcache_cache_only(easrc->regmap, true);
clk_disable_unprepare(easrc->mem_clk);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- easrc_priv->firmware_loaded = 0;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ easrc_priv->firmware_loaded = 0;
return 0;
}
@@ -2311,7 +2301,6 @@ static int fsl_easrc_runtime_resume(struct device *dev)
struct fsl_easrc_priv *easrc_priv = easrc->private;
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
- unsigned long lock_flags;
int ret;
int i;
@@ -2323,13 +2312,11 @@ static int fsl_easrc_runtime_resume(struct device *dev)
regcache_mark_dirty(easrc->regmap);
regcache_sync(easrc->regmap);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- if (easrc_priv->firmware_loaded) {
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
- goto skip_load;
+ scoped_guard(spinlock_irqsave, &easrc->lock) {
+ if (easrc_priv->firmware_loaded)
+ return 0;
+ easrc_priv->firmware_loaded = 1;
}
- easrc_priv->firmware_loaded = 1;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
ret = fsl_easrc_get_firmware(easrc);
if (ret) {
@@ -2377,9 +2364,6 @@ static int fsl_easrc_runtime_resume(struct device *dev)
goto disable_mem_clk;
}
-skip_load:
- return 0;
-
disable_mem_clk:
clk_disable_unprepare(easrc->mem_clk);
return ret;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index cde0b0c6c1ef..4a530a6c33f0 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -709,10 +709,9 @@ static void fsl_esai_hw_reset(struct work_struct *work)
{
struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);
bool tx = true, rx = false, enabled[2];
- unsigned long lock_flags;
u32 tfcr, rfcr;
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
+ guard(spinlock_irqsave)(&esai_priv->lock);
/* Save the registers */
regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);
regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);
@@ -750,8 +749,6 @@ static void fsl_esai_hw_reset(struct work_struct *work)
fsl_esai_trigger_start(esai_priv, tx);
if (enabled[rx])
fsl_esai_trigger_start(esai_priv, rx);
-
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
}
static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -759,7 +756,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
esai_priv->channels[tx] = substream->runtime->channels;
@@ -767,16 +763,14 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_start(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_start(esai_priv, tx);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_stop(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_stop(esai_priv, tx);
break;
default:
return -EINVAL;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 1b9be85b34c2..ad1206ed9882 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -853,17 +853,15 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
memcpy(&ucontrol->value.iec958.subcode[0],
&ctrl->subcode[idx], SPDIF_UBITS_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
@@ -885,17 +883,15 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
memcpy(&ucontrol->value.bytes.data[0],
&ctrl->qsub[idx], SPDIF_QSUB_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index b2e1da1781ae..dc022976c982 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1218,13 +1218,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (reg > 0x7f)
return;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 write clk_prepare_enable failed: %d\n",
ret);
- goto ret_unlock;
+ return;
}
lreg = reg << 12;
@@ -1238,9 +1238,6 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
-
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
@@ -1252,12 +1249,12 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned int lreg;
int ret;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 read clk_prepare_enable failed: %d\n", ret);
- goto ret_unlock;
+ return val;
}
lreg = (reg & 0x7f) << 12;
@@ -1272,8 +1269,6 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
clk_disable_unprepare(fsl_ac97_data->clk);
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
return val;
}
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 6677d3bf36ec..41d100500534 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -797,10 +797,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
int ret = 0;
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -812,7 +811,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -824,7 +823,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_ISR_CMDC_TX_EN);
if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret);
- goto release_lock;
+ return ret;
}
fallthrough;
case FSL_XCVR_MODE_SPDIF:
@@ -833,7 +832,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -844,14 +843,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
if (ret < 0) {
dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
/* clear DPATH RESET */
@@ -860,7 +859,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
@@ -873,14 +872,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -891,7 +890,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (xcvr->soc_data->spdif_only)
break;
@@ -905,7 +904,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0) {
dev_err(dai->dev,
"Err updating ISR %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -916,8 +915,6 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
break;
}
-release_lock:
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
return ret;
}
@@ -1448,11 +1445,10 @@ static void reset_rx_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst);
struct device *dev = &xcvr->pdev->dev;
- unsigned long lock_flags;
u32 ext_ctrl;
dev_dbg(dev, "reset rx path\n");
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl);
if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) {
@@ -1469,7 +1465,6 @@ static void reset_rx_work(struct work_struct *work)
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
0);
}
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
}
static irqreturn_t irq0_isr(int irq, void *devid)
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 38aafb8954c7..b55dfbdb4502 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -22,7 +22,6 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
struct rpmsg_info *info;
struct rpmsg_msg *msg;
- unsigned long flags;
if (!rpmsg->rpmsg_pdev)
return 0;
@@ -37,21 +36,21 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
/* TYPE C is notification from M core */
switch (r_msg->header.cmd) {
case TX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[TX], flags);
- msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[TX];
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[TX];
+ }
info->callback[TX](info->callback_param[TX]);
break;
case RX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[RX], flags);
- msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[1];
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[1];
+ }
info->callback[RX](info->callback_param[RX]);
break;
default:
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 2a4813c6cda9..ee741f3d79bd 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -39,10 +39,9 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
struct rpmsg_device *rpdev = info->rpdev;
int ret = 0;
- mutex_lock(&info->msg_lock);
+ guard(mutex)(&info->msg_lock);
if (!rpdev) {
dev_err(info->dev, "rpmsg channel not ready\n");
- mutex_unlock(&info->msg_lock);
return -EINVAL;
}
@@ -55,15 +54,12 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
sizeof(struct rpmsg_s_msg));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
- mutex_unlock(&info->msg_lock);
return ret;
}
/* No receive msg for TYPE_C command */
- if (msg->s_msg.header.type == MSG_TYPE_C) {
- mutex_unlock(&info->msg_lock);
+ if (msg->s_msg.header.type == MSG_TYPE_C)
return 0;
- }
/* wait response from rpmsg */
ret = wait_for_completion_timeout(&info->cmd_complete,
@@ -71,7 +67,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
if (!ret) {
dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
msg->s_msg.header.cmd);
- mutex_unlock(&info->msg_lock);
return -ETIMEDOUT;
}
@@ -100,8 +95,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
info->r_msg.param.resp);
- mutex_unlock(&info->msg_lock);
-
return 0;
}
@@ -109,14 +102,13 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
struct rpmsg_msg *msg,
struct rpmsg_info *info)
{
- unsigned long flags;
int ret = 0;
/*
* Queue the work to workqueue.
* If the queue is full, drop the message.
*/
- spin_lock_irqsave(&info->wq_lock, flags);
+ guard(spinlock_irqsave)(&info->wq_lock);
if (info->work_write_index != info->work_read_index) {
int index = info->work_write_index;
@@ -130,7 +122,6 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
info->msg_drop_count[substream->stream]++;
ret = -EPIPE;
}
- spin_unlock_irqrestore(&info->wq_lock, flags);
return ret;
}
@@ -523,7 +514,6 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
snd_pcm_sframes_t avail;
struct timer_list *timer;
struct rpmsg_msg *msg;
- unsigned long flags;
int buffer_tail = 0;
int written_num;
@@ -553,11 +543,11 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
msg->s_msg.param.buffer_tail = buffer_tail;
/* The notification message is updated to latest */
- spin_lock_irqsave(&info->lock[substream->stream], flags);
- memcpy(&info->notify[substream->stream], msg,
- sizeof(struct rpmsg_s_msg));
- info->notify_updated[substream->stream] = true;
- spin_unlock_irqrestore(&info->lock[substream->stream], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[substream->stream]) {
+ memcpy(&info->notify[substream->stream], msg,
+ sizeof(struct rpmsg_s_msg));
+ info->notify_updated[substream->stream] = true;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
avail = snd_pcm_playback_hw_avail(runtime);
@@ -641,7 +631,7 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
bool is_notification = false;
struct rpmsg_info *info;
struct rpmsg_msg msg;
- unsigned long flags;
+ bool updated;
work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
info = work_of_rpmsg->info;
@@ -652,25 +642,26 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
* enough data in M core side, need to let M core know
* data is updated immediately.
*/
- spin_lock_irqsave(&info->lock[TX], flags);
- if (info->notify_updated[TX]) {
- memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[TX] = false;
- spin_unlock_irqrestore(&info->lock[TX], flags);
- info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ updated = info->notify_updated[TX];
+ if (updated) {
+ memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[TX] = false;
+ }
}
-
- spin_lock_irqsave(&info->lock[RX], flags);
- if (info->notify_updated[RX]) {
- memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[RX] = false;
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ if (updated)
info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[RX], flags);
+
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ updated = info->notify_updated[RX];
+ if (updated) {
+ memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[RX] = false;
+ }
}
+ if (updated)
+ info->send_message(&msg, info);
+
/* Skip the notification message for it has been processed above */
if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
@@ -682,10 +673,10 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
info->send_message(&work_of_rpmsg->msg, info);
/* update read index */
- spin_lock_irqsave(&info->wq_lock, flags);
- info->work_read_index++;
- info->work_read_index %= WORK_MAX_NUM;
- spin_unlock_irqrestore(&info->wq_lock, flags);
+ scoped_guard(spinlock_irqsave, &info->wq_lock) {
+ info->work_read_index++;
+ info->work_read_index %= WORK_MAX_NUM;
+ }
}
static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 56e2cf2f727b..bfedb2dea0b3 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -77,18 +77,20 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
{
struct psc_dma_stream *s = _psc_dma_stream;
- spin_lock(&s->psc_dma->lock);
- /* For each finished period, dequeue the completed period buffer
- * and enqueue a new one in it's place. */
- while (bcom_buffer_done(s->bcom_task)) {
- bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+ scoped_guard(spinlock, &s->psc_dma->lock) {
+ /*
+ * For each finished period, dequeue the completed period buffer
+ * and enqueue a new one in its place
+ */
+ while (bcom_buffer_done(s->bcom_task)) {
+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
- s->period_current = (s->period_current+1) % s->runtime->periods;
- s->period_count++;
+ s->period_current = (s->period_current+1) % s->runtime->periods;
+ s->period_count++;
- psc_dma_bcom_enqueue_next_buffer(s);
+ psc_dma_bcom_enqueue_next_buffer(s);
+ }
}
- spin_unlock(&s->psc_dma->lock);
/* If the stream is active, then also inform the PCM middle layer
* of the period finished event. */
@@ -116,7 +118,6 @@ static int psc_dma_trigger(struct snd_soc_component *component,
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
u16 imr;
- unsigned long flags;
int i;
switch (cmd) {
@@ -135,19 +136,18 @@ static int psc_dma_trigger(struct snd_soc_component *component,
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
- spin_lock_irqsave(&psc_dma->lock, flags);
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
- for (i = 0; i < runtime->periods; i++)
- if (!bcom_queue_full(s->bcom_task))
- psc_dma_bcom_enqueue_next_buffer(s);
+ for (i = 0; i < runtime->periods; i++)
+ if (!bcom_queue_full(s->bcom_task))
+ psc_dma_bcom_enqueue_next_buffer(s);
- bcom_enable(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ bcom_enable(s->bcom_task);
+ }
out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
@@ -158,13 +158,13 @@ static int psc_dma_trigger(struct snd_soc_component *component,
substream->pstr->stream, s->period_count);
s->active = 0;
- spin_lock_irqsave(&psc_dma->lock, flags);
- bcom_disable(s->bcom_task);
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ bcom_disable(s->bcom_task);
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
+ }
break;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index c21104355aa0..2aefd6414ace 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -30,14 +30,13 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
int status;
unsigned int val;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command send status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (rdy)\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
@@ -53,19 +52,16 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (status == 0) {
pr_err("timeout on ac97 read (val) %x\n",
in_be16(&psc_dma->psc_regs->sr_csr.status));
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
/* Get the data */
val = in_be32(&psc_dma->psc_regs->ac97_data);
if (((val >> 24) & 0x7f) != reg) {
pr_err("reg echo error on ac97 read\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
val = (val >> 8) & 0xffff;
- mutex_unlock(&psc_dma->mutex);
return (unsigned short) val;
}
@@ -74,52 +70,46 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
{
int status;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (write)\n");
- goto out;
+ return;
}
/* Write data */
out_be32(&psc_dma->psc_regs->ac97_cmd,
((reg & 0x7f) << 24) | (val << 8));
-
- out:
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
udelay(3);
out_be32(&regs->sicr, psc_dma->sicr);
-
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
- dev_dbg(psc_dma->dev, "cold reset\n");
+ scoped_guard(mutex, &psc_dma->mutex) {
+ dev_dbg(psc_dma->dev, "cold reset\n");
- mpc5200_psc_ac97_gpio_reset(psc_dma->id);
+ mpc5200_psc_ac97_gpio_reset(psc_dma->id);
- /* Notify the PSC that a reset has occurred */
- out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
+ /* Notify the PSC that a reset has occurred */
+ out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
- /* Re-enable RX and TX */
- out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
-
- mutex_unlock(&psc_dma->mutex);
+ /* Re-enable RX and TX */
+ out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+ }
usleep_range(1000, 2000);
psc_ac97_warm_reset(ac97);
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 9ad44eeed6ad..7831136f4f12 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -170,6 +170,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
+ mpc5200_audio_dma_destroy(op);
return rc;
}
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 3629ceaaac17..82df398237da 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -14,6 +14,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/tlv.h>
@@ -73,14 +74,10 @@ static int sst_fill_and_send_cmd(struct sst_data *drv,
u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
void *cmd_data, u16 len)
{
- int ret;
+ guard(mutex)(&drv->lock);
- mutex_lock(&drv->lock);
- ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
- task_id, pipe_id, cmd_data, len);
- mutex_unlock(&drv->lock);
-
- return ret;
+ return sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+ task_id, pipe_id, cmd_data, len);
}
/*
@@ -167,7 +164,7 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
unsigned int val, mux;
u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
val = 1 << ctl_no;
/* search which slot/channel has this bit set - there should be only one */
for (mux = e->max; mux > 0; mux--)
@@ -175,7 +172,6 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
break;
ucontrol->value.enumerated.item[0] = mux;
- mutex_unlock(&drv->lock);
dev_dbg(c->dev, "%s - %s map = %#x\n",
is_tx ? "tx channel" : "rx slot",
@@ -235,7 +231,7 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
if (mux > e->max - 1)
return -EINVAL;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
/* first clear all registers of this bit */
for (i = 0; i < e->max; i++)
map[i] &= ~val;
@@ -244,7 +240,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
/* kctl set to 'none' and we reset the bits so send IPC */
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -258,7 +253,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -354,13 +348,12 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
struct sst_algo_control *bc = (void *)kcontrol->private_value;
dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (bc->type) {
case SST_ALGO_PARAMS:
memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
bc->type);
return -EINVAL;
@@ -368,7 +361,6 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
/*if pipe is enabled, need to send the algo params from here*/
if (bc->w && bc->w->power)
ret = sst_send_algo_cmd(drv, bc);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -475,7 +467,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
struct sst_gain_value *gv = mc->gain_val;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (mc->type) {
case SST_GAIN_TLV:
@@ -497,7 +489,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
mc->type);
return -EINVAL;
@@ -506,7 +497,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
if (mc->w && mc->w->power)
ret = sst_send_gain_cmd(drv, gv, mc->task_id,
mc->pipe_id | mc->instance_id, mc->module_id, 0);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -521,10 +511,9 @@ static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
struct sst_data *drv = snd_soc_component_get_drvdata(c);
struct sst_ids *ids = w->priv;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
sst_find_and_send_pipe_algo(drv, w->name, ids);
sst_set_pipe_gain(ids, drv, 0);
- mutex_unlock(&drv->lock);
return 0;
}
@@ -761,27 +750,29 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
return ret;
}
- mutex_lock(&drv->lock);
- if (enable)
- timer_usage++;
- else
- timer_usage--;
-
- /*
- * Send the command only if this call is the first enable or last
- * disable
- */
- if ((enable && (timer_usage == 1)) ||
- (!enable && (timer_usage == 0))) {
- ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
- SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
- sizeof(cmd.header) + cmd.header.length);
- if (ret && enable) {
+ scoped_guard(mutex, &drv->lock) {
+ if (enable)
+ timer_usage++;
+ else
timer_usage--;
- enable = false;
+
+ /*
+ * Send the command only if this call is the first enable or last
+ * disable
+ */
+ if ((enable && timer_usage == 1) ||
+ (!enable && timer_usage == 0)) {
+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
+ SST_FLAG_BLOCKED,
+ SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) +
+ cmd.header.length);
+ if (ret && enable) {
+ timer_usage--;
+ enable = false;
+ }
}
}
- mutex_unlock(&drv->lock);
if (!enable)
sst->ops->power(sst->dev, false);
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index f074af2499c8..9ee4d9926e06 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -11,6 +11,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -32,7 +33,7 @@ int sst_register_dsp(struct sst_device *dev)
return -EINVAL;
if (!try_module_get(dev->dev->driver->owner))
return -ENODEV;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
if (sst) {
dev_err(dev->dev, "we already have a device %s\n", sst->name);
module_put(dev->dev->driver->owner);
@@ -41,7 +42,7 @@ int sst_register_dsp(struct sst_device *dev)
}
dev_dbg(dev->dev, "registering device %s\n", dev->name);
sst = dev;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_register_dsp);
@@ -53,17 +54,15 @@ int sst_unregister_dsp(struct sst_device *dev)
if (dev != sst)
return -EINVAL;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
- if (!sst) {
- mutex_unlock(&sst_lock);
+ if (!sst)
return -EIO;
- }
module_put(sst->dev->driver->owner);
dev_dbg(dev->dev, "unreg %s\n", sst->name);
sst = NULL;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_unregister_dsp);
@@ -103,21 +102,14 @@ static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
void sst_set_stream_status(struct sst_runtime_stream *stream,
int state)
{
- unsigned long flags;
- spin_lock_irqsave(&stream->status_lock, flags);
+ guard(spinlock_irqsave)(&stream->status_lock);
stream->stream_status = state;
- spin_unlock_irqrestore(&stream->status_lock, flags);
}
static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
{
- int state;
- unsigned long flags;
-
- spin_lock_irqsave(&stream->status_lock, flags);
- state = stream->stream_status;
- spin_unlock_irqrestore(&stream->status_lock, flags);
- return state;
+ guard(spinlock_irqsave)(&stream->status_lock);
+ return stream->stream_status;
}
static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
@@ -304,7 +296,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
{
int ret_val = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct sst_runtime_stream *stream;
+ struct sst_runtime_stream *stream __free(kfree) = NULL;
stream = kzalloc_obj(*stream);
if (!stream)
@@ -312,15 +304,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
spin_lock_init(&stream->status_lock);
/* get the sst ops */
- mutex_lock(&sst_lock);
- if (!sst ||
- !try_module_get(sst->dev->driver->owner)) {
- dev_err(dai->dev, "no device available to run\n");
- ret_val = -ENODEV;
- goto out_ops;
+ scoped_guard(mutex, &sst_lock) {
+ if (!sst ||
+ !try_module_get(sst->dev->driver->owner)) {
+ dev_err(dai->dev, "no device available to run\n");
+ return -ENODEV;
+ }
+ stream->ops = sst->ops;
}
- stream->ops = sst->ops;
- mutex_unlock(&sst_lock);
stream->stream_info.str_id = 0;
@@ -330,7 +321,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
ret_val = power_up_sst(stream);
if (ret_val < 0)
- goto out_power_up;
+ return ret_val;
/*
* Make sure the period to be multiple of 1ms to align the
@@ -347,12 +338,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIODS, 2);
- return snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
-out_ops:
- mutex_unlock(&sst_lock);
-out_power_up:
- kfree(stream);
+ ret_val = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
+ if (ret_val < 0)
+ return ret_val;
+
+ stream = NULL;
+
return ret_val;
}
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 0d5e71e8a5b5..6c19ab63aa4f 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
@@ -180,9 +181,8 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
union interrupt_reg_mrfld isr;
union interrupt_reg_mrfld imr;
union ipc_header_mrfld clear_ipc;
- unsigned long irq_flags;
- spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ guard(spinlock_irqsave)(&sst_drv_ctx->ipc_spin_lock);
imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
@@ -200,7 +200,6 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
/* un mask busy interrupt */
imr.part.busy_interrupt = 0;
sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
- spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
}
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 22ae2d22f121..44bb11c69490 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -130,13 +130,15 @@ static int intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->pci = pci_dev_get(pci);
ret = sst_platform_get_resources(sst_drv_ctx);
if (ret < 0)
- goto do_free_drv_ctx;
+ goto do_put_pci;
pci_set_drvdata(pci, sst_drv_ctx);
sst_configure_runtime_pm(sst_drv_ctx);
return ret;
+do_put_pci:
+ pci_dev_put(sst_drv_ctx->pci);
do_free_drv_ctx:
sst_context_cleanup(sst_drv_ctx);
dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index 67b1ab14239f..0b0cfd70efbc 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/kobject.h>
#include <linux/pci.h>
#include <linux/fs.h>
@@ -64,9 +65,8 @@ u64 sst_shim_read64(void __iomem *addr, int offset)
void sst_set_fw_state_locked(
struct intel_sst_drv *sst_drv_ctx, int sst_state)
{
- mutex_lock(&sst_drv_ctx->sst_lock);
+ guard(mutex)(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = sst_state;
- mutex_unlock(&sst_drv_ctx->sst_lock);
}
/*
@@ -302,18 +302,17 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv)
{
int local;
- spin_lock(&drv->block_lock);
+ guard(spinlock)(&drv->block_lock);
/* find first zero index from lsb */
local = ffz(drv->pvt_id);
dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
if (local >= SST_MAX_BLOCKS){
- spin_unlock(&drv->block_lock);
dev_err(drv->dev, "PVT _ID error: no free id blocks ");
return -EINVAL;
}
/* toggle the index */
change_bit(local, &drv->pvt_id);
- spin_unlock(&drv->block_lock);
+
return local;
}
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b922eeaba843..cf600e1c986e 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/devcoredump.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -190,7 +191,7 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
{
struct avs_path *path;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
list_for_each_entry(path, &adev->path_list, node) {
struct avs_path_pipeline *ppl;
@@ -210,14 +211,11 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
if (cfg->copier.dma_type == INVALID_OBJECT_ID)
continue;
- if (!mod->gtw_attrs.lp_buffer_alloc) {
- spin_unlock(&adev->path_list_lock);
+ if (!mod->gtw_attrs.lp_buffer_alloc)
return false;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return true;
}
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index a8f05de338e0..370069247a7d 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -27,7 +27,7 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
list_for_each_entry(path, &adev->path_list, node) {
list_for_each_entry(ppl, &path->ppl_list, node) {
list_for_each_entry(mod, &ppl->mod_list, node) {
@@ -35,14 +35,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) ||
guid_equal(type, &AVS_GAIN_MOD_UUID)) &&
- mod->template->ctl_id == id) {
- spin_unlock(&adev->path_list_lock);
+ mod->template->ctl_id == id)
return mod;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 1a53856c2ffb..2afe59646896 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -14,6 +14,7 @@
// foundation of this driver
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -273,7 +274,7 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
ret = IRQ_HANDLED;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
/* Clear RIRB interrupt. */
status = snd_hdac_chip_readb(bus, RIRBSTS);
if (status & RIRB_INT_MASK) {
@@ -283,7 +284,6 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
ret = IRQ_HANDLED;
}
- spin_unlock_irq(&bus->reg_lock);
return ret;
}
diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h
index 94fe8729a5c1..c47fc4e8b02b 100644
--- a/sound/soc/intel/avs/debug.h
+++ b/sound/soc/intel/avs/debug.h
@@ -9,6 +9,7 @@
#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H
#define __SOUND_SOC_INTEL_AVS_DEBUG_H
+#include <linux/cleanup.h>
#include "messages.h"
#include "registers.h"
@@ -26,14 +27,9 @@ struct avs_dev;
static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
{
- unsigned long flags;
- int ret;
+ guard(spinlock_irqsave)(&adev->trace_lock);
- spin_lock_irqsave(&adev->trace_lock, flags);
- ret = avs_dsp_op(adev, log_buffer_status, msg);
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
- return ret;
+ return avs_dsp_op(adev, log_buffer_status, msg);
}
struct avs_apl_log_buffer_layout {
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 701c247227bf..9ab503da3b75 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
@@ -251,24 +252,22 @@ static int strace_release(struct inode *inode, struct file *file)
union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
struct avs_dev *adev = file->private_data;
unsigned long resource_mask;
- unsigned long flags, i;
+ unsigned long i;
u32 num_cores;
resource_mask = adev->logged_resources;
num_cores = adev->hw_cfg.dsp_cores;
- spin_lock_irqsave(&adev->trace_lock, flags);
+ scoped_guard(spinlock_irqsave, &adev->trace_lock) {
+ /* Gather any remaining logs. */
+ for_each_set_bit(i, &resource_mask, num_cores) {
+ msg.log.core = i;
+ avs_dsp_op(adev, log_buffer_status, &msg);
+ }
- /* Gather any remaining logs. */
- for_each_set_bit(i, &resource_mask, num_cores) {
- msg.log.core = i;
- avs_dsp_op(adev, log_buffer_status, &msg);
+ kfifo_free(&adev->trace_fifo);
}
- kfifo_free(&adev->trace_fifo);
-
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
module_put(adev->dev->driver->owner);
return 0;
}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index c0feb9edd7f6..71e7997e52c2 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -99,39 +100,39 @@ static void avs_dsp_recovery(struct avs_dev *adev)
unsigned int core_mask;
int ret;
- mutex_lock(&adev->comp_list_mutex);
- /* disconnect all running streams */
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_card *card;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ /* disconnect all running streams */
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_card *card;
- card = acomp->base.card;
- if (!card)
- continue;
-
- for_each_card_rtds(card, rtd) {
- struct snd_pcm *pcm;
- int dir;
-
- pcm = rtd->pcm;
- if (!pcm || rtd->dai_link->no_pcm)
+ card = acomp->base.card;
+ if (!card)
continue;
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream;
+ for_each_card_rtds(card, rtd) {
+ struct snd_pcm *pcm;
+ int dir;
- substream = pcm->streams[dir].substream;
- if (!substream || !substream->runtime)
+ pcm = rtd->pcm;
+ if (!pcm || rtd->dai_link->no_pcm)
continue;
- /* No need for _irq() as we are in nonatomic context. */
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
- snd_pcm_stream_unlock(substream);
+ for_each_pcm_streams(dir) {
+ struct snd_pcm_substream *substream;
+
+ substream = pcm->streams[dir].substream;
+ if (!substream || !substream->runtime)
+ continue;
+
+ /* No need for _irq() as we are in nonatomic context. */
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock(substream);
+ }
}
}
}
- mutex_unlock(&adev->comp_list_mutex);
/* forcibly shutdown all cores */
core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0);
@@ -397,7 +398,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
if (!ipc->ready)
return -EPERM;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, reply);
@@ -412,7 +413,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
/* Same treatment as on exception, just stack_dump=0. */
avs_dsp_exception_caught(adev, &msg);
}
- goto exit;
+ return ret;
}
ret = ipc->rx.rsp.status;
@@ -436,8 +437,6 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
memcpy(reply->data, ipc->rx.data, reply->size);
}
-exit:
- mutex_unlock(&ipc->msg_mutex);
return ret;
}
@@ -501,7 +500,7 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
struct avs_ipc *ipc = adev->ipc;
int ret;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, NULL);
@@ -522,8 +521,6 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
name, request->glb.primary, request->glb.ext.val, ret);
- mutex_unlock(&ipc->msg_mutex);
-
return ret;
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 353e343b1d28..bebdc79ec88e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -630,15 +631,15 @@ static int avs_load_firmware(struct avs_dev *adev, bool purge)
if (ret)
goto reenable_gating;
- mutex_lock(&adev->comp_list_mutex);
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct avs_tplg *tplg = acomp->tplg;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct avs_tplg *tplg = acomp->tplg;
- ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
- if (ret < 0)
- break;
+ ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
+ if (ret < 0)
+ break;
+ }
}
- mutex_unlock(&adev->comp_list_mutex);
reenable_gating:
avs_hda_l1sen_enable(adev, true);
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 2291f9728a54..213d6ecdd7cc 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <acpi/nhlt.h>
#include <sound/pcm_params.h>
@@ -69,16 +70,13 @@ avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id)
if (!template)
return NULL;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Only one variant of given path template may be instantiated at a time. */
list_for_each_entry(path, &adev->path_list, node) {
- if (path->template->owner == template) {
- spin_unlock(&adev->path_list_lock);
+ if (path->template->owner == template)
return path;
- }
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
@@ -1305,7 +1303,7 @@ void avs_path_free(struct avs_path *path)
struct avs_path *cpath, *csave;
struct avs_dev *adev = path->owner;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Free all condpaths this path spawned. */
list_for_each_entry_safe(cpath, csave, &path->source_list, source_node)
@@ -1314,8 +1312,6 @@ void avs_path_free(struct avs_path *path)
avs_condpath_free(path->owner, cpath);
avs_path_free_unlocked(path);
-
- mutex_unlock(&adev->path_mutex);
}
struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
@@ -1334,13 +1330,13 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
}
/* Serialize path and its components creation. */
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Satisfy needs of avs_path_find_tplg(). */
- mutex_lock(&adev->comp_list_mutex);
+ guard(mutex)(&adev->comp_list_mutex);
path = avs_path_create_unlocked(adev, dma_id, variant);
if (IS_ERR(path))
- goto exit;
+ return path;
ret = avs_condpaths_walk_all(adev, path);
if (ret) {
@@ -1348,10 +1344,6 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
path = ERR_PTR(ret);
}
-exit:
- mutex_unlock(&adev->comp_list_mutex);
- mutex_unlock(&adev->path_mutex);
-
return path;
}
@@ -1496,15 +1488,13 @@ static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path)
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* If either source or sink stops, so do the attached conditional paths. */
list_for_each_entry(cpath, &path->source_list, source_node)
avs_condpath_pause(adev, cpath);
list_for_each_entry(cpath, &path->sink_list, sink_node)
avs_condpath_pause(adev, cpath);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_pause(struct avs_path *path)
@@ -1560,7 +1550,7 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Run conditional paths only if source and sink are both running. */
list_for_each_entry(cpath, &path->source_list, source_node)
@@ -1572,8 +1562,6 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
cpath->sink->state == AVS_PPL_STATE_RUNNING)
avs_condpath_run(adev, cpath, trigger);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_run(struct avs_path *path, int trigger)
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index ee36725ac731..ea14ec173855 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
@@ -48,13 +49,12 @@ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_mo
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_entry_index(adev, uuid);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -62,13 +62,12 @@ int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_modu
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -86,13 +85,12 @@ bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
bool ret = false;
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
ret = ida_is_empty(adev->mod_idas[idx]);
- mutex_unlock(&adev->modres_mutex);
return ret;
}
@@ -163,68 +161,57 @@ int avs_module_info_init(struct avs_dev *adev, bool purge)
if (ret)
return AVS_IPC_RET(ret);
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
ret = avs_module_ida_alloc(adev, info, purge);
if (ret < 0) {
dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
- goto exit;
+ return ret;
}
/* Refresh current information with newly received table. */
kfree(adev->mods_info);
adev->mods_info = info;
-exit:
- mutex_unlock(&adev->modres_mutex);
return ret;
}
void avs_module_info_free(struct avs_dev *adev)
{
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
avs_module_ida_destroy(adev);
kfree(adev->mods_info);
adev->mods_info = NULL;
-
- mutex_unlock(&adev->modres_mutex);
}
int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
{
- int ret, idx, max_id;
+ int idx, max_id;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx == -ENOENT) {
dev_err(adev->dev, "invalid module id: %d", module_id);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
max_id = adev->mods_info->entries[idx].instance_max_count - 1;
- ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
-exit:
- mutex_unlock(&adev->modres_mutex);
- return ret;
+
+ return ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
}
void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
- if (idx == -ENOENT) {
+ if (idx == -ENOENT)
dev_err(adev->dev, "invalid module id: %d", module_id);
- goto exit;
- }
-
- ida_free(adev->mod_idas[idx], instance_id);
-exit:
- mutex_unlock(&adev->modres_mutex);
+ else
+ ida_free(adev->mod_idas[idx], instance_id);
}
/*
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index d43daf9b025d..24226a387cc2 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -1285,7 +1285,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
if (ret < 0)
goto err_end;
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 7910d5d9ac4f..25cd12eab4b1 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -2,24 +2,131 @@
//
// Loongson ASoC Audio Machine driver
//
-// Copyright (C) 2023 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
// Author: Yingkun Meng <mengyingkun@loongson.cn>
+// Binbin Zhou <zhoubinbin@loongson.cn>
//
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
#include <linux/pci.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
static char codec_name[SND_ACPI_I2C_ID_LEN];
struct loongson_card_data {
struct snd_soc_card snd_card;
unsigned int mclk_fs;
+ struct gpio_desc *gpiod_hp_det;
+ struct gpio_desc *gpiod_hp_ctl;
+ struct gpio_desc *gpiod_spkr_en;
+ const struct loongson_card_config *cfg;
+};
+
+struct loongson_card_config {
+ unsigned int fmt;
+ bool add_hp_jack;
+ bool add_dapm_widgets;
+ bool add_dapm_routes;
+};
+
+static const struct loongson_card_config ls2k1000_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_forever_pi_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = true,
+ .add_dapm_widgets = true,
+ .add_dapm_routes = true,
+};
+
+static int tegra_machine_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct loongson_card_data *priv = snd_soc_card_get_drvdata(card);
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Speaker"))
+ gpiod_set_value_cansleep(priv->gpiod_spkr_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Headphone"))
+ gpiod_set_value_cansleep(priv->gpiod_hp_ctl,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", tegra_machine_event),
+ SND_SOC_DAPM_SPK("Speaker", tegra_machine_event),
};
+/* Headphones Jack */
+
+static struct snd_soc_jack loongson_asoc_hp_jack;
+
+static struct snd_soc_jack_pin loongson_asoc_hp_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1
+ },
+};
+
+static struct snd_soc_jack_gpio loongson_asoc_hp_jack_gpio = {
+ .name = "Headphones detection",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+};
+
+static int loongson_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct loongson_card_data *ls_priv = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (!ls_priv->cfg->add_hp_jack || !ls_priv->gpiod_hp_det)
+ return 0;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headphones Jack",
+ SND_JACK_HEADPHONE,
+ &loongson_asoc_hp_jack,
+ loongson_asoc_hp_jack_pins,
+ ARRAY_SIZE(loongson_asoc_hp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headphones Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ loongson_asoc_hp_jack_gpio.desc = ls_priv->gpiod_hp_det;
+
+ ret = snd_soc_jack_add_gpios(&loongson_asoc_hp_jack, 1, &loongson_asoc_hp_jack_gpio);
+ if (ret)
+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+
+ return ret;
+}
+
static int loongson_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -45,7 +152,7 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- return 0;
+ return snd_soc_runtime_set_dai_fmt(rtd, ls_card->cfg->fmt);
}
static const struct snd_soc_ops loongson_ops = {
@@ -61,8 +168,7 @@ static struct snd_soc_dai_link loongson_dai_links[] = {
{
.name = "Loongson Audio Port",
.stream_name = "Loongson Audio",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF
- | SND_SOC_DAIFMT_CBC_CFC,
+ .init = loongson_asoc_machine_init,
SND_SOC_DAILINK_REG(analog),
.ops = &loongson_ops,
},
@@ -91,7 +197,7 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
const char *codec_dai_name;
struct acpi_device *adev;
struct device *phy_dev;
- int i;
+ int i, ret;
/* fixup platform name based on reference node */
adev = loongson_card_acpi_find_device(card, "cpu");
@@ -108,7 +214,9 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
return -ENOENT;
snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev));
- device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ ret = device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ if (ret)
+ return ret;
for (i = 0; i < card->num_links; i++) {
loongson_dai_links[i].platforms->name = dev_name(phy_dev);
@@ -121,16 +229,35 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
static int loongson_card_parse_of(struct loongson_card_data *data)
{
- struct device_node *cpu, *codec;
struct snd_soc_card *card = &data->snd_card;
+ struct device_node *cpu, *codec;
struct device *dev = card->dev;
int ret, i;
+ data->gpiod_hp_det = devm_gpiod_get_optional(dev, "hp-det", GPIOD_IN);
+ if (IS_ERR(data->gpiod_hp_det))
+ return PTR_ERR(data->gpiod_hp_det);
+
+ data->gpiod_hp_ctl = devm_gpiod_get_optional(dev, "hp-ctl", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_hp_ctl))
+ return PTR_ERR(data->gpiod_hp_ctl);
+
+ data->gpiod_spkr_en = devm_gpiod_get_optional(dev, "spkr-en", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_spkr_en))
+ return PTR_ERR(data->gpiod_spkr_en);
+
+ if (data->cfg->add_dapm_routes) {
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret)
+ return ret;
+ }
+
cpu = of_get_child_by_name(dev->of_node, "cpu");
if (!cpu) {
dev_err(dev, "platform property missing or invalid\n");
return -EINVAL;
}
+
codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec) {
dev_err(dev, "audio-codec property missing or invalid\n");
@@ -175,12 +302,22 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
if (!ls_priv)
return -ENOMEM;
+ ls_priv->cfg = (const struct loongson_card_config *)device_get_match_data(dev);
+ if (!ls_priv->cfg)
+ return -EINVAL;
+
card = &ls_priv->snd_card;
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = loongson_dai_links;
card->num_links = ARRAY_SIZE(loongson_dai_links);
+
+ if (ls_priv->cfg->add_dapm_widgets) {
+ card->dapm_widgets = loongson_aosc_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets);
+ }
+
snd_soc_card_set_drvdata(card, ls_priv);
ret = device_property_read_string(dev, "model", &card->name);
@@ -200,7 +337,19 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_asoc_dt_ids[] = {
- { .compatible = "loongson,ls-audio-card" },
+ /* Loongson-2K1000/Loongson-2K2000/LS7A */
+ {
+ .compatible = "loongson,ls-audio-card",
+ .data = &ls2k1000_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-forever-pi-audio-card",
+ .data = &ls2k0300_forever_pi_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-dl2k0300b-audio-card",
+ .data = &ls2k0300_dl2k0300b_card_config
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids);
diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c
index ac054b6ce632..82d95c6644ef 100644
--- a/sound/soc/loongson/loongson_i2s_plat.c
+++ b/sound/soc/loongson/loongson_i2s_plat.c
@@ -2,7 +2,7 @@
//
// Loongson I2S controller master mode dirver(platform device)
//
-// Copyright (C) 2023-2024 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
//
// Author: Yingkun Meng <mengyingkun@loongson.cn>
// Binbin Zhou <zhoubinbin@loongson.cn>
@@ -21,6 +21,7 @@
#include "loongson_i2s.h"
#include "loongson_dma.h"
+/* Loongson-2K1000 APBDMA routing */
#define LOONGSON_I2S_RX_DMA_OFFSET 21
#define LOONGSON_I2S_TX_DMA_OFFSET 18
@@ -30,6 +31,11 @@
#define LOONGSON_DMA3_CONF 0x3
#define LOONGSON_DMA4_CONF 0x4
+struct loongson_i2s_plat_config {
+ int rev_id;
+ int (*i2s_dma_config)(struct platform_device *pdev);
+};
+
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
{
int val;
@@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev)
return 0;
}
+static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = {
+ .rev_id = 1,
+};
+
+static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = {
+ .rev_id = 0,
+ .i2s_dma_config = loongson_i2s_apbdma_config,
+};
+
static int loongson_i2s_plat_probe(struct platform_device *pdev)
{
+ const struct loongson_i2s_plat_config *plat_config;
struct device *dev = &pdev->dev;
struct loongson_i2s *i2s;
struct resource *res;
@@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (!i2s)
return -ENOMEM;
- ret = loongson_i2s_apbdma_config(pdev);
- if (ret)
- return ret;
+ plat_config = device_get_match_data(dev);
+ if (!plat_config)
+ return -EINVAL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (plat_config->i2s_dma_config) {
+ ret = plat_config->i2s_dma_config(pdev);
+ if (ret)
+ return ret;
+ }
+
+ i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->reg_base))
return dev_err_probe(dev, PTR_ERR(i2s->reg_base),
"devm_ioremap_resource failed\n");
@@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (IS_ERR(i2s_clk))
return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n");
i2s->clk_rate = clk_get_rate(i2s_clk);
+ i2s->rev_id = plat_config->rev_id;
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
dev_set_name(dev, LS_I2S_DRVNAME);
dev_set_drvdata(dev, i2s);
+ if (i2s->rev_id == 1) {
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET);
+ fsleep(200);
+ }
+
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
&loongson_i2s_dai, 1);
if (ret)
@@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_i2s_ids[] = {
- { .compatible = "loongson,ls2k1000-i2s" },
+ { .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config },
+ { .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_i2s_ids);
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 4af7bbb58010..224746e7664f 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,7 +7,7 @@ config SND_SOC_MEDIATEK
config SND_SOC_MT2701
tristate "ASoC support for Mediatek MT2701 chip"
- depends on ARCH_MEDIATEK
+ depends on ARCH_MEDIATEK || COMPILE_TEST
select SND_SOC_MEDIATEK
help
This adds ASoC driver for Mediatek MT2701 boards
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 3d6d7bc05b87..8c5096482520 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -315,7 +315,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
&mt8173_rt5650_priv.pll_from);
if (ret) {
dev_err(&pdev->dev,
- "%s snd_soc_register_card fail %d\n",
+ "%s device_property_read_u32() fail %d\n",
__func__, ret);
}
}
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index 24078e4396b0..f9ec0ebb01f0 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -4,6 +4,8 @@ snd-soc-meson-aiu-y := aiu.o
snd-soc-meson-aiu-y += aiu-acodec-ctrl.o
snd-soc-meson-aiu-y += aiu-codec-ctrl.o
snd-soc-meson-aiu-y += aiu-encoder-i2s.o
+snd-soc-meson-aiu-y += gx-formatter.o
+snd-soc-meson-aiu-y += aiu-formatter-i2s.o
snd-soc-meson-aiu-y += aiu-encoder-spdif.o
snd-soc-meson-aiu-y += aiu-fifo.o
snd-soc-meson-aiu-y += aiu-fifo-i2s.o
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index 3b4061508c18..83b579e98f1c 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -10,14 +10,11 @@
#include <sound/soc-dai.h>
#include "aiu.h"
+#include "gx-formatter.h"
+#include "gx-interface.h"
-#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
-#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
-#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
-#define AIU_RST_SOFT_I2S_FAST BIT(0)
-#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
#define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2)
#define AIU_CLK_CTRL_AOCLK_INVERT BIT(6)
@@ -35,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
}
-static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
-{
- /* Always operate in split (classic interleaved) mode */
- unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
-
- /* Reset required to update the pipeline */
- snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
- snd_soc_component_read(component, AIU_I2S_SYNC);
-
- switch (params_physical_width(params)) {
- case 16: /* Nothing to do */
- break;
-
- case 32:
- desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT);
- break;
-
- default:
- return -EINVAL;
- }
-
- switch (params_channels(params)) {
- case 2: /* Nothing to do */
- break;
- case 8:
- desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
- AIU_I2S_SOURCE_DESC_MODE_8CH |
- AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT |
- AIU_I2S_SOURCE_DESC_MODE_SPLIT,
- desc);
-
- return 0;
-}
-
static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -112,6 +66,9 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
{
+ struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
+
/*
* NOTE: this HW is odd.
* In most configuration, the i2s divider is 'mclk / blck'.
@@ -126,6 +83,18 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
return -EINVAL;
}
bs += bs / 2;
+ iface->bs_quirk = true;
+ } else {
+ /*
+ * If the bs quirk is currently applied for one stream and another
+ * ones tries to setup a configuration for which the quirk is
+ * not required, then fail.
+ */
+ if (iface->bs_quirk) {
+ dev_err(component->dev,
+ "bclk requirements are incompatible with active stream\n");
+ return -EINVAL;
+ }
}
/* Use CLK_MORE for mclk to bclk divider */
@@ -145,21 +114,17 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
struct snd_pcm_hw_params *params)
{
struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int srate = params_rate(params);
unsigned int fs, bs;
int ret;
/* Get the oversampling factor */
- fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
+ fs = DIV_ROUND_CLOSEST(iface->mclk_rate, srate);
- if (fs % 64)
+ if ((fs % 64) || (fs == 0))
return -EINVAL;
- /* Send data MSB first */
- snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
- AIU_I2S_DAC_CFG_MSB_FIRST,
- AIU_I2S_DAC_CFG_MSB_FIRST);
-
/* Set bclk to lrlck ratio */
snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
AIU_CODEC_DAC_LRCLK_CTRL_DIV,
@@ -188,24 +153,53 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct gx_iface *iface = ts->iface;
struct snd_soc_component *component = dai->component;
int ret;
- /* Disable the clock while changing the settings */
- aiu_encoder_i2s_divider_enable(component, false);
-
- ret = aiu_encoder_i2s_setup_desc(component, params);
- if (ret) {
- dev_err(dai->dev, "setting i2s desc failed\n");
- return ret;
+ /*
+ * Enforce interface wide rate symmetry only if there is more than
+ * 1 stream active.
+ */
+ if (snd_soc_dai_active(dai) > 1) {
+ if (iface->rate && iface->rate != params_rate(params)) {
+ dev_err(dai->dev, "can't set iface rate (%d != %d)\n",
+ iface->rate, params_rate(params));
+ return -EINVAL;
+ }
}
ret = aiu_encoder_i2s_set_clocks(component, params);
if (ret) {
- dev_err(dai->dev, "setting i2s clocks failed\n");
+ dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret);
return ret;
}
+ iface->rate = params_rate(params);
+ ts->physical_width = params_physical_width(params);
+ ts->width = params_width(params);
+ ts->channels = params_channels(params);
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct snd_soc_component *component = dai->component;
+ int ret;
+
+ if (ts->clk_enabled)
+ return 0;
+
+ ret = clk_prepare_enable(ts->iface->mclk);
+ if (ret)
+ return ret;
+
+ ts->clk_enabled = true;
+
aiu_encoder_i2s_divider_enable(component, true);
return 0;
@@ -214,9 +208,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct gx_iface *iface = ts->iface;
struct snd_soc_component *component = dai->component;
- aiu_encoder_i2s_divider_enable(component, false);
+ /*
+ * If this is the last substream being closed then disable the i2s
+ * clock divider and clear 'iface->rate'.
+ */
+ if (snd_soc_dai_active(dai) <= 1) {
+ aiu_encoder_i2s_divider_enable(component, 0);
+ iface->rate = 0;
+ iface->bs_quirk = false;
+ }
+
+ if (ts->clk_enabled) {
+ clk_disable_unprepare(ts->iface->mclk);
+ ts->clk_enabled = false;
+ }
return 0;
}
@@ -224,6 +233,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
+ struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
unsigned int val = 0;
unsigned int skew;
@@ -255,9 +266,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
skew = 0;
break;
default:
+ dev_err(dai->dev, "unsupported dai format\n");
return -EINVAL;
}
+ iface->fmt = fmt;
+
val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew);
snd_soc_component_update_bits(component, AIU_CLK_CTRL,
AIU_CLK_CTRL_LRCLK_INVERT |
@@ -272,6 +286,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
+ struct gx_iface *iface = &aiu->i2s.iface;
int ret;
if (WARN_ON(clk_id != 0))
@@ -280,11 +295,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dir == SND_SOC_CLOCK_IN)
return 0;
- ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq);
- if (ret)
- dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
+ ret = clk_set_rate(iface->mclk, freq);
+ if (ret) {
+ dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret);
+ return ret;
+ }
- return ret;
+ iface->mclk_rate = freq;
+
+ return 0;
}
static const unsigned int hw_channels[] = {2, 8};
@@ -305,15 +324,54 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_channel_constraints);
if (ret) {
- dev_err(dai->dev, "adding channels constraints failed\n");
+ dev_err(dai->dev, "adding channels constraints failed: %d\n", ret);
return ret;
}
- ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks);
- if (ret)
- dev_err(dai->dev, "failed to enable i2s clocks\n");
+ /*
+ * Enable only clocks which are required for the interface internal
+ * logic. MCLK is enabled/disabled from the formatter and the I2S
+ * divider is enabled/disabled in "hw_params"/"hw_free", respectively.
+ */
+ ret = clk_prepare_enable(aiu->i2s.clks[PCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable PCLK: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[MIXER].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable MIXER: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[AOCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
- return ret;
+ /*
+ * We're always operating in split mode for the playback stream.
+ *
+ * This setting arguably belong to the 'aiu-formatter', but it's kept
+ * here for backward compatibility reason. At reset the I2S encoder
+ * operates in normal mode which would only support 8ch, but by default
+ * only 2ch are enabled. If a playback stream is started without
+ * changing to split mode, then the I2S encoder doesn't consume audio
+ * samples and the playback fails.
+ * Moving this to 'aiu-formatter' would cause the split mode to be set
+ * only when the formatter is enabled, which doesn't happen at boot as
+ * the default value for "HDMI CTRL SRC" is "DISABLED".
+ */
+ ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
+ if (ret < 0)
+ dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret);
+
+ return 0;
}
static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
@@ -321,14 +379,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
- clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks);
+ clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+}
+
+static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = gx_stream_start(ts);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ gx_stream_stop(ts);
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai)
+{
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ ts = snd_soc_dai_dma_data_get(dai, stream);
+ if (ts)
+ gx_stream_free(ts);
+
+ snd_soc_dai_dma_data_set(dai, stream, NULL);
+ }
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai)
+{
+ struct aiu *aiu = snd_soc_dai_get_drvdata(dai);
+ struct gx_iface *iface = &aiu->i2s.iface;
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ if (!snd_soc_dai_get_widget(dai, stream))
+ continue;
+
+ ts = gx_stream_alloc(iface);
+ if (!ts) {
+ aiu_encoder_i2s_remove_dai(dai);
+ return -ENOMEM;
+ }
+ snd_soc_dai_dma_data_set(dai, stream, ts);
+ }
+
+ iface->mclk = aiu->i2s.clks[MCLK].clk;
+ iface->mclk_rate = clk_get_rate(iface->mclk);
+
+ return 0;
}
const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
+ .probe = aiu_encoder_i2s_probe_dai,
+ .remove = aiu_encoder_i2s_remove_dai,
.hw_params = aiu_encoder_i2s_hw_params,
+ .prepare = aiu_encoder_i2s_prepare,
.hw_free = aiu_encoder_i2s_hw_free,
.set_fmt = aiu_encoder_i2s_set_fmt,
.set_sysclk = aiu_encoder_i2s_set_sysclk,
.startup = aiu_encoder_i2s_startup,
.shutdown = aiu_encoder_i2s_shutdown,
+ .trigger = aiu_encoder_i2s_trigger,
};
diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c
new file mode 100644
index 000000000000..b4604734fe88
--- /dev/null
+++ b/sound/soc/meson/aiu-formatter-i2s.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "aiu.h"
+#include "gx-formatter.h"
+
+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
+#define AIU_RST_SOFT_I2S_FAST BIT(0)
+
+#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
+
+static struct snd_soc_dai *
+aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dai *be;
+
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (!p->connect)
+ continue;
+
+ if (p->sink->id == snd_soc_dapm_dai_in)
+ return (struct snd_soc_dai *)p->sink->priv;
+
+ be = aiu_formatter_i2s_get_be(p->sink);
+ if (be)
+ return be;
+ }
+
+ return NULL;
+}
+
+static struct gx_stream *
+aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w);
+
+ if (!be)
+ return NULL;
+
+ return snd_soc_dai_dma_data_get_playback(be);
+}
+
+static int aiu_formatter_i2s_prepare(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts)
+{
+ /* Always operate in split (classic interleaved) mode */
+ unsigned int desc = 0;
+ unsigned int tmp;
+
+ /* Reset required to update the pipeline */
+ regmap_write(map, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
+ regmap_read(map, AIU_I2S_SYNC, &tmp);
+
+ switch (ts->physical_width) {
+ case 16: /* Nothing to do */
+ break;
+
+ case 32:
+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (ts->channels) {
+ case 2: /* Nothing to do */
+ break;
+ case 8:
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(map, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT,
+ desc);
+
+ /* Send data MSB first */
+ regmap_update_bits(map, AIU_I2S_DAC_CFG,
+ AIU_I2S_DAC_CFG_MSB_FIRST,
+ AIU_I2S_DAC_CFG_MSB_FIRST);
+
+ return 0;
+}
+
+const struct gx_formatter_ops aiu_formatter_i2s_ops = {
+ .get_stream = aiu_formatter_i2s_get_stream,
+ .prepare = aiu_formatter_i2s_prepare,
+};
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index f2890111c1d2..64ace4d25d92 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
static const struct snd_kcontrol_new aiu_spdif_encode_mux =
SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
-static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
- SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
- &aiu_spdif_encode_mux),
+#define AIU_WIDGET_SPDIF_SRC_SEL 0
+#define AIU_WIDGET_I2S_FORMATTER 1
+
+static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
+ [AIU_WIDGET_SPDIF_SRC_SEL] =
+ SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
+ &aiu_spdif_encode_mux),
+ [AIU_WIDGET_I2S_FORMATTER] =
+ SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0,
+ gx_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
};
static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
- { "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
+ { "I2S Formatter", NULL, "I2S FIFO Playback" },
+ { "I2S Encoder Playback", NULL, "I2S Formatter" },
{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
@@ -172,6 +181,11 @@ static const struct regmap_config aiu_regmap_cfg = {
.max_register = 0x2ac,
};
+const struct gx_formatter_driver aiu_formatter_i2s_drv = {
+ .regmap_cfg = &aiu_regmap_cfg,
+ .ops = &aiu_formatter_i2s_ops,
+};
+
static int aiu_clk_bulk_get(struct device *dev,
const char * const *ids,
unsigned int num,
@@ -282,6 +296,14 @@ static int aiu_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* Allocate the aiu-formatter into its widget */
+ ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER],
+ &aiu_formatter_i2s_drv, map);
+ if (ret) {
+ dev_err(dev, "Failed to allocate aiu formatter\n");
+ goto err;
+ }
+
/* Register the cpu component of the aiu */
ret = snd_soc_register_component(dev, &aiu_cpu_component,
aiu_cpu_dai_drv,
@@ -310,12 +332,14 @@ static int aiu_probe(struct platform_device *pdev)
return 0;
err:
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(dev);
return ret;
}
static void aiu_remove(struct platform_device *pdev)
{
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(&pdev->dev);
}
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
index 0f94c8bf6081..7d0b98c1f351 100644
--- a/sound/soc/meson/aiu.h
+++ b/sound/soc/meson/aiu.h
@@ -7,6 +7,8 @@
#ifndef _MESON_AIU_H
#define _MESON_AIU_H
+#include "gx-formatter.h"
+
struct clk;
struct clk_bulk_data;
struct device;
@@ -25,6 +27,7 @@ struct aiu_interface {
struct clk_bulk_data *clks;
unsigned int clk_num;
int irq;
+ struct gx_iface iface;
};
struct aiu_platform_data {
@@ -58,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops;
+extern const struct gx_formatter_ops aiu_formatter_i2s_ops;
#define AIU_IEC958_BPF 0x000
#define AIU_958_MISC 0x010
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
index a95375b53f0a..21941ee552c5 100644
--- a/sound/soc/meson/g12a-toacodec.c
+++ b/sound/soc/meson/g12a-toacodec.c
@@ -312,7 +312,7 @@ static int g12a_toacodec_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
index d541ca4acfaf..967109ca2b57 100644
--- a/sound/soc/meson/g12a-tohdmitx.c
+++ b/sound/soc/meson/g12a-tohdmitx.c
@@ -251,7 +251,7 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c
new file mode 100644
index 000000000000..311e63affb23
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "gx-formatter.h"
+
+struct gx_formatter {
+ struct list_head list;
+ struct gx_stream *stream;
+ const struct gx_formatter_driver *drv;
+ bool enabled;
+ struct regmap *map;
+};
+
+static int gx_formatter_enable(struct gx_formatter *formatter)
+{
+ int ret;
+
+ /* Do nothing if the formatter is already enabled */
+ if (formatter->enabled)
+ return 0;
+
+ /* Setup the stream parameter in the formatter */
+ if (formatter->drv->ops->prepare) {
+ ret = formatter->drv->ops->prepare(formatter->map,
+ formatter->drv->quirks,
+ formatter->stream);
+ if (ret)
+ return ret;
+ }
+
+ /* Finally, actually enable the formatter */
+ if (formatter->drv->ops->enable)
+ formatter->drv->ops->enable(formatter->map);
+
+ formatter->enabled = true;
+
+ return 0;
+}
+
+static void gx_formatter_disable(struct gx_formatter *formatter)
+{
+ /* Do nothing if the formatter is already disabled */
+ if (!formatter->enabled)
+ return;
+
+ if (formatter->drv->ops->disable)
+ formatter->drv->ops->disable(formatter->map);
+
+ formatter->enabled = false;
+}
+
+static int gx_formatter_attach(struct gx_formatter *formatter)
+{
+ struct gx_stream *ts = formatter->stream;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Catch up if the stream is already running when we attach */
+ if (ts->ready) {
+ ret = gx_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ list_add_tail(&formatter->list, &ts->formatter_list);
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+
+static void gx_formatter_detach(struct gx_formatter *formatter)
+{
+ struct gx_stream *ts = formatter->stream;
+
+ if (!ts)
+ return;
+
+ mutex_lock(&ts->lock);
+ list_del(&formatter->list);
+ mutex_unlock(&ts->lock);
+
+ gx_formatter_disable(formatter);
+}
+
+static int gx_formatter_power_up(struct gx_formatter *formatter,
+ struct snd_soc_dapm_widget *w)
+{
+ struct gx_stream *ts = formatter->drv->ops->get_stream(w);
+ int ret;
+
+ /*
+ * If we don't get a stream at this stage, it would mean that the
+ * widget is powering up but is not attached to any backend DAI.
+ * It should not happen, ever !
+ */
+ if (WARN_ON(!ts))
+ return -ENODEV;
+
+ formatter->stream = ts;
+ INIT_LIST_HEAD(&formatter->list);
+ ret = gx_formatter_attach(formatter);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void gx_formatter_power_down(struct gx_formatter *formatter)
+{
+ gx_formatter_detach(formatter);
+ formatter->stream = NULL;
+}
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event)
+{
+ struct snd_soc_component *c;
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ c = snd_soc_dapm_to_component(w->dapm);
+
+ if (w->priv)
+ formatter = w->priv;
+ else
+ formatter = snd_soc_component_get_drvdata(c);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = gx_formatter_power_up(formatter, w);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ gx_formatter_power_down(formatter);
+ break;
+
+ default:
+ dev_err(c->dev, "Unexpected event %d\n", event);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_event);
+
+int gx_formatter_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct gx_formatter_driver *drv;
+ struct gx_formatter *formatter;
+ void __iomem *regs;
+
+ drv = of_device_get_match_data(dev);
+ if (!drv) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, formatter);
+ formatter->drv = drv;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
+ if (IS_ERR(formatter->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(formatter->map));
+ return PTR_ERR(formatter->map);
+ }
+
+ return devm_snd_soc_register_component(dev, drv->component_drv,
+ NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gx_formatter_probe);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap)
+{
+ struct gx_formatter *formatter;
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+
+ formatter->drv = drv;
+ formatter->map = regmap;
+
+ w->priv = formatter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_create);
+
+int gx_stream_start(struct gx_stream *ts)
+{
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Start all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ ret = gx_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ ts->ready = true;
+
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_stream_start);
+
+void gx_stream_stop(struct gx_stream *ts)
+{
+ struct gx_formatter *formatter;
+
+ mutex_lock(&ts->lock);
+ ts->ready = false;
+
+ /* Stop all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ gx_formatter_disable(formatter);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+EXPORT_SYMBOL_GPL(gx_stream_stop);
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface)
+{
+ struct gx_stream *ts;
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts) {
+ INIT_LIST_HEAD(&ts->formatter_list);
+ mutex_init(&ts->lock);
+ ts->iface = iface;
+ }
+
+ return ts;
+}
+EXPORT_SYMBOL_GPL(gx_stream_alloc);
+
+void gx_stream_free(struct gx_stream *ts)
+{
+ /*
+ * If the list is not empty, it would mean that one of the formatter
+ * widget is still powered and attached to the interface while we
+ * are removing the TDM DAI. It should not be possible
+ */
+ WARN_ON(!list_empty(&ts->formatter_list));
+ mutex_destroy(&ts->lock);
+ kfree(ts);
+}
+EXPORT_SYMBOL_GPL(gx_stream_free);
+
+MODULE_DESCRIPTION("Amlogic GX formatter driver");
+MODULE_AUTHOR("Valerio Setti <vsetti@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h
new file mode 100644
index 000000000000..b90b1814d79b
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_FORMATTER_H
+#define _MESON_GX_FORMATTER_H
+
+#include "gx-interface.h"
+
+struct platform_device;
+struct regmap;
+struct snd_soc_dapm_widget;
+struct snd_kcontrol;
+
+struct gx_formatter_hw {
+ unsigned int skew_offset;
+};
+
+struct gx_formatter_ops {
+ struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
+ void (*enable)(struct regmap *map);
+ void (*disable)(struct regmap *map);
+ int (*prepare)(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts);
+};
+
+struct gx_formatter_driver {
+ const struct snd_soc_component_driver *component_drv;
+ const struct regmap_config *regmap_cfg;
+ const struct gx_formatter_ops *ops;
+ const struct gx_formatter_hw *quirks;
+};
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event);
+int gx_formatter_probe(struct platform_device *pdev);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap);
+
+/*
+ * Formatter data is already freed when the associated device is removed,
+ * so we just need to remove the pointer from the widget.
+ */
+static inline void gx_formatter_free(struct snd_soc_dapm_widget *w)
+{
+ w->priv = NULL;
+}
+
+#endif /* _MESON_GX_FORMATTER_H */
diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h
new file mode 100644
index 000000000000..65c46dcce32a
--- /dev/null
+++ b/sound/soc/meson/gx-interface.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_INTERFACE_H
+#define _MESON_GX_INTERFACE_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+struct gx_iface {
+ struct clk *mclk;
+ unsigned long mclk_rate;
+
+ /* format is common to all the DAIs of the iface */
+ unsigned int fmt;
+
+ /* For component wide symmetry */
+ int rate;
+
+ /* Only for GX platform */
+ int bs_quirk;
+};
+
+struct gx_stream {
+ struct gx_iface *iface;
+ struct list_head formatter_list;
+ struct mutex lock;
+ unsigned int channels;
+ unsigned int width;
+ unsigned int physical_width;
+ bool ready;
+
+ /* For continuous clock tracking */
+ bool clk_enabled;
+};
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface);
+void gx_stream_free(struct gx_stream *ts);
+int gx_stream_start(struct gx_stream *ts);
+void gx_stream_stop(struct gx_stream *ts);
+
+#endif /* _MESON_GX_INTERFACE_H */
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index da1a93946d67..f0b55aee5241 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -265,10 +265,8 @@ static int t9015_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n");
ret = device_reset(dev);
- if (ret) {
- dev_err(dev, "reset failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) {
diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c
index ae86014c3819..6be6587e1095 100644
--- a/sound/soc/renesas/fsi.c
+++ b/sound/soc/renesas/fsi.c
@@ -1992,7 +1992,7 @@ static int fsi_probe(struct platform_device *pdev)
const struct fsi_core *core;
struct fsi_priv *fsi;
struct resource *res;
- unsigned int irq;
+ int irq;
int ret;
memset(&info, 0, sizeof(info));
@@ -2007,12 +2007,15 @@ static int fsi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
+ if (!res) {
dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
return -ENODEV;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
if (!master)
return -ENOMEM;
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 48ccc1d1854b..6db91b73f25c 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -658,6 +658,7 @@ static int aries_audio_probe(struct platform_device *pdev)
goto out;
}
+ of_node_get(aries_dai[0].cpus->of_node);
aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node;
/* Set CPU of_node for BT DAI */
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index f80f697a5d55..f80e8d498156 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -8,6 +8,7 @@
#include <dt-bindings/sound/samsung-i2s.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
@@ -512,7 +513,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
u32 mod, mask, val = 0;
int ret = 0;
- pm_runtime_get_sync(dai->dev);
+ guard(pm_runtime_active)(dai->dev);
scoped_guard(spinlock_irqsave, &priv->lock)
mod = readl(priv->addr + I2SMOD);
@@ -537,8 +538,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
&& (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
}
if (dir == SND_SOC_CLOCK_IN)
@@ -566,7 +566,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
} else {
priv->rclk_srcrate =
clk_get_rate(priv->op_clk);
- goto done;
+ return 0;
}
}
@@ -580,14 +580,14 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
if (WARN_ON(IS_ERR(priv->op_clk))) {
ret = PTR_ERR(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
ret = clk_prepare_enable(priv->op_clk);
if (ret) {
clk_put(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
priv->rclk_srcrate = clk_get_rate(priv->op_clk);
@@ -595,11 +595,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
|| (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
} else {
/* Call can't be on the active DAI */
- goto done;
+ return 0;
}
if (clk_id == 1)
@@ -607,8 +606,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
scoped_guard(spinlock_irqsave, &priv->lock) {
@@ -616,13 +614,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
mod = (mod & ~mask) | val;
writel(mod, priv->addr + I2SMOD);
}
-done:
- pm_runtime_put(dai->dev);
return 0;
-err:
- pm_runtime_put(dai->dev);
- return ret;
}
static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 7fc46d55c522..53eaabaf8956 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -380,8 +380,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
if (IS_ERR(spdif->pclk)) {
- dev_err(&pdev->dev, "failed to get peri-clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->pclk),
+ "failed to get peri-clock\n");
goto err0;
}
ret = clk_prepare_enable(spdif->pclk);
@@ -390,8 +390,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
if (IS_ERR(spdif->sclk)) {
- dev_err(&pdev->dev, "failed to get internal source clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->sclk),
+ "failed to get internal source clock\n");
goto err1;
}
ret = clk_prepare_enable(spdif->sclk);
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
index e0e32a279787..129a437ae397 100644
--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -99,11 +99,9 @@ static const struct snd_soc_dai_link bridge_dai_template = {
SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai),
};
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs)
{
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
-
if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
(*num_dais)++;
(*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index d8db8fc5313e..dd2cc57059d6 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -1976,14 +1976,13 @@ put_device:
return ret;
}
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
int *num_devs)
{
- struct device *dev = card->dev;
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
const struct snd_soc_acpi_link_adr *adr_link;
@@ -2045,7 +2044,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
if (codec_info->count_sidecar && codec_info->add_sidecar) {
- ret = codec_info->count_sidecar(card, &num_dais, num_devs);
+ ret = codec_info->count_sidecar(ctx, &num_dais, num_devs);
if (ret)
return ret;
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 95ad5266b0c6..8ac7dde32f77 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1127,6 +1127,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
src->available_fmt.num_input_formats,
src->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
@@ -1179,6 +1180,7 @@ static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
asrc->available_fmt.num_input_formats,
asrc->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 42a2d90bb705..6de8a6c1c127 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1102,7 +1102,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
full = NULL;
partial = NULL;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (rtd->dai_link->stream_name) {
if (!strcmp(rtd->dai_link->stream_name, w->sname)) {
@@ -1167,7 +1167,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
else
return;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
!strstr(rtd->dai_link->stream_name, sname))
@@ -1943,8 +1943,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
private->array, le32_to_cpu(private->size));
if (ret < 0) {
dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n");
- kfree(slink);
- return ret;
+ goto free_slink;
}
token_list = tplg_ops ? tplg_ops->token_list : NULL;
@@ -2013,8 +2012,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
/* allocate memory for tuples array */
slink->tuples = kzalloc_objs(*slink->tuples, num_tuples);
if (!slink->tuples) {
- kfree(slink);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_slink;
}
if (token_list[SOF_DAI_LINK_TOKENS].tokens) {
@@ -2070,6 +2069,7 @@ out:
err:
kfree(slink->tuples);
+free_slink:
kfree(slink);
return ret;
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
index c214ae0d7b95..312298e0b004 100644
--- a/sound/soc/ti/j721e-evm.c
+++ b/sound/soc/ti/j721e-evm.c
@@ -4,6 +4,7 @@
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -263,7 +264,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
int ret = 0;
int i;
- guard(mutex)(&priv->mutex);
+ mutex_lock(&priv->mutex);
domain->active++;
@@ -303,6 +304,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
out:
if (ret)
domain->active--;
+ mutex_unlock(&priv->mutex);
return ret;
}