sound updates for 7.2-rc1

Unsurprisingly, we've had a fairly busy development cycle with
 various fixes and enhancements.  While the majority of changes consist
 of device-specific fixes, a significant number of cleanups, hardening,
 and modernizations have been applied to the core frameworks as well.
 
 Below are some highlights:
 
 * ALSA Core:
 - Hardening, race condition, and UAF/leak fixes in the ALSA timer and
   sequencer cores
 - Widespread adoption of flexible array members across core structures
 - Integration of new simple refcount helper functions to simplify code
 
 * ASoC Core:
 - Introduction of a unified SoundWire enumeration helper to clean up
   redundant device initialization across codecs
 - Enhancements to SDCA support, including handling devices with
   multiple functions of the same type and proper jack reporting masks
 - Continued refactoring of ASoC component debugfs and DAPM structures
 - Simplification and improvements to the format auto-selection
   mechanism
 - Added shared BCLK rate constraints for cross-DAI coordination
 
 * ASoC Platforms & Codecs:
 - Initial bring-up and power management support for AMD ACP 7.x
 - Support for Everest Semi ES9356 (SDCA), Mediatek MT2701 (on-chip
   HDMI) and MT8196 SoCs, Renesas RZ/G3E, SpacemiT K3, and TI
   TAC5xx2/TAS67524
 - Added a new generic driver for GPIO-driven amplifiers
 - Continued mass conversion of locking code to guard() helpers across
   numerous platform drivers (MediaTek, Rockchip, STM32, Samsung, etc.)
 - Cleanup of legacy non-DT platform data and rollbacks for obsolete SH
   Ecovec24/7724se boards
 
 * HD- and USB-Audio:
 - Device-specific hardware quirks and fixes for various Realtek
   HD-Audio devices (Lenovo, HP, ASUS, Acer, Clevo)
 - Refinements to Qualcomm USB-audio offloading support
 - Front-panel controls and autogain status support for Scarlett Gen 4
 - Quirks for XIBERIA (K03S), Sennheiser (MOMENTUM 3), Edifier (MF200),
   Novation (Mininova), and Behringer (Flow 8) USB-audio devices
 - Improved robustness by rolling back or propagating write errors to the
   mixer control caches (Babyface Pro, US-16x08, Scarlett)
 
 * Others:
 - Support for the HT-Omega eClaro PCI sound card in the Oxygen driver
 - Robustness improvements and fixes for Virtio-audio, Xen-front, and
   legacy OSS dmasound drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmoxPGIOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE+wOA/+IVmz8RuySkrOpVkKepK4lVCbG3oZM1twTFkh
 YNhOOGWAjueCTfhuiTHadrg0eP4hKsO2Padu2OEFp6aZLH8zJI7UCinoRuvQ8yep
 gmQs0rsMsLkYd8JCDJjC+6kltvhigbKkrWza8FgBHu1fxJ0PQuhwKhUW/vrP4OsM
 7HrGP2lmaWHetRh8v9NxzhJWrUgqXtpklmUZJQvnIHe5ER752I6fO3QaKjLMJ+O1
 EBIjpA1kP8kw0z8yvW3RAmfAyrGB5J4AnLDZ5AmPf61v+xPgy3FsqbbWRC0CDCZB
 5KC2/AToDNOXPUbUqVKEv6lj6c6dhxf6+1zqcCYokMA1bsiCsnU2jtYsX9DOZjWw
 qs+MDLkcYRlol2UZrOCRkJZkfqqaKsIqUE3P+MaTJdgTspMrl9Bd0M3TzGLe6Kxi
 4HpA3+z1yNSWvUEwDTpXjKIg1Qni7NsfNLZHzYDCd2UW/sAV5pD0phEXRveVerTL
 qxeL3Fwmil2ApeTEwdXqdXiaDs9DV2wQU1hPfukOXiUYSXAYhSA+D4NIWmWPs4nU
 WsgcMo/Tq8GdapE2KxulOS4KuMddhxCZAg2UQAERPVAz61UlkbXJ15P7A8xKEm3h
 PhPOlKzH9tzsDjG2zPwnkxLLNvHfbBJjbpy6tvi45qhKWptG4nuiYcxfhnGogi63
 367P/Wg=
 =wMnQ
 -----END PGP SIGNATURE-----

Merge tag 'sound-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "Unsurprisingly, we've had a fairly busy development cycle with various
  fixes and enhancements. While the majority of changes consist of
  device-specific fixes, a significant number of cleanups, hardening,
  and modernizations have been applied to the core frameworks as well.

  Below are some highlights:

  ALSA Core:
   - Hardening, race condition, and UAF/leak fixes in the ALSA timer and
     sequencer cores
   - Widespread adoption of flexible array members across core
     structures
   - Integration of new simple refcount helper functions to simplify
     code

  ASoC Core:
   - Introduction of a unified SoundWire enumeration helper to clean up
     redundant device initialization across codecs
   - Enhancements to SDCA support, including handling devices with
     multiple functions of the same type and proper jack reporting masks
   - Continued refactoring of ASoC component debugfs and DAPM structures
   - Simplification and improvements to the format auto-selection
     mechanism
   - Added shared BCLK rate constraints for cross-DAI coordination

  ASoC Platforms & Codecs:
   - Initial bring-up and power management support for AMD ACP 7.x
   - Support for Everest Semi ES9356 (SDCA), Mediatek MT2701 (on-chip
     HDMI) and MT8196 SoCs, Renesas RZ/G3E, SpacemiT K3, and TI
     TAC5xx2/TAS67524
   - Added a new generic driver for GPIO-driven amplifiers
   - Continued mass conversion of locking code to guard() helpers across
     numerous platform drivers (MediaTek, Rockchip, STM32, Samsung, etc)
   - Cleanup of legacy non-DT platform data and rollbacks for obsolete
     SH Ecovec24/7724se boards

  HD- and USB-Audio:
   - Device-specific hardware quirks and fixes for various Realtek
     HD-Audio devices (Lenovo, HP, ASUS, Acer, Clevo)
   - Refinements to Qualcomm USB-audio offloading support
   - Front-panel controls and autogain status support for Scarlett Gen 4
   - Quirks for XIBERIA (K03S), Sennheiser (MOMENTUM 3), Edifier
     (MF200), Novation (Mininova), and Behringer (Flow 8) USB-audio
     devices
   - Improved robustness by rolling back or propagating write errors to
     the mixer control caches (Babyface Pro, US-16x08, Scarlett)

  Others:
   - Support for the HT-Omega eClaro PCI sound card in the Oxygen driver
   - Robustness improvements and fixes for Virtio-audio, Xen-front, and
     legacy OSS dmasound drivers"

* tag 'sound-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (483 commits)
  ALSA: usb-audio: Add iface reset and delay quirk for XIBERIA K03S
  ALSA: hda/realtek: Add quirk for Lenovo Xiaoxin 14 GT
  ALSA: hda/realtek: Add CS35L41 I2C quirk for ASUS UM3405GA
  ALSA: timer: Fix racy timeri->timer changes with rwlock
  ALSA: core: Fix unintuitive behavior of snd_power_ref_and_wait()
  ALSA: seq: avoid stale FIFO cells during resize
  ALSA: seq: oss: Serialize readq reset state with q->lock
  ASoC: dt-bindings: Fix RT5677 "realtek,gpio-config" type
  ASoC: audio-graph-card2: recommend to use auto select DAI format
  ASoC: update auto format selection method
  ASoC: renesas: rcar: update auto select format
  ASoC: codecs: pcm3168a: update auto select format
  ASoC: codecs: ak4619: update auto select format
  ASoC: codecs: peb2466: don't use array if single pattern
  ASoC: codecs: idt821034: don't use array if single pattern
  ASoC: codecs: framer-codec: don't use array if single pattern
  ASoC: remove SND_SOC_POSSIBLE_xBx_xFx
  ASoC: adau1372: Clear PLL_EN on failed PLL lock without reset GPIO
  ALSA: seq: Don't re-bounce the error event
  ASoC: bcm: cygnus: use scoped child node loop
  ...
This commit is contained in:
Linus Torvalds 2026-06-17 11:18:45 +01:00
commit 056e065a6b
694 changed files with 44951 additions and 5641 deletions

View File

@ -1,18 +0,0 @@
Bindings for I2S controller built into xtfpga Xtensa bitstreams.
Required properties:
- compatible: shall be "cdns,xtfpga-i2s".
- reg: memory region (address and length) with device registers.
- interrupts: interrupt for the device.
- clocks: phandle to the clk used as master clock. I2S bus clock
is derived from it.
Examples:
i2s0: xtfpga-i2s@d080000 {
#sound-dai-cells = <0>;
compatible = "cdns,xtfpga-i2s";
reg = <0x0d080000 0x40>;
interrupts = <2 1>;
clocks = <&cdce706 4>;
};

View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/cdns,xtfpga-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: I2S controller built into xtfpga Xtensa bitstreams
maintainers:
- Max Filippov <jcmvbkbc@gmail.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: cdns,xtfpga-i2s
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
description: phandle to the clk used as master clock. I2S bus clock is derived from it.
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
i2s@d080000 {
compatible = "cdns,xtfpga-i2s";
reg = <0x0d080000 0x40>;
interrupts = <2 1>;
clocks = <&cdce706 4>;
#sound-dai-cells = <0>;
};

View File

@ -11,6 +11,7 @@ maintainers:
allOf:
- $ref: dai-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
@ -21,6 +22,9 @@ properties:
reg:
maxItems: 1
spi-max-frequency:
maximum: 6000000
clocks:
minItems: 1
maxItems: 2
@ -86,3 +90,22 @@ examples:
reset-gpios = <&gpio 1>;
};
};
spi {
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio 8 0>;
codec@0 {
compatible = "cirrus,cs42888";
reg = <0>;
spi-max-frequency = <6000000>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&gpio 1>;
};
};

View File

@ -27,6 +27,10 @@ properties:
items:
- const: mclk
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
"#sound-dai-cells":
const: 0

View File

@ -98,6 +98,10 @@ properties:
- rpmsg-audio-channel
- rpmsg-micfil-channel
hp-det-gpios:
maxItems: 1
description: The GPIO that detect headphones are plugged in
required:
- compatible

View File

@ -162,6 +162,13 @@ properties:
of transmitter.
type: boolean
fsl,sai-bit-clock-swap:
description:
Enable Bit Clock Swap, which swaps the bit clock used by the transmitter
or receiver in asynchronous mode, i.e. makes transmitter use RX_BCLK and
TX_SYNC, and vice versa, makes receiver use TX_BCLK and RX_SYNC.
type: boolean
fsl,shared-interrupt:
description: Interrupt is shared with other modules.
type: boolean

View File

@ -0,0 +1,270 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/gpio-audio-amp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Audio amplifier driven by GPIOs
maintainers:
- Herve Codina <herve.codina@bootlin.com>
description: |
Audio GPIO amplifiers are driven by GPIO in order to control the gain value
of the amplifier, its mute function and/or its bypass function.
Those amplifiers are based on discrete components (analog switches, op-amps
and more) where some of them, mostly analog switches, are controlled by GPIOs
to adjust the gain value of the whole amplifier and/or to control
the mute and/or bypass function.
For instance, the following piece of hardware is a GPIO amplifier
+5VA
^
|\ |
| \
Vin >---------------------------|+ \
| +-------+-----> Vout
.--\/\/\/--+------------|- / |
| | | / |
v | |/ | |
GND o v |
\ GND |
gpio >-----------> \ |
o o |
| | |
| '--\/\/\/--. |
| +--\/\/\/--'
'---------------'
properties:
compatible:
oneOf:
- const: gpio-audio-amp-mono
description:
A single channel amplifier. All features apply to this sole channel.
- const: gpio-audio-amp-stereo
description:
A dual channel amplifier (left and right). All features apply to both
channels producing the same effect on both channels at the same time.
vdd-supply:
description: Main power supply of the amplifier
vddio-supply:
description: Power supply related to the control path
vdda1-supply:
description: Analog power supply
vdda2-supply:
description: Additional analog power supply
mute-gpios:
description: GPIO to control the mute function
maxItems: 1
bypass-gpios:
description: GPIO to control the bypass function
maxItems: 1
gain-gpios:
description: |
GPIOs to control the amplifier gain
The gain value is computed from GPIOs value from 0 to 2^N-1 with N the
number of GPIO described. The first GPIO described is the lsb of the gain
value.
For instance assuming 2 gpios
gain-gpios = <&gpio1 GPIO_ACTIVE_HIGH> <&gpio2 GPIO_ACTIVE_HIGH>;
The gain value will be the following:
gpio1 | gpio2 | gain
------+-------+-----
0 | 0 | 0b00 -> 0
1 | 0 | 0b01 -> 1
0 | 1 | 0b10 -> 2
1 | 1 | 0b11 -> 3
------+-------+-----
Note: The gain value, bits set to 1 or 0, indicate the state active (bit
set) or the state inactive (bit unset) of the related GPIO. The
physical voltage corresponding to this active/inactive state is
given by the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags.
minItems: 1
maxItems: 16
gain-ranges:
$ref: /schemas/types.yaml#/definitions/int32-matrix
description: |
A list of one or more ranges of possible values. Each range is defined by
the first and last point in the range. Each point is defined by the pair
(GPIOs value, Gain in 0.01 dB unit).
Ranges can be contiguous or holes can be present between ranges if some
gpios value should not be used. Also in a range the first point and the
last point can be identical. In that case, the range contains only one
item, the given point.
items:
items:
- description: GPIOs value of the first point in the range
- description: Gain in 0.01 dB unit of the first point in the range
- description: GPIOs value of the last point in the range
- description: Gain in 0.01 dB unit of the last point in the range
description: |
A range defines a linear function (linear in dB) from the first point
to the last point, both included. The number of items in the range is
N = abs(first_point.gpio_value - last_point.gpio_value) + 1
It allows to define the gain range from the first_point.gain to
the last_point.gain, both points included.
Gain (0.01 dB unit)
^
| last
+- - - - - - - - - - + point
| + .
| + .
| + .
+- - - - + .
| first . .
| point . .
| . .
+--------+-----------+---> gpios
value
Note: Even if first_point.gpio_value is lower than last_point.gpio_value
and first_point.gain is lower than last_point.gain in the above
graphic, all combination of values are supported leading to an
increasing or a decreasing linear segment.
minItems: 1
maxItems: 65536
gain-labels:
$ref: /schemas/types.yaml#/definitions/string-array
minItems: 2
maxItems: 65536
description: |
List of the gain labels attached to the combination of GPIOs controlling
the gain. The first label is related to the gain value 0, the second label
is related to the gain value 1 and so on.
With 2 GPIOs controlling the gain, GPIOs value can be 0, 1, 2 and 3.
Assuming that gain value set the hardware according to the following
table:
GPIOs | Hardware
value | amplification
------+--------------
0 | Low
1 | Middle
2 | High
3 | Max
------+--------------
The description using gain labels can be:
gain-labels = "Low", "Middle", "High", "Max";
dependencies:
gain-ranges: [ gain-gpios ]
gain-labels: [ gain-gpios ]
required:
- compatible
- vdd-supply
anyOf:
- required:
- gain-gpios
- required:
- mute-gpios
- required:
- bypass-gpios
allOf:
- $ref: component-common.yaml#
- if:
required:
- gain-ranges
then:
properties:
gain-labels: false
- if:
required:
- gain-labels
then:
properties:
gain-ranges: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
/* Gain controlled by gpios */
amplifier-0 {
compatible = "gpio-audio-amp-mono";
vdd-supply = <&regulator>;
gain-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>, <&gpio 1 GPIO_ACTIVE_HIGH>;
};
/* Gain controlled by gpio using a simple range on a stereo amplifier */
amplifier-1 {
compatible = "gpio-audio-amp-stereo";
vdd-supply = <&regulator>;
gain-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>, <&gpio 1 GPIO_ACTIVE_HIGH>;
gain-ranges = <0 (-300) 3 600>;
};
/* Gain controlled by gpio with labels */
amplifier-3 {
compatible = "gpio-audio-amp-mono";
vdd-supply = <&regulator>;
gain-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
gain-labels = "Low", "High";
};
/* A mutable stereo amplifier without any gain control */
amplifier-4 {
compatible = "gpio-audio-amp-stereo";
vdd-supply = <&regulator>;
mute-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
};
/*
* Several supplies, gain controlled using more complex ranges, mute and
* bypass.
*
* Assuming 3 gpios for controlling the gain with the following table
* gpios value Gain
* 0b000 Do not use (gpios value not allowed)
* 0b001 - 3dB
* 0b010 + 3dB
* 0b011 + 10dB
* 0b100 Do not use (gpios value not allowed)
* 0b101 + 6dB
* 0b110 + 7dB
* 0b111 + 8dB
*/
amplifier-5 {
compatible = "gpio-audio-amp-mono";
vdd-supply = <&regulator>;
vddio-supply = <&regulator1>;
vdda1-supply = <&regulator2>;
gain-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>,
<&gpio 1 GPIO_ACTIVE_HIGH>,
<&gpio 2 GPIO_ACTIVE_HIGH>;
gain-ranges = <1 (-300) 2 300>,
<3 1000 3 1000>,
<5 600 7 800>;
mute-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
bypass-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>;
};
...

View File

@ -37,7 +37,13 @@ patternProperties:
items:
enum:
- i2s
- left_j
- right_j
- dsp_a
- dsp_b
- pdm
- msb
- lsb
dai-tdm-slot-num: true

View File

@ -32,6 +32,7 @@ properties:
maxItems: 1
clocks:
minItems: 34
items:
- description: audio infra sys clock
- description: top audio mux 1
@ -67,8 +68,13 @@ properties:
- description: top audio a1 sys pd
- description: top audio a2 sys pd
- description: audio merge interface pd
- description: HADDS2 PLL 294 MHz (HDMI audio path root)
- description: HDMI audio interface pd
- description: S/PDIF interface pd
- description: audio APLL root pd
clock-names:
minItems: 34
items:
- const: infra_sys_audio_clk
- const: top_audio_mux1_sel
@ -104,6 +110,10 @@ properties:
- const: audio_a1sys_pd
- const: audio_a2sys_pd
- const: audio_mrgif_pd
- const: hadds2pll_294m
- const: audio_hdmi_pd
- const: audio_spdf_pd
- const: audio_apll_pd
required:
- compatible
@ -113,4 +123,17 @@ required:
- clocks
- clock-names
allOf:
- if:
properties:
compatible:
contains:
const: mediatek,mt7622-audio
then:
properties:
clocks:
maxItems: 34
clock-names:
maxItems: 34
additionalProperties: false

View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt2701-hdmi-audio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT2701/MT7623N HDMI audio output
maintainers:
- Daniel Golle <daniel@makrotopia.org>
description:
Sound card routing the MT2701/MT7623N Audio Front End HDMI
playback path to the on-chip HDMI transmitter. The AFE
provides the DMA memif and internal I2S engine; the HDMI
transmitter acts as the audio codec on the serialised link.
properties:
compatible:
oneOf:
- const: mediatek,mt2701-hdmi-audio
- items:
- const: mediatek,mt7623n-hdmi-audio
- const: mediatek,mt2701-hdmi-audio
mediatek,platform:
$ref: /schemas/types.yaml#/definitions/phandle
description: Phandle of the MT2701/MT7623N AFE platform node.
mediatek,audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: Phandle of the HDMI transmitter acting as audio codec.
required:
- compatible
- mediatek,platform
- mediatek,audio-codec
additionalProperties: false
examples:
- |
sound-hdmi {
compatible = "mediatek,mt7623n-hdmi-audio",
"mediatek,mt2701-hdmi-audio";
mediatek,platform = <&afe>;
mediatek,audio-codec = <&hdmi0>;
};

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt6351-sound.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT6351 Audio CODEC
maintainers:
- KaiChieh Chuang <kaichieh.chuang@mediatek.com>
description:
MT6351 Audio CODEC is a part of the MediaTek MT6351 PMIC.
It communicates with the SoC through the MediaTek PMIC wrapper(pwrap).
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: mediatek,mt6351-sound
"#sound-dai-cells":
const: 0
required:
- compatible
- "#sound-dai-cells"
unevaluatedProperties: false
examples:
- |
sound {
compatible = "mediatek,mt6351-sound";
#sound-dai-cells = <0>;
};

View File

@ -0,0 +1,113 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt8196-afe.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Audio Front End PCM controller for MT8196
maintainers:
- Darren Ye <darren.ye@mediatek.com>
properties:
compatible:
const: mediatek,mt8196-afe
reg:
maxItems: 1
interrupts:
maxItems: 1
memory-region:
maxItems: 1
power-domains:
maxItems: 1
clocks:
items:
- description: mux for audio intbus
- description: mux for audio engen1
- description: mux for audio engen2
- description: mux for audio h
- description: audio apll1 clock
- description: audio apll2 clock
- description: audio apll12 divide for i2sin0
- description: audio apll12 divide for i2sin1
- description: audio apll12 divide for fmi2s
- description: audio apll12 divide for tdmout mck
- description: audio apll12 divide for tdmout bck
- description: mux for adsp clock
clock-names:
items:
- const: top_aud_intbus
- const: top_aud_eng1
- const: top_aud_eng2
- const: top_aud_h
- const: apll1
- const: apll2
- const: apll12_div_i2sin0
- const: apll12_div_i2sin1
- const: apll12_div_fmi2s
- const: apll12_div_tdmout_m
- const: apll12_div_tdmout_b
- const: top_adsp
required:
- compatible
- reg
- interrupts
- memory-region
- power-domains
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
afe@1a110000 {
compatible = "mediatek,mt8196-afe";
reg = <0 0x1a110000 0 0x9000>;
interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH 0>;
memory-region = <&afe_dma_mem_reserved>;
power-domains = <&scpsys 14>; //MT8196_POWER_DOMAIN_AUDIO
pinctrl-names = "default";
pinctrl-0 = <&aud_pins_default>;
clocks = <&vlp_cksys_clk 40>, //CLK_VLP_CK_AUD_INTBUS_SEL
<&vlp_cksys_clk 38>, //CLK_VLP_CK_AUD_ENGEN1_SEL
<&vlp_cksys_clk 39>, //CLK_VLP_CK_AUD_ENGEN2_SEL
<&vlp_cksys_clk 37>, //CLK_VLP_CK_AUDIO_H_SEL
<&vlp_cksys_clk 0>, //CLK_VLP_CK_VLP_APLL1
<&vlp_cksys_clk 1>, //CLK_VLP_CK_VLP_APLL2
<&cksys_clk 80>, //CLK_CK_APLL12_CK_DIV_I2SIN0
<&cksys_clk 81>, //CLK_CK_APLL12_CK_DIV_I2SIN1
<&cksys_clk 92>, //CLK_CK_APLL12_CK_DIV_FMI2S
<&cksys_clk 93>, //CLK_CK_APLL12_CK_DIV_TDMOUT_M
<&cksys_clk 94>, //CLK_CK_APLL12_CK_DIV_TDMOUT_B
<&cksys_clk 45>; //CLK_CK_ADSP_SEL
clock-names = "top_aud_intbus",
"top_aud_eng1",
"top_aud_eng2",
"top_aud_h",
"apll1",
"apll2",
"apll12_div_i2sin0",
"apll12_div_i2sin1",
"apll12_div_fmi2s",
"apll12_div_tdmout_m",
"apll12_div_tdmout_b",
"top_adsp";
};
};
...

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt8196-nau8825.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT8196 ASoC sound card
maintainers:
- Darren Ye <darren.ye@mediatek.com>
allOf:
- $ref: sound-card-common.yaml#
properties:
compatible:
enum:
- mediatek,mt8196-nau8825-sound
- mediatek,mt8196-rt5682s-sound
- mediatek,mt8196-rt5650-sound
mediatek,platform:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of MT8188 ASoC platform.
patternProperties:
"^dai-link-[0-9]+$":
type: object
description:
Container for dai-link level properties and CODEC sub-nodes.
properties:
link-name:
description:
This property corresponds to the name of the BE dai-link to which
we are going to update parameters in this node.
items:
enum:
- TDM_DPTX_BE
- I2SOUT6_BE
- I2SIN6_BE
- I2SOUT4_BE
- I2SOUT3_BE
codec:
description: Holds subnode which indicates codec dai.
type: object
additionalProperties: false
properties:
sound-dai:
minItems: 1
maxItems: 2
required:
- sound-dai
dai-format:
description: audio format.
items:
enum:
- i2s
- right_j
- left_j
- dsp_a
- dsp_b
mediatek,clk-provider:
$ref: /schemas/types.yaml#/definitions/string
description: Indicates dai-link clock master.
enum:
- cpu
- codec
additionalProperties: false
required:
- link-name
required:
- compatible
- mediatek,platform
unevaluatedProperties: false
examples:
- |
sound {
compatible = "mediatek,mt8196-nau8825-sound";
model = "mt8196-nau8825";
mediatek,platform = <&afe>;
dai-link-0 {
link-name = "I2SOUT6_BE";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&nau8825>;
};
};
};
...

View File

@ -1,16 +0,0 @@
Mediatek MT6351 Audio Codec
The communication between MT6351 and SoC is through Mediatek PMIC wrapper.
For more detail, please visit Mediatek PMIC wrapper documentation.
Must be a child node of PMIC wrapper.
Required properties:
- compatible : "mediatek,mt6351-sound".
Example:
mt6351_snd {
compatible = "mediatek,mt6351-sound";
};

View File

@ -30,6 +30,20 @@ properties:
clock-names:
const: mclk
vdda-supply:
description: Analog power supply
vddb-supply:
description: Digital buffer (input/output) supply
vddc-supply:
description: Digital core supply
vddspk-supply:
description:
Speaker supply (power supply pin for RSPKOUT, LSPKOUT, AUXOUT2 and
AUXTOUT1 output drivers)
nuvoton,spk-btl:
description:
If set, configure the two loudspeaker outputs as a Bridge Tied Load output
@ -54,5 +68,9 @@ examples:
codec@1a {
compatible = "nuvoton,nau8822";
reg = <0x1a>;
vdda-supply = <&vcca_3v3_s0>;
vddb-supply = <&vcca_3v3_s0>;
vddc-supply = <&vcca_3v3_s0>;
vddspk-supply = <&vcca_3v3_s0>;
};
};

View File

@ -58,7 +58,7 @@ properties:
0 - floating (reset value)
1 - pull down
2 - pull up
$ref: /schemas/types.yaml#/definitions/uint32-array
$ref: /schemas/types.yaml#/definitions/uint8-array
minItems: 6
maxItems: 6
items:
@ -130,6 +130,6 @@ examples:
realtek,pow-ldo2-gpio = <&gpio 3 GPIO_ACTIVE_HIGH>;
realtek,reset-gpio = <&gpio 3 GPIO_ACTIVE_LOW>;
realtek,in1-differential;
realtek,gpio-config = <0 0 0 0 0 2>;
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>;
};
};

View File

@ -9,9 +9,6 @@ title: Renesas FIFO-buffered Serial Interface (FSI)
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
allOf:
- $ref: dai-common.yaml#
properties:
$nodename:
pattern: "^sound@.*"
@ -38,7 +35,32 @@ properties:
maxItems: 1
clocks:
maxItems: 1
minItems: 1
items:
- description: Main FSI module clock
- description: |
SPU bus/bridge clock. On R8A7740, this clock must be enabled to allow
register access as the FSI block is connected behind the SPU bus.
- description: CPG DIV6 functional clocks for FSI port A
- description: CPG DIV6 functional clocks for FSI port B
- description: FSI dividers for port A used for audio clock generation
- description: FSI dividers for port B used for audio clock generation
- description: External clock inputs for FSI port A provided by the board
- description: External clock inputs for FSI port B provided by the board
clock-names:
minItems: 1
maxItems: 8
items:
enum:
- fck # Main FSI module clock
- spu # optional SPU bus/bridge clock
- icka # optional CPG DIV6 functional clocks for FSI port A
- ickb # optional CPG DIV6 functional clocks for FSI port B
- diva # optional FSI dividers for port A used for audio clock generation
- divb # optional FSI dividers for port B used for audio clock generation
- xcka # optional External clock inputs for FSI port A provided by the board
- xckb # optional External clock inputs for FSI port B provided by the board
power-domains:
maxItems: 1
@ -69,6 +91,30 @@ required:
unevaluatedProperties: false
allOf:
- $ref: dai-common.yaml#
- if:
properties:
compatible:
contains:
const: renesas,fsi2-r8a7740
then:
required:
- clock-names
properties:
clock-names:
minItems: 2
items:
- const: fck
- const: spu
- enum: [icka, ickb, diva, divb, xcka, xckb]
- enum: [icka, ickb, diva, divb, xcka, xckb]
- enum: [icka, ickb, diva, divb, xcka, xckb]
- enum: [icka, ickb, diva, divb, xcka, xckb]
- enum: [icka, ickb, diva, divb, xcka, xckb]
- enum: [icka, ickb, diva, divb, xcka, xckb]
examples:
- |
#include <dt-bindings/clock/r8a7740-clock.h>
@ -77,7 +123,11 @@ examples:
compatible = "renesas,fsi2-r8a7740", "renesas,sh_fsi2";
reg = <0xfe1f0000 0x400>;
interrupts = <GIC_SPI 9 0x4>;
clocks = <&mstp3_clks R8A7740_CLK_FSI>;
clocks = <&mstp3_clks R8A7740_CLK_FSI>, <&spu_clk>,
<&fsia_clk>, <&fsiack_clk>, <&fsidiva_clk>,
<&fsib_clk>, <&fsibck_clk>, <&fsidivb_clk>;
clock-names = "fck", "spu", "icka", "xcka", "diva",
"ickb", "xckb", "divb";
power-domains = <&pd_a4mp>;
#sound-dai-cells = <1>;

View File

@ -0,0 +1,800 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/renesas,r9a09g047-sound.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/G3E Sound Controller
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- John Madieu <john.madieu.xa@bp.renesas.com>
description:
The RZ/G3E (R9A09G047) sound controller is based on R-Car Sound IP
with extended DMA channel support (up to 5 DMACs per direction),
additional clock domains (47 clocks including per-SSI ADG clocks),
and additional reset lines (14 including SCU, ADG and Audio DMAC
peri-peri resets). SSI operates exclusively in BUSIF mode with
2-4 BUSIF channels per SSI.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: renesas,r9a09g047-sound
reg:
maxItems: 5
reg-names:
items:
- const: scu
- const: adg
- const: ssiu
- const: ssi
- const: audmapp
"#sound-dai-cells":
const: 1
"#clock-cells":
const: 0
"#address-cells":
const: 1
"#size-cells":
const: 0
clocks:
maxItems: 47
clock-names:
items:
- const: ssi-all
- const: ssi-0
- const: ssi-1
- const: ssi-2
- const: ssi-3
- const: ssi-4
- const: ssi-5
- const: ssi-6
- const: ssi-7
- const: ssi-8
- const: ssi-9
- const: src-0
- const: src-1
- const: src-2
- const: src-3
- const: src-4
- const: src-5
- const: src-6
- const: src-7
- const: src-8
- const: src-9
- const: mix-0
- const: mix-1
- const: ctu-0
- const: ctu-1
- const: dvc-0
- const: dvc-1
- const: audio-clka
- const: audio-clkb
- const: audio-clkc
- const: audio-clki
- const: ssif_supply
- const: scu
- const: scu_x2
- const: scu_supply
- const: adg-ssi-0
- const: adg-ssi-1
- const: adg-ssi-2
- const: adg-ssi-3
- const: adg-ssi-4
- const: adg-ssi-5
- const: adg-ssi-6
- const: adg-ssi-7
- const: adg-ssi-8
- const: adg-ssi-9
- const: audmapp
- const: adg
power-domains:
maxItems: 1
resets:
maxItems: 14
reset-names:
items:
- const: ssi-all
- const: ssi-0
- const: ssi-1
- const: ssi-2
- const: ssi-3
- const: ssi-4
- const: ssi-5
- const: ssi-6
- const: ssi-7
- const: ssi-8
- const: ssi-9
- const: scu
- const: adg
- const: audmapp
dvc:
type: object
additionalProperties: false
patternProperties:
"^dvc-[0-1]$":
type: object
additionalProperties: false
properties:
dmas:
maxItems: 5
description:
List of references to DMA specifiers, one per DMA
controller, all for the transmission direction
(DVC is playback-only). The dma-engine core falls
through the list to find a free channel.
dma-names:
maxItems: 5
allOf:
- items:
enum:
- tx
required:
- dmas
- dma-names
mix:
type: object
additionalProperties: false
description:
Per-channel Mixer (MIX) sub-nodes. Each mix-N node has no
properties of its own. It exists so the driver can enumerate
the MIX instances and so that DT labels can be attached to it
for the dai/playback/capture phandle routing arrays.
patternProperties:
"^mix-[0-1]$":
type: object
additionalProperties: false
ctu:
type: object
additionalProperties: false
description:
Per-channel Channel Transfer Unit (CTU) sub-nodes. Each ctu-N
node has no properties of its own. It exists so the driver
can enumerate the CTU instances and so that DT labels can be
attached to it for the dai/playback/capture phandle routing arrays.
patternProperties:
"^ctu-[0-7]$":
type: object
additionalProperties: false
src:
type: object
additionalProperties: false
patternProperties:
"^src-[0-9]$":
type: object
additionalProperties: false
properties:
interrupts:
maxItems: 1
dmas:
maxItems: 10
description:
Must contain a list of pairs of references to DMA
specifiers, one for transmission and one for reception,
repeated for each DMA controller. The dma-engine core
falls through the list to find a free channel.
dma-names:
maxItems: 10
allOf:
- items:
enum:
- tx
- rx
ssiu:
type: object
additionalProperties: false
patternProperties:
"^ssiu-[0-9]+$":
type: object
additionalProperties: false
properties:
dmas:
maxItems: 10
description:
Must contain a list of pairs of references to DMA
specifiers, one for transmission and one for reception,
repeated for each DMA controller. The dma-engine core
falls through the list to find a free channel.
dma-names:
maxItems: 10
allOf:
- items:
enum:
- tx
- rx
required:
- dmas
- dma-names
ssi:
type: object
additionalProperties: false
patternProperties:
"^ssi-[0-9]$":
type: object
additionalProperties: false
properties:
interrupts:
maxItems: 1
shared-pin:
description: Shared clock pin.
$ref: /schemas/types.yaml#/definitions/flag
required:
- interrupts
ports:
$ref: audio-graph-port.yaml#/definitions/port-base
unevaluatedProperties: false
patternProperties:
'^port@[0-9a-f]+$':
$ref: audio-graph-port.yaml#/definitions/port-base
unevaluatedProperties: false
properties:
reg:
maxItems: 1
endpoint:
$ref: audio-graph-port.yaml#/definitions/endpoint-base
unevaluatedProperties: false
properties:
playback:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Ordered list of phandles to the in-SoC modules used
by this DAI in the playback direction. Each phandle
must reference one of the ssi-N, src-N, ctu-N,
mix-N or dvc-N sub-nodes of the parent sound
controller. The list order is the pipeline order
from CPU to off-SoC endpoint.
capture:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Ordered list of phandles to the in-SoC modules used
by this DAI in the capture direction. Each phandle
must reference one of the ssi-N, src-N, ctu-N,
mix-N or dvc-N sub-nodes of the parent sound
controller. The list order is the pipeline order
from off-SoC endpoint to CPU.
required:
- compatible
- reg
- reg-names
- "#sound-dai-cells"
- "#clock-cells"
- clocks
- clock-names
- resets
- reset-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
sound@13c00000 {
#sound-dai-cells = <1>;
#clock-cells = <0>;
compatible = "renesas,r9a09g047-sound";
reg = <0x13c00000 0x10000>,
<0x13c20000 0x10000>,
<0x13c30000 0x1000>,
<0x13c31000 0x1f000>,
<0x13c50000 0x10000>;
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
clocks = <&cpg 245>,
<&cpg 385>, <&cpg 386>,
<&cpg 387>, <&cpg 388>,
<&cpg 389>, <&cpg 390>,
<&cpg 391>, <&cpg 392>,
<&cpg 393>, <&cpg 394>,
<&cpg 372>, <&cpg 373>,
<&cpg 374>, <&cpg 375>,
<&cpg 376>, <&cpg 377>,
<&cpg 378>, <&cpg 379>,
<&cpg 380>, <&cpg 381>,
<&cpg 370>, <&cpg 371>,
<&cpg 370>, <&cpg 371>,
<&cpg 368>, <&cpg 369>,
<&cpg 251>, <&cpg 252>,
<&cpg 253>, <&cpg 250>,
<&cpg 384>,
<&cpg 246>, <&cpg 247>,
<&cpg 382>,
<&cpg 352>, <&cpg 353>,
<&cpg 354>, <&cpg 355>,
<&cpg 356>, <&cpg 357>,
<&cpg 358>, <&cpg 359>,
<&cpg 360>, <&cpg 361>,
<&cpg 248>, <&cpg 249>;
clock-names = "ssi-all",
"ssi-0", "ssi-1",
"ssi-2", "ssi-3",
"ssi-4", "ssi-5",
"ssi-6", "ssi-7",
"ssi-8", "ssi-9",
"src-0", "src-1",
"src-2", "src-3",
"src-4", "src-5",
"src-6", "src-7",
"src-8", "src-9",
"mix-0", "mix-1",
"ctu-0", "ctu-1",
"dvc-0", "dvc-1",
"audio-clka", "audio-clkb",
"audio-clkc", "audio-clki",
"ssif_supply",
"scu", "scu_x2",
"scu_supply",
"adg-ssi-0", "adg-ssi-1",
"adg-ssi-2", "adg-ssi-3",
"adg-ssi-4", "adg-ssi-5",
"adg-ssi-6", "adg-ssi-7",
"adg-ssi-8", "adg-ssi-9",
"audmapp", "adg";
power-domains = <&cpg>;
resets = <&cpg 225>,
<&cpg 226>, <&cpg 227>,
<&cpg 228>, <&cpg 229>,
<&cpg 230>, <&cpg 231>,
<&cpg 232>, <&cpg 233>,
<&cpg 234>, <&cpg 235>,
<&cpg 236>, <&cpg 238>, <&cpg 237>;
reset-names = "ssi-all",
"ssi-0", "ssi-1",
"ssi-2", "ssi-3",
"ssi-4", "ssi-5",
"ssi-6", "ssi-7",
"ssi-8", "ssi-9",
"scu", "adg",
"audmapp";
ctu {
ctu-0 { };
ctu-1 { };
ctu-2 { };
ctu-3 { };
ctu-4 { };
ctu-5 { };
ctu-6 { };
ctu-7 { };
};
dvc {
dvc0: dvc-0 {
dmas = <&dmac0 0x1db3>, <&dmac1 0x1db3>,
<&dmac2 0x1db3>, <&dmac3 0x1db3>,
<&dmac4 0x1db3>;
dma-names = "tx", "tx", "tx", "tx", "tx";
};
dvc1: dvc-1 {
dmas = <&dmac0 0x1db4>, <&dmac1 0x1db4>,
<&dmac2 0x1db4>, <&dmac3 0x1db4>,
<&dmac4 0x1db4>;
dma-names = "tx", "tx", "tx", "tx", "tx";
};
};
mix {
mix-0 { };
mix-1 { };
};
src {
src0: src-0 {
interrupts = <GIC_SPI 902 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1d9f>, <&dmac0 0x1da9>,
<&dmac1 0x1d9f>, <&dmac1 0x1da9>,
<&dmac2 0x1d9f>, <&dmac2 0x1da9>,
<&dmac3 0x1d9f>, <&dmac3 0x1da9>,
<&dmac4 0x1d9f>, <&dmac4 0x1da9>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src1: src-1 {
interrupts = <GIC_SPI 903 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da0>, <&dmac0 0x1daa>,
<&dmac1 0x1da0>, <&dmac1 0x1daa>,
<&dmac2 0x1da0>, <&dmac2 0x1daa>,
<&dmac3 0x1da0>, <&dmac3 0x1daa>,
<&dmac4 0x1da0>, <&dmac4 0x1daa>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-2 {
interrupts = <GIC_SPI 904 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da1>, <&dmac0 0x1dab>,
<&dmac1 0x1da1>, <&dmac1 0x1dab>,
<&dmac2 0x1da1>, <&dmac2 0x1dab>,
<&dmac3 0x1da1>, <&dmac3 0x1dab>,
<&dmac4 0x1da1>, <&dmac4 0x1dab>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-3 {
interrupts = <GIC_SPI 905 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da2>, <&dmac0 0x1dac>,
<&dmac1 0x1da2>, <&dmac1 0x1dac>,
<&dmac2 0x1da2>, <&dmac2 0x1dac>,
<&dmac3 0x1da2>, <&dmac3 0x1dac>,
<&dmac4 0x1da2>, <&dmac4 0x1dac>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-4 {
interrupts = <GIC_SPI 906 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da3>, <&dmac0 0x1dad>,
<&dmac1 0x1da3>, <&dmac1 0x1dad>,
<&dmac2 0x1da3>, <&dmac2 0x1dad>,
<&dmac3 0x1da3>, <&dmac3 0x1dad>,
<&dmac4 0x1da3>, <&dmac4 0x1dad>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-5 {
interrupts = <GIC_SPI 907 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da4>, <&dmac0 0x1dae>,
<&dmac1 0x1da4>, <&dmac1 0x1dae>,
<&dmac2 0x1da4>, <&dmac2 0x1dae>,
<&dmac3 0x1da4>, <&dmac3 0x1dae>,
<&dmac4 0x1da4>, <&dmac4 0x1dae>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-6 {
interrupts = <GIC_SPI 908 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da5>, <&dmac0 0x1daf>,
<&dmac1 0x1da5>, <&dmac1 0x1daf>,
<&dmac2 0x1da5>, <&dmac2 0x1daf>,
<&dmac3 0x1da5>, <&dmac3 0x1daf>,
<&dmac4 0x1da5>, <&dmac4 0x1daf>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-7 {
interrupts = <GIC_SPI 909 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da6>, <&dmac0 0x1db0>,
<&dmac1 0x1da6>, <&dmac1 0x1db0>,
<&dmac2 0x1da6>, <&dmac2 0x1db0>,
<&dmac3 0x1da6>, <&dmac3 0x1db0>,
<&dmac4 0x1da6>, <&dmac4 0x1db0>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-8 {
interrupts = <GIC_SPI 910 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da7>, <&dmac0 0x1db1>,
<&dmac1 0x1da7>, <&dmac1 0x1db1>,
<&dmac2 0x1da7>, <&dmac2 0x1db1>,
<&dmac3 0x1da7>, <&dmac3 0x1db1>,
<&dmac4 0x1da7>, <&dmac4 0x1db1>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
src-9 {
interrupts = <GIC_SPI 911 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dmac0 0x1da8>, <&dmac0 0x1db2>,
<&dmac1 0x1da8>, <&dmac1 0x1db2>,
<&dmac2 0x1da8>, <&dmac2 0x1db2>,
<&dmac3 0x1da8>, <&dmac3 0x1db2>,
<&dmac4 0x1da8>, <&dmac4 0x1db2>;
dma-names = "rx", "tx", "rx", "tx", "rx", "tx",
"rx", "tx", "rx", "tx";
};
};
ssi {
ssi-0 {
interrupts = <GIC_SPI 889 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-1 {
interrupts = <GIC_SPI 890 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-2 {
interrupts = <GIC_SPI 891 IRQ_TYPE_LEVEL_HIGH>;
};
ssi3: ssi-3 {
interrupts = <GIC_SPI 892 IRQ_TYPE_LEVEL_HIGH>;
};
ssi4: ssi-4 {
interrupts = <GIC_SPI 893 IRQ_TYPE_LEVEL_HIGH>;
shared-pin;
};
ssi-5 {
interrupts = <GIC_SPI 894 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-6 {
interrupts = <GIC_SPI 895 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-7 {
interrupts = <GIC_SPI 896 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-8 {
interrupts = <GIC_SPI 897 IRQ_TYPE_LEVEL_HIGH>;
};
ssi-9 {
interrupts = <GIC_SPI 898 IRQ_TYPE_LEVEL_HIGH>;
};
};
ssiu {
ssiu-0 {
dmas = <&dmac0 0x1d61>, <&dmac0 0x1d62>,
<&dmac1 0x1d61>, <&dmac1 0x1d62>,
<&dmac2 0x1d61>, <&dmac2 0x1d62>,
<&dmac3 0x1d61>, <&dmac3 0x1d62>,
<&dmac4 0x1d61>, <&dmac4 0x1d62>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-1 {
dmas = <&dmac0 0x1d63>, <&dmac0 0x1d64>,
<&dmac1 0x1d63>, <&dmac1 0x1d64>,
<&dmac2 0x1d63>, <&dmac2 0x1d64>,
<&dmac3 0x1d63>, <&dmac3 0x1d64>,
<&dmac4 0x1d63>, <&dmac4 0x1d64>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-2 {
dmas = <&dmac0 0x1d65>, <&dmac0 0x1d66>,
<&dmac1 0x1d65>, <&dmac1 0x1d66>,
<&dmac2 0x1d65>, <&dmac2 0x1d66>,
<&dmac3 0x1d65>, <&dmac3 0x1d66>,
<&dmac4 0x1d65>, <&dmac4 0x1d66>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-3 {
dmas = <&dmac0 0x1d67>, <&dmac0 0x1d68>,
<&dmac1 0x1d67>, <&dmac1 0x1d68>,
<&dmac2 0x1d67>, <&dmac2 0x1d68>,
<&dmac3 0x1d67>, <&dmac3 0x1d68>,
<&dmac4 0x1d67>, <&dmac4 0x1d68>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-4 {
dmas = <&dmac0 0x1d69>, <&dmac0 0x1d6a>,
<&dmac1 0x1d69>, <&dmac1 0x1d6a>,
<&dmac2 0x1d69>, <&dmac2 0x1d6a>,
<&dmac3 0x1d69>, <&dmac3 0x1d6a>,
<&dmac4 0x1d69>, <&dmac4 0x1d6a>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-5 {
dmas = <&dmac0 0x1d6b>, <&dmac0 0x1d6c>,
<&dmac1 0x1d6b>, <&dmac1 0x1d6c>,
<&dmac2 0x1d6b>, <&dmac2 0x1d6c>,
<&dmac3 0x1d6b>, <&dmac3 0x1d6c>,
<&dmac4 0x1d6b>, <&dmac4 0x1d6c>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-6 {
dmas = <&dmac0 0x1d6d>, <&dmac0 0x1d6e>,
<&dmac1 0x1d6d>, <&dmac1 0x1d6e>,
<&dmac2 0x1d6d>, <&dmac2 0x1d6e>,
<&dmac3 0x1d6d>, <&dmac3 0x1d6e>,
<&dmac4 0x1d6d>, <&dmac4 0x1d6e>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-7 {
dmas = <&dmac0 0x1d6f>, <&dmac0 0x1d70>,
<&dmac1 0x1d6f>, <&dmac1 0x1d70>,
<&dmac2 0x1d6f>, <&dmac2 0x1d70>,
<&dmac3 0x1d6f>, <&dmac3 0x1d70>,
<&dmac4 0x1d6f>, <&dmac4 0x1d70>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-8 {
dmas = <&dmac0 0x1d71>, <&dmac0 0x1d72>,
<&dmac1 0x1d71>, <&dmac1 0x1d72>,
<&dmac2 0x1d71>, <&dmac2 0x1d72>,
<&dmac3 0x1d71>, <&dmac3 0x1d72>,
<&dmac4 0x1d71>, <&dmac4 0x1d72>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-9 {
dmas = <&dmac0 0x1d73>, <&dmac0 0x1d74>,
<&dmac1 0x1d73>, <&dmac1 0x1d74>,
<&dmac2 0x1d73>, <&dmac2 0x1d74>,
<&dmac3 0x1d73>, <&dmac3 0x1d74>,
<&dmac4 0x1d73>, <&dmac4 0x1d74>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-10 {
dmas = <&dmac0 0x1d75>, <&dmac0 0x1d76>,
<&dmac1 0x1d75>, <&dmac1 0x1d76>,
<&dmac2 0x1d75>, <&dmac2 0x1d76>,
<&dmac3 0x1d75>, <&dmac3 0x1d76>,
<&dmac4 0x1d75>, <&dmac4 0x1d76>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-11 {
dmas = <&dmac0 0x1d77>, <&dmac0 0x1d78>,
<&dmac1 0x1d77>, <&dmac1 0x1d78>,
<&dmac2 0x1d77>, <&dmac2 0x1d78>,
<&dmac3 0x1d77>, <&dmac3 0x1d78>,
<&dmac4 0x1d77>, <&dmac4 0x1d78>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-12 {
dmas = <&dmac0 0x1d79>, <&dmac0 0x1d7a>,
<&dmac1 0x1d79>, <&dmac1 0x1d7a>,
<&dmac2 0x1d79>, <&dmac2 0x1d7a>,
<&dmac3 0x1d79>, <&dmac3 0x1d7a>,
<&dmac4 0x1d79>, <&dmac4 0x1d7a>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-13 {
dmas = <&dmac0 0x1d7b>, <&dmac0 0x1d7c>,
<&dmac1 0x1d7b>, <&dmac1 0x1d7c>,
<&dmac2 0x1d7b>, <&dmac2 0x1d7c>,
<&dmac3 0x1d7b>, <&dmac3 0x1d7c>,
<&dmac4 0x1d7b>, <&dmac4 0x1d7c>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-14 {
dmas = <&dmac0 0x1d7d>, <&dmac0 0x1d7e>,
<&dmac1 0x1d7d>, <&dmac1 0x1d7e>,
<&dmac2 0x1d7d>, <&dmac2 0x1d7e>,
<&dmac3 0x1d7d>, <&dmac3 0x1d7e>,
<&dmac4 0x1d7d>, <&dmac4 0x1d7e>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-15 {
dmas = <&dmac0 0x1d7f>, <&dmac0 0x1d80>,
<&dmac1 0x1d7f>, <&dmac1 0x1d80>,
<&dmac2 0x1d7f>, <&dmac2 0x1d80>,
<&dmac3 0x1d7f>, <&dmac3 0x1d80>,
<&dmac4 0x1d7f>, <&dmac4 0x1d80>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-16 {
dmas = <&dmac0 0x1d81>, <&dmac0 0x1d82>,
<&dmac1 0x1d81>, <&dmac1 0x1d82>,
<&dmac2 0x1d81>, <&dmac2 0x1d82>,
<&dmac3 0x1d81>, <&dmac3 0x1d82>,
<&dmac4 0x1d81>, <&dmac4 0x1d82>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-17 {
dmas = <&dmac0 0x1d83>, <&dmac0 0x1d84>,
<&dmac1 0x1d83>, <&dmac1 0x1d84>,
<&dmac2 0x1d83>, <&dmac2 0x1d84>,
<&dmac3 0x1d83>, <&dmac3 0x1d84>,
<&dmac4 0x1d83>, <&dmac4 0x1d84>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-18 {
dmas = <&dmac0 0x1d85>, <&dmac0 0x1d86>,
<&dmac1 0x1d85>, <&dmac1 0x1d86>,
<&dmac2 0x1d85>, <&dmac2 0x1d86>,
<&dmac3 0x1d85>, <&dmac3 0x1d86>,
<&dmac4 0x1d85>, <&dmac4 0x1d86>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-19 {
dmas = <&dmac0 0x1d87>, <&dmac0 0x1d88>,
<&dmac1 0x1d87>, <&dmac1 0x1d88>,
<&dmac2 0x1d87>, <&dmac2 0x1d88>,
<&dmac3 0x1d87>, <&dmac3 0x1d88>,
<&dmac4 0x1d87>, <&dmac4 0x1d88>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-20 {
dmas = <&dmac0 0x1d89>, <&dmac0 0x1d8a>,
<&dmac1 0x1d89>, <&dmac1 0x1d8a>,
<&dmac2 0x1d89>, <&dmac2 0x1d8a>,
<&dmac3 0x1d89>, <&dmac3 0x1d8a>,
<&dmac4 0x1d89>, <&dmac4 0x1d8a>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-21 {
dmas = <&dmac0 0x1d8b>, <&dmac0 0x1d8c>,
<&dmac1 0x1d8b>, <&dmac1 0x1d8c>,
<&dmac2 0x1d8b>, <&dmac2 0x1d8c>,
<&dmac3 0x1d8b>, <&dmac3 0x1d8c>,
<&dmac4 0x1d8b>, <&dmac4 0x1d8c>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-22 {
dmas = <&dmac0 0x1d8d>, <&dmac0 0x1d8e>,
<&dmac1 0x1d8d>, <&dmac1 0x1d8e>,
<&dmac2 0x1d8d>, <&dmac2 0x1d8e>,
<&dmac3 0x1d8d>, <&dmac3 0x1d8e>,
<&dmac4 0x1d8d>, <&dmac4 0x1d8e>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-23 {
dmas = <&dmac0 0x1d8f>, <&dmac0 0x1d90>,
<&dmac1 0x1d8f>, <&dmac1 0x1d90>,
<&dmac2 0x1d8f>, <&dmac2 0x1d90>,
<&dmac3 0x1d8f>, <&dmac3 0x1d90>,
<&dmac4 0x1d8f>, <&dmac4 0x1d90>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-24 {
dmas = <&dmac0 0x1d91>, <&dmac0 0x1d92>,
<&dmac1 0x1d91>, <&dmac1 0x1d92>,
<&dmac2 0x1d91>, <&dmac2 0x1d92>,
<&dmac3 0x1d91>, <&dmac3 0x1d92>,
<&dmac4 0x1d91>, <&dmac4 0x1d92>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-25 {
dmas = <&dmac0 0x1d93>, <&dmac0 0x1d94>,
<&dmac1 0x1d93>, <&dmac1 0x1d94>,
<&dmac2 0x1d93>, <&dmac2 0x1d94>,
<&dmac3 0x1d93>, <&dmac3 0x1d94>,
<&dmac4 0x1d93>, <&dmac4 0x1d94>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-26 {
dmas = <&dmac0 0x1d95>, <&dmac0 0x1d96>,
<&dmac1 0x1d95>, <&dmac1 0x1d96>,
<&dmac2 0x1d95>, <&dmac2 0x1d96>,
<&dmac3 0x1d95>, <&dmac3 0x1d96>,
<&dmac4 0x1d95>, <&dmac4 0x1d96>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
ssiu-27 {
dmas = <&dmac0 0x1d97>, <&dmac0 0x1d98>,
<&dmac1 0x1d97>, <&dmac1 0x1d98>,
<&dmac2 0x1d97>, <&dmac2 0x1d98>,
<&dmac3 0x1d97>, <&dmac3 0x1d98>,
<&dmac4 0x1d97>, <&dmac4 0x1d98>;
dma-names = "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx", "tx", "rx";
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
rsnd_endpoint0: endpoint {
remote-endpoint = <&codec_endpoint>;
dai-format = "i2s";
bitclock-master = <&rsnd_endpoint0>;
frame-master = <&rsnd_endpoint0>;
playback = <&ssi3>, <&src1>, <&dvc1>;
capture = <&ssi4>, <&src0>, <&dvc0>;
};
};
};
};

View File

@ -45,8 +45,8 @@ properties:
clocks:
items:
- description: clock for SPDIF bus
- description: clock for SPDIF controller
- description: clock for SPDIF bus
clock-names:
items:

View File

@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/sound/spacemit,k1-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: K1 I2S controller
title: SpacemiT K1/K3 I2S controller
description:
The I2S bus (Inter-IC sound bus) is a serial link for digital
@ -15,27 +15,54 @@ maintainers:
allOf:
- $ref: dai-common.yaml#
- if:
properties:
compatible:
contains:
const: spacemit,k3-i2s
then:
properties:
clocks:
minItems: 7
clock-names:
minItems: 7
else:
properties:
clocks:
maxItems: 4
clock-names:
maxItems: 4
properties:
compatible:
const: spacemit,k1-i2s
enum:
- spacemit,k1-i2s
- spacemit,k3-i2s
reg:
maxItems: 1
clocks:
minItems: 4
items:
- description: clock for I2S sysclk
- description: clock for I2S bclk
- description: clock for I2S bus
- description: clock for I2S controller
- description: clock for I2S sysclk divider
- description: clock for I2S common sysclk
- description: clock for I2S common bclk
clock-names:
minItems: 4
items:
- const: sysclk
- const: bclk
- const: bus
- const: func
- const: sysclk_div
- const: c_sysclk
- const: c_bclk
dmas:
minItems: 1

View File

@ -71,6 +71,9 @@ properties:
ti,tas2572: 6.6-W Digital Input smart amp with I/V sense and integrated
13-V Class-H Boost
ti,tas2573: Boosted Class-D Audio Amplifier with Integrated DSP and IV
Sense
ti,tas2574: 8.5-W Digital Input smart amp with I/V sense and integrated
15-V Class-H Boost
@ -121,6 +124,7 @@ properties:
- ti,tas2568
- ti,tas2570
- ti,tas2572
- ti,tas2573
- ti,tas2574
- ti,tas5802
- ti,tas5806m
@ -183,6 +187,7 @@ allOf:
contains:
enum:
- ti,tas2563
- ti,tas2573
- ti,tas5825
then:
properties:

View File

@ -0,0 +1,280 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tas67524.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TAS67524 Audio Amplifier
maintainers:
- Sen Wang <sen@ti.com>
description:
The TAS67524 is a four-channel, digital-input, automotive
Class-D audio amplifier with load diagnostics and an integrated
DSP for audio processing.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- ti,tas6754
- const: ti,tas67524
- const: ti,tas67524
reg:
maxItems: 1
'#sound-dai-cells':
const: 1
description: |
The device exposes three DAIs, selected by index.
0 - Standard Audio Path (Playback)
1 - Low-Latency Playback Path (Playback)
2 - Sensory Feedback (Capture - Vpredict and Isense)
By default, all four channels of each DAI are active.
interrupts:
maxItems: 1
description:
Active-low falling-edge interrupt from the FAULT pin. When provided,
the driver uses IRQ-driven fault reporting instead of polling.
powerdown-gpios:
maxItems: 1
description:
GPIO connected to the PD pin, active low. Controls the internal
digital circuitry power state. When asserted the device enters
full power-down mode and all register state is lost. Can be omitted if
PD pin is hardwired or externally controlled.
standby-gpios:
maxItems: 1
description:
GPIO connected to the STBY pin, active low. Controls the analog
power stage. When asserted the device enters Deep Sleep mode but
remains I2C-accessible with registers retained. Can be omitted if
STBY pin is tied to PD or hardwired.
dvdd-supply:
description:
Digital logic supply (1.62 V to 3.6 V). All three supply rails must
be within their recommended operating ranges before the PD pin is
released.
pvdd-supply:
description:
Output FET power supply (4.5 V to 19 V). All three supply rails must
be within their recommended operating ranges before the PD pin is
released.
vbat-supply:
description:
Battery supply for the Class-D output stage (4.5 V to 19 V). Optional
when PVDD and VBAT are connected to the same supply rail. When absent,
VBAT is assumed hardwired to PVDD.
ti,fast-boot:
type: boolean
description:
Skip DC load diagnostic sweep at power-on to reduce boot latency.
Automatic diagnostics after fault conditions remain enabled. Hardware
overcurrent protection is always active.
ti,audio-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description:
TDM slot offset for the standard audio playback path via SDIN1. A value
of 4 maps to slot 4. If omitted, slot assignment is derived from the
tx_mask provided via set_tdm_slot(). Without either property, no slot
mapping is configured.
ti,llp-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description:
TDM slot offset for the low-latency playback path via SDIN1. If omitted,
slot assignment is derived from the tx_mask provided via set_tdm_slot().
Without either property, no slot mapping is configured. Disabled outside
of LLP mode, and only relevant for TDM formats.
ti,vpredict-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
In TDM mode, enables Vpredict output and assigns its starting slot;
four consecutive slots carry Vpredict Ch1-4 on SDOUT1. May coexist
with ti,isense-slot-no using separate non-overlapping slots.
In I2S mode, enables Vpredict output on SDOUT1 (Ch1/Ch2) and SDOUT2
(Ch3/Ch4). The slot value is unused. Requires a GPIO configured as
sdout2 for Ch3/Ch4; without it only Ch1/Ch2 are output. Mutually
exclusive with ti,isense-slot-no; if both are set, Vpredict takes
priority.
Irrelevant in Left-J and Right-J modes.
ti,isense-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
In TDM mode, enables Isense output and assigns its starting slot;
four consecutive slots carry Isense Ch1-4 on SDOUT1. May coexist
with ti,vpredict-slot-no using separate non-overlapping slots.
In I2S mode, enables Isense output on SDOUT1 (Ch1/Ch2) and SDOUT2
(Ch3/Ch4). The slot value is unused. Requires a GPIO configured as
SDOUT2 for Ch3/Ch4; without it only Ch1/Ch2 are output. Mutually
exclusive with ti,vpredict-slot-no; Vpredict takes priority if both
are set.
Irrelevant in Left-J and Right-J modes.
ti,gpio1-function:
$ref: /schemas/types.yaml#/definitions/string
description:
Function for the GPIO_1 pin. When omitted, GPIO_1 remains in its
power-on default state.
enum:
- low # Output: driven low
- auto-mute # Output: high when all channels are auto-muted
- auto-mute-ch4 # Output: high when channel 4 is auto-muted
- auto-mute-ch3 # Output: high when channel 3 is auto-muted
- auto-mute-ch2 # Output: high when channel 2 is auto-muted
- auto-mute-ch1 # Output: high when channel 1 is auto-muted
- sdout2 # Output: Routes secondary serial data output 2
- sdout1 # Output: Re-routes secondary serial data output 1
- warn # Output: warning signal (OTW, CBC)
- fault # Output: fault signal (OTSD, OC, DC)
- clock-sync # Output: clock synchronisation
- invalid-clock # Output: high when clock is invalid
- high # Output: driven high
- mute # Input: external mute control
- phase-sync # Input: phase synchronisation
- sdin2 # Input: secondary SDIN2 for I2S/LJ/RJ ch3/ch4
- deep-sleep # Input: asserted transitions device to Deep Sleep
- hiz # Input: asserted transitions device to Hi-Z
- play # Input: asserted transitions device to Play
- sleep # Input: asserted transitions device to Sleep
ti,gpio2-function:
$ref: /schemas/types.yaml#/definitions/string
description:
Function for the GPIO_2 pin. When omitted, GPIO_2 remains in its
power-on default state.
enum:
- low # Output: driven low
- auto-mute # Output: high when all channels are auto-muted
- auto-mute-ch4 # Output: high when channel 4 is auto-muted
- auto-mute-ch3 # Output: high when channel 3 is auto-muted
- auto-mute-ch2 # Output: high when channel 2 is auto-muted
- auto-mute-ch1 # Output: high when channel 1 is auto-muted
- sdout2 # Output: Routes secondary serial data output 2
- sdout1 # Output: Re-routes secondary serial data output 1
- warn # Output: warning signal (OTW, CBC)
- fault # Output: fault signal (OTSD, OC, DC)
- clock-sync # Output: clock synchronisation
- invalid-clock # Output: high when clock is invalid
- high # Output: driven high
- mute # Input: external mute control
- phase-sync # Input: phase synchronisation
- sdin2 # Input: secondary SDIN2 for I2S/LJ/RJ ch3/ch4
- deep-sleep # Input: asserted transitions device to Deep Sleep
- hiz # Input: asserted transitions device to Hi-Z
- play # Input: asserted transitions device to Play
- sleep # Input: asserted transitions device to Sleep
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: Standard audio playback port (DAI 0).
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: Low-latency playback port (LLP) (DAI 1).
port@2:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: Sensory feedback capture port (DAI 2).
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
- '#sound-dai-cells'
- dvdd-supply
- pvdd-supply
anyOf:
- required: [powerdown-gpios]
- required: [standby-gpios]
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
amplifier@70 {
compatible = "ti,tas67524";
reg = <0x70>;
#sound-dai-cells = <1>;
sound-name-prefix = "TAS0";
standby-gpios = <&main_gpio0 33 GPIO_ACTIVE_LOW>;
dvdd-supply = <&dvdd_1v8>;
pvdd-supply = <&pvdd_12v>;
vbat-supply = <&vbat_12v>;
ti,audio-slot-no = <0>;
ti,llp-slot-no = <4>;
ti,vpredict-slot-no = <0>;
ti,isense-slot-no = <4>;
ti,gpio2-function = "warn";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
tas0_audio_ep: endpoint {
dai-format = "dsp_b";
remote-endpoint = <&be_tas0_audio_ep>;
};
};
port@1 {
reg = <1>;
tas0_anc_ep: endpoint {
remote-endpoint = <&be_tas0_anc_ep>;
};
};
port@2 {
reg = <2>;
tas0_fb_ep: endpoint {
remote-endpoint = <&be_tas0_fb_ep>;
};
};
};
};
};

View File

@ -1097,7 +1097,7 @@ output (with ``--no-upload`` option) to kernel bugzilla or alsa-devel
ML (see the section `Links and Addresses`_).
``power_save`` and ``power_save_controller`` options are for power-saving
mode. See powersave.rst for details.
mode. See Documentation/sound/designs/powersave.rst for details.
Note 2: If you get click noises on output, try the module option
``position_fix=1`` or ``2``. ``position_fix=1`` will use the SD_LPIB
@ -1168,7 +1168,7 @@ line_outs_monitor
enable_monitor
Enable Analog Out on Channel 63/64 by default.
See hdspm.rst for details.
See Documentation/sound/cards/hdspm.rst for details.
Module snd-ice1712
------------------
@ -2383,6 +2383,24 @@ quirk_flags
``V(x) = k * x``; ``dB(x) = 20 * log10(x)``. Overrides bit 24
* bit 28: ``mixer_capture_linear_vol``
Similar to bit 27 but for capture streams. Overrides bit 25
* bit 29: ``ifb_silence_on_empty``
In implicit feedback mode, when an entire capture URB returns with
all iso_frame_desc[i].status != 0 (bytes==0), do not silently return
from snd_usb_handle_sync_urb. Instead fall through and enqueue a
packet_info containing only size-0 packets, so the OUT ring keeps
moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
* bit 30: ``mixer_get_cur_broken``
Some mixers are sticky, which means that setting their current volume
is a no-op, and reading the current volume returns a constant value.
The sticky check disables these mixers to prevent confusing userspace.
However, some devices do have a tunable volume despite the reported
current volume being constant. As the sticky check can't distinguish
between the two categories, setting this flag tells that the device
should fall into the second category when GET_CUR returns a constant
value, resulting in the sticky check being non-fatal and only
disabling GET_CUR instead of the whole mixer. The current volume will
then be provided by the internal cache that stores the last set
volume
This module supports multiple devices, autoprobe and hotplugging.

View File

@ -7,3 +7,4 @@ Codec-Specific Information
:maxdepth: 2
cs35l56
tas675x

View File

@ -0,0 +1,820 @@
.. SPDX-License-Identifier: GPL-2.0
======================================
TAS675x Codec Mixer Controls
======================================
This document describes the ALSA mixer controls for the TAS675x
4-channel amplifier driver.
For device tree bindings, see:
Documentation/devicetree/bindings/sound/ti,tas67524.yaml
DSP Signal Path Mode
====================
DSP Signal Path Mode
--------------------
:Description: Signal processing mode selection.
:Type: Enumerated
:Default: Normal
:Options: Normal, LLP, FFLP
:Register: 0x32 bits [1:0]
Normal
Full DSP with all features available.
LLP (Low Latency Path)
Bypasses DSP processing. DSP protection features (Thermal Foldback,
PVDD Foldback, Clip Detect) and Real-Time Load Diagnostics unavailable.
FFLP (Full Feature Low Latency Path)
Reduced latency. Real-Time Load Diagnostics unavailable.
The following controls are unavailable in LLP mode:
``Thermal Foldback Switch``, ``PVDD Foldback Switch``,
``DC Blocker Bypass Switch``, ``Clip Detect Switch``, ``Audio SDOUT Switch``.
The following controls require Normal mode (unavailable in FFLP and LLP):
``CHx RTLDG Switch``, ``RTLDG Clip Mask Switch``, ``ISENSE Calibration Switch``,
``RTLDG Open Load Threshold``, ``RTLDG Short Load Threshold``,
``CHx RTLDG Impedance``.
Volume Controls
===============
Analog Playback Volume
----------------------
:Description: Analog output gain for all channels (CH1/CH2 and CH3/CH4 pairs).
:Type: Volume (TLV)
:Default: 0 dB
:Range: -15.5 dB to 0 dB (0.5 dB steps)
:Register: 0x4A (CH1/CH2), 0x4B (CH3/CH4)
Analog Gain Ramp Step
---------------------
:Description: Anti-pop ramp step duration for analog gain transitions.
:Type: Enumerated
:Default: 15us
:Options: 15us, 60us, 200us, 400us
:Register: 0x4E bits [3:2]
CHx Digital Playback Volume
---------------------------
:Description: Per-channel digital volume control (x = 1, 2, 3, 4).
:Type: Volume (TLV)
:Default: 0 dB
:Range: -103 dB to 0 dB (0.5 dB steps)
:Bounds: 0x30 (min/mute) to 0xFF (max)
:Register: 0x40 (CH1), 0x41 (CH2), 0x42 (CH3), 0x43 (CH4)
Volume Ramp Down Rate
---------------------
:Description: Update frequency during mute transition.
:Type: Enumerated
:Default: 16 FS
:Options: 4 FS, 16 FS, 32 FS, Instant
:Register: 0x44 bits [7:6]
Volume Ramp Down Step
---------------------
:Description: dB change per update during mute.
:Type: Enumerated
:Default: 0.5dB
:Options: 4dB, 2dB, 1dB, 0.5dB
:Register: 0x44 bits [5:4]
Volume Ramp Up Rate
-------------------
:Description: Update frequency during unmute transition.
:Type: Enumerated
:Default: 16 FS
:Options: 4 FS, 16 FS, 32 FS, Instant
:Register: 0x44 bits [3:2]
Volume Ramp Up Step
-------------------
:Description: dB change per update during unmute.
:Type: Enumerated
:Default: 0.5dB
:Options: 4dB, 2dB, 1dB, 0.5dB
:Register: 0x44 bits [1:0]
CH1/2 Volume Combine
--------------------
:Description: Links digital volume controls for CH1 and CH2.
:Type: Enumerated
:Default: Independent
:Options: Independent, CH2 follows CH1, CH1 follows CH2
:Register: 0x46 bits [1:0]
CH3/4 Volume Combine
--------------------
:Description: Links digital volume controls for CH3 and CH4.
:Type: Enumerated
:Default: Independent
:Options: Independent, CH4 follows CH3, CH3 follows CH4
:Register: 0x46 bits [3:2]
Auto Mute & Silence Detection
==============================
CHx Auto Mute Switch
--------------------
:Description: Enables automatic muting on zero-signal detection (x = 1, 2, 3, 4).
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x47 bit [0] (CH1), bit [1] (CH2), bit [2] (CH3), bit [3] (CH4)
Auto Mute Combine Switch
------------------------
:Description: Coordinated muting behaviour across all channels.
:Type: Boolean Switch
:Default: Disabled (0)
:Behavior: Disabled: channels mute independently when their signal is zero.
Enabled: all channels mute together only when all detect zero
signal; unmute when any channel has non-zero signal.
:Register: 0x47 bit [4]
CHx Auto Mute Time
------------------
:Description: Duration of zero signal before muting triggers (x = 1, 2, 3, 4).
:Type: Enumerated
:Default: 11.5ms
:Options: 11.5ms, 53ms, 106.5ms, 266.5ms, 535ms, 1065ms, 2665ms, 5330ms
:Register: 0x48 bits [7:4] (CH1), bits [3:0] (CH2),
0x49 bits [7:4] (CH3), bits [3:0] (CH4)
:Note: Values are at 96 kHz. At 48 kHz, times are doubled.
Clock & EMI Management
======================
Spread Spectrum Mode
--------------------
:Description: Frequency dithering mode to reduce peak EMI.
:Type: Enumerated
:Default: Disabled
:Options: Disabled, Triangle, Random, Triangle and Random
:Register: 0x61 bits [1:0]
SS Triangle Range
-----------------
:Description: Frequency deviation range for Triangle spread spectrum.
:Type: Enumerated
:Default: 6.5%
:Options: 6.5%, 13.5%, 5%, 10%
:Register: 0x62 bits [1:0]
:Note: Applies only when Spread Spectrum Mode includes Triangle.
SS Random Range
---------------
:Description: Frequency deviation range for Random spread spectrum.
:Type: Enumerated
:Default: 0.83%
:Options: 0.83%, 2.50%, 5.83%, 12.50%, 25.83%
:Register: 0x62 bits [6:4]
:Note: Applies only when Spread Spectrum Mode includes Random.
SS Random Dwell Range
---------------------
:Description: Dwell time range for Random spread spectrum (FSS = spread
spectrum modulation frequency).
:Type: Enumerated
:Default: 1/FSS to 2/FSS
:Options: 1/FSS to 2/FSS, 1/FSS to 4/FSS, 1/FSS to 8/FSS, 1/FSS to 15/FSS
:Register: 0x62 bits [3:2]
:Note: Applies only when Spread Spectrum Mode includes Random.
SS Triangle Dwell Min
---------------------
:Description: Minimum dwell time at Triangle spread spectrum frequency extremes.
:Type: Integer
:Default: 0
:Range: 0 to 15 (0 = feature disabled)
:Register: 0x66 bits [7:4]
:Note: Counts in FSS clock cycles. The modulator holds the extreme
frequency for at least this many FSS cycles before reversing.
When Dwell Min equals Dwell Max, the dwell feature is inactive.
For FSS values at each PWM frequency refer to the "Spread
Spectrum" section of the TRM.
SS Triangle Dwell Max
---------------------
:Description: Maximum dwell time at Triangle spread spectrum frequency extremes.
:Type: Integer
:Default: 0
:Range: 0 to 15 (0 = feature disabled)
:Register: 0x66 bits [3:0]
:Note: Counts in FSS clock cycles. Must be >= Dwell Min. When Dwell Max
equals Dwell Min, the dwell feature is inactive.
Hardware Protection
===================
OTSD Auto Recovery Switch
--------------------------
:Description: Enables automatic recovery from over-temperature shutdown.
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x8F bit [1]
:Note: When disabled, manual fault clearing is required after OTSD events.
Overcurrent Limit Level
-----------------------
:Description: Current-limit trip point sensitivity.
:Type: Enumerated
:Default: Level 4
:Options: Level 4, Level 3, Level 2, Level 1
:Register: 0x55 bits [1:0]
:Note: Level 4 is the least sensitive (highest trip current); Level 1 is
the most sensitive. The exact ILIM values depend on operating
conditions (PVDD voltage, switching frequency, and temperature).
Refer to the Electrical Characteristics table and the
"Overcurrent Limit (Cycle-By-Cycle)" section of the TRM.
CHx OTW Threshold
-----------------
:Description: Over-temperature warning threshold per channel (x = 1, 2, 3, 4).
:Type: Enumerated
:Default: >95C
:Options: Disabled, >95C, >110C, >125C, >135C, >145C, >155C, >165C
:Register: 0xE2 bits [6:4] (CH1), bits [2:0] (CH2),
0xE3 bits [6:4] (CH3), bits [2:0] (CH4)
Temperature and Voltage Monitoring
===================================
PVDD Sense
----------
:Description: Supply voltage sense register.
:Type: Integer (read-only)
:Range: 0 to 255
:Conversion: value × 0.19 V
:Register: 0x74
Global Temperature
------------------
:Description: Global die temperature sense register.
:Type: Integer (read-only)
:Range: 0 to 255
:Conversion: (value × 0.5 °C) 50 °C
:Register: 0x75
CHx Temperature Range
---------------------
:Description: Per-channel coarse temperature range indicator (x = 1, 2, 3, 4).
:Type: Integer (read-only)
:Range: 0 to 3
:Mapping: 0 = <80 °C, 1 = 80100 °C, 2 = 100120 °C, 3 = >120 °C
:Register: 0xBB bits [7:6] (CH1), bits [5:4] (CH2),
0xBC bits [3:2] (CH3), bits [1:0] (CH4)
Load Diagnostics
================
The TAS675x provides three load diagnostic modes:
DC Load Diagnostics (DC LDG)
Measures DC resistance to detect S2G (short-to-ground), S2P
(short-to-power), OL (open load), and SL (shorted load) faults.
AC Load Diagnostics (AC LDG)
Measures complex AC impedance at a configurable frequency. Detects
capacitive loads and tweeter configurations.
Real-Time Load Diagnostics (RTLDG)
Monitors impedance continuously during playback using a pilot tone.
Normal DSP mode only, at 48 kHz or 96 kHz.
Fast Boot Mode
--------------
By default the device runs DC load diagnostics at initialization before
accepting audio. Setting ``ti,fast-boot`` in the device tree bypasses this
initial diagnostic run for faster startup. Automatic diagnostics after
fault recovery remain enabled.
DC Load Diagnostics
-------------------
The ``CHx DC LDG Report`` 4-bit fault field uses the following encoding:
====== =========== ===================================================
Bit Fault Description
====== =========== ===================================================
[3] S2G Short-to-Ground
[2] S2P Short-to-Power
[1] OL Open Load
[0] SL Shorted Load
====== =========== ===================================================
DC LDG Trigger
~~~~~~~~~~~~~~
:Description: Triggers manual DC load diagnostics on all channels.
:Type: Boolean (write-only)
:Note: Returns -EBUSY if any DAI stream (playback or capture) is active.
The driver manages all channel state transitions. Blocks until
diagnostics complete or time out (300 ms).
DC LDG Auto Diagnostics Switch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Enables automatic DC diagnostics after fault recovery.
:Type: Boolean Switch
:Default: Enabled (1)
:Register: 0xB0 bit [0]
:Note: Active-low, when enabled, affected channels re-run diagnostics after
fault recovery and retry approximately every 750 ms until resolved.
CHx LO LDG Switch
~~~~~~~~~~~~~~~~~
:Description: Enables line output load detection per channel (x = 1, 2, 3, 4).
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0xB1 bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (CH4)
:Note: When enabled and DC diagnostics report OL, the device tests for
a high-impedance line output load.
DC LDG SLOL Ramp Time
~~~~~~~~~~~~~~~~~~~~~
:Description: Voltage ramp time for shorted-load and open-load detection.
:Type: Enumerated
:Default: 15 ms
:Options: 15 ms, 30 ms, 10 ms, 20 ms
:Register: 0xB2 bits [7:6]
DC LDG SLOL Settling Time
~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Settling time for shorted-load and open-load detection.
:Type: Enumerated
:Default: 10 ms
:Options: 10 ms, 5 ms, 20 ms, 15 ms
:Register: 0xB2 bits [5:4]
DC LDG S2PG Ramp Time
~~~~~~~~~~~~~~~~~~~~~
:Description: Voltage ramp time for short-to-power and short-to-ground detection.
:Type: Enumerated
:Default: 5 ms
:Options: 5 ms, 2.5 ms, 10 ms, 15 ms
:Register: 0xB2 bits [3:2]
DC LDG S2PG Settling Time
~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Settling time for short-to-power and short-to-ground detection.
:Type: Enumerated
:Default: 10 ms
:Options: 10 ms, 5 ms, 20 ms, 30 ms
:Register: 0xB2 bits [1:0]
CHx DC LDG SL Threshold
~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Shorted-load detection threshold per channel (x = 1, 2, 3, 4).
:Type: Enumerated
:Default: 1 Ohm
:Options: 0.5 Ohm, 1 Ohm, 1.5 Ohm, 2 Ohm, 2.5 Ohm,
3 Ohm, 3.5 Ohm, 4 Ohm, 4.5 Ohm, 5 Ohm
:Register: 0xB3 bits [7:4] (CH1), bits [3:0] (CH2),
0xB4 bits [7:4] (CH3), bits [3:0] (CH4)
DC LDG Result
~~~~~~~~~~~~~
:Description: Overall DC diagnostic result register.
:Type: Integer (read-only)
:Range: 0x00 to 0xFF
:Register: 0xC2
:Bit Encoding:
======== =====================================================
Bits Description
======== =====================================================
[7:4] Line output detection result, one bit per channel
[3:0] DC diagnostic pass/fail per channel (1=pass, 0=fail)
======== =====================================================
CHx DC LDG Report
~~~~~~~~~~~~~~~~~
:Description: DC diagnostic fault status per channel (x = 1, 2, 3, 4).
:Type: Integer (read-only)
:Range: 0x0 to 0xF
:Register: 0xC0 bits [7:4] (CH1), bits [3:0] (CH2),
0xC1 bits [7:4] (CH3), bits [3:0] (CH4)
:Note: See fault bit encoding table at the start of this section.
CHx LO LDG Report
~~~~~~~~~~~~~~~~~
:Description: Line output load detection result per channel (x = 1, 2, 3, 4).
:Type: Boolean (read-only)
:Values: 0 = not detected, 1 = line output load detected
:Register: 0xC2 bit [7] (CH1), bit [6] (CH2), bit [5] (CH3), bit [4] (CH4)
CHx DC Resistance
~~~~~~~~~~~~~~~~~
:Description: Measured DC load resistance per channel (x = 1, 2, 3, 4).
:Type: Float (read-only, displayed in ohms)
:Resolution: 0.1 ohm per code (10-bit value)
:Range: 0.0 to 102.3 ohms
:Register: 0xD9 bits [7:6]/[5:4]/[3:2]/[1:0] (MSB for CH1CH4),
0xDA (CH1 LSB), 0xDB (CH2 LSB), 0xDC (CH3 LSB), 0xDD (CH4 LSB)
AC Load Diagnostics
-------------------
AC LDG Trigger
~~~~~~~~~~~~~~
:Description: Triggers AC impedance measurement on all channels.
:Type: Boolean (write-only)
:Note: Returns -EBUSY if any DAI stream (playback or capture) is active.
The driver transitions all channels to SLEEP state before starting
the measurement. Blocks until diagnostics complete or time out.
AC LDG Gain
~~~~~~~~~~~
:Description: Measurement resolution for AC diagnostics.
:Type: Boolean Switch
:Default: 1 (Gain 8)
:Values: 0 = 0.8 ohm/code (Gain 1), 1 = 0.1 ohm/code (Gain 8)
:Register: 0xB5 bit [4]
:Note: Gain 8 recommended for load impedances below 8 ohms.
AC LDG Test Frequency
~~~~~~~~~~~~~~~~~~~~~
:Description: Test signal frequency for AC impedance measurement.
:Type: Integer
:Default: 200 (0xC8 = 18.75 kHz)
:Range: 0x01 to 0xFF (0x00 reserved)
:Formula: Frequency = 93.75 Hz × register value
:Register: 0xB8
CHx AC LDG Real / CHx AC LDG Imag
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Real and imaginary AC impedance components per channel
(x = 1, 2, 3, 4).
:Type: Integer (read-only)
:Range: 0x00 to 0xFF (8-bit signed)
:Register: 0xC3 (CH1 Real), 0xC4 (CH1 Imag), 0xC5 (CH2 Real), 0xC6 (CH2 Imag),
0xC7 (CH3 Real), 0xC8 (CH3 Imag), 0xC9 (CH4 Real), 0xCA (CH4 Imag)
:Note: Scale set by AC LDG Gain.
Speaker Protection & Detection
-------------------------------
Tweeter Detection Switch
~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Enables tweeter detection using the AC impedance magnitude comparator.
:Type: Boolean Switch
:Default: Enabled (1)
:Register: 0xB6 bit [0]
:Note: The underlying register bit is TWEETER DETECT DISABLE (active-low).
Control value 1 = detection enabled (register bit 0), 0 = disabled
(register bit 1).
Tweeter Detect Threshold
~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Magnitude threshold for tweeter detection.
:Type: Integer
:Default: 0
:Range: 0x00 to 0xFF
:Resolution: 0.8 ohm/code (AC LDG Gain=0) or 0.1 ohm/code (AC LDG Gain=1)
:Register: 0xB7
CHx Tweeter Detect Report
~~~~~~~~~~~~~~~~~~~~~~~~~~
:Description: Tweeter detection result per channel (x = 1, 2, 3, 4).
:Type: Boolean (read-only)
:Values: 0 = no tweeter detected, 1 = tweeter detected
:Register: 0xCB bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (CH4)
DSP Protection Features
=======================
These controls are unavailable in LLP mode.
Thermal Foldback Switch
-----------------------
:Description: Enables dynamic gain reduction based on die temperature.
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x3A bit [0]
PVDD Foldback Switch
--------------------
:Description: Enables automatic gain limiting when supply voltage drops
(Automatic Gain Limiter).
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x3A bit [4]
DC Blocker Bypass Switch
------------------------
:Description: Bypasses the DC-blocking high-pass filter.
:Type: Boolean Switch
:Default: Not bypassed (0)
:Register: 0x39 bit [0]
Clip Detect Switch
------------------
:Description: Enables DSP-based clip detection (Pseudo-Analog Clip Detect).
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x93 bit [6]
Audio SDOUT Switch
------------------
:Description: Routes post-processed audio to the SDOUT pin instead of
Vpredict data.
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x3A bit [5]
:Note: When enabled, replaces Vpredict data on SDOUT with post-processed
SDIN. All SDOUT configurations that apply to Vpredict also apply
to SDIN-to-SDOUT transmission.
Real-Time Load Diagnostics
===========================
These controls require Normal DSP mode at 48 kHz or 96 kHz. They are
unavailable at 192 kHz and in FFLP and LLP modes.
CHx RTLDG Switch
----------------
:Description: Enables real-time impedance monitoring during playback
(x = 1, 2, 3, 4).
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x37 bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (CH4)
RTLDG Clip Mask Switch
----------------------
:Description: Suppresses impedance updates during clipping events.
:Type: Boolean Switch
:Default: Enabled (1)
:Register: 0x37 bit [4]
ISENSE Calibration Switch
--------------------------
:Description: Enables current sense calibration for accurate impedance
measurements.
:Type: Boolean Switch
:Default: Disabled (0)
:Register: 0x5B bit [3]
RTLDG Open Load Threshold
--------------------------
:Description: DSP coefficient for open load fault detection threshold.
:Type: DSP coefficient (extended control)
:Register: DSP Book 0x8C, page 0x22, 0x98
RTLDG Short Load Threshold
---------------------------
:Description: DSP coefficient for shorted load fault detection threshold.
:Type: DSP coefficient (extended control)
:Register: DSP Book 0x8C, page 0x22, 0x9C
CHx RTLDG Impedance
-------------------
:Description: Real-time load impedance per channel (x = 1, 2, 3, 4).
:Type: Float (read-only, displayed in ohms)
:Register: 0xD10xD2 (CH1), 0xD30xD4 (CH2), 0xD50xD6 (CH3), 0xD70xD8 (CH4)
:Note: Valid only during PLAY state with RTLDG enabled at 48 or
96 kHz. Holds stale data in SLEEP, MUTE, or Hi-Z states.
Fault Monitoring
================
The driver monitors faults via IRQ or periodic polling (fallback when
no ``interrupts`` DT property is present). Detected faults are logged
and cleared so affected channels can recover.
Kernel log messages use the format::
tas675x <addr>: <Name> Latched: 0x<value>
Critical faults are logged at ``CRIT`` level; warnings at ``WARN``.
The following fault registers are monitored:
Critical Faults
---------------
These faults place affected channels into the FAULT state. The driver
issues fault clear (register 0x01 bit 3) to allow recovery.
Overtemperature Shutdown (0x87)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[4] Global OTSD
[3:0] CH1-CH4 OTSD respectively
======== ==========================================
Fires when die temperature exceeds the OTSD threshold. If auto-recovery
is enabled (``OTSD Auto Recovery Switch``), channels return to their
previous state after cooling. Otherwise fault clear is required.
Overcurrent / DC Fault (0x8E)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[7:4] Overcurrent Shutdown, CH1-CH4 respectively
[3:0] DC Fault, CH1-CH4 respectively
======== ==========================================
Overcurrent shutdown occurs when output current reaches the shutdown
threshold (e.g. output short to GND). DC fault fires when DC offset
exceeds the DCFAULT threshold.
Real-Time Load Diagnostic Fault (0x8B)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[7:4] Shorted Load faults, CH1-CH4 respectively
[3:0] Open Load faults, CH1-CH4 respectively
======== ==========================================
Reported during playback when RTLDG detects impedance outside the
configured open/short thresholds. Requires RTLDG and current sense to
be enabled, and a sampling rate of 48 kHz or 96 kHz.
CBC Fault/Warning (0x8D)
~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[7:4] Load current warning, CH1-CH4 respectively
[3:0] Load current fault, CH1-CH4 respectively
======== ==========================================
Cycle-by-cycle current limiting events. A warning fires when the
current limit is active for at least 25% of a 21.3 ms window. A fault
fires if the warning persists for 170.4 ms continuously.
Warnings
--------
These conditions are logged but do not place channels into FAULT state.
Corresponding register bits are cleared when read. Nonetheless, the driver
still clears all events as warnings also latch the (mapped) FAULT pin.
Power Fault (0x86)
~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[7] DVDD Power-On-Reset
[4] DVDD Undervoltage
[3] PVDD Overvoltage
[2] VBAT Overvoltage
[1] PVDD Undervoltage
[0] VBAT Undervoltage
======== ==========================================
Supply-related events. DVDD POR at bit 7 is expected after every
power-up and can be ignored.
CP / OUTM Soft Short Fault (0x7D)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[5:2] OUTM soft short, CH4-CH1 respectively
[1] Charge Pump UVLO (latched)
[0] Charge Pump UVLO (unlatched/live status)
======== ==========================================
Per-channel out_minus soft short faults and charge pump undervoltage lockout.
Clock Fault (0x8A)
~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[0] Clock error
======== ==========================================
Fires on clock halt or unsupported SCLK/FSYNC ratio. Only logged when
a stream is active (suppressed during idle to avoid noise from normal
stream stop/start transitions). See `Clock Fault Behaviour`_ below.
Overtemperature Warning (0x88)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[4] Global OTW
[3:0] CH1-CH4 OTW respectively
======== ==========================================
Fires when temperature crosses the OTW threshold. The device continues
to operate. Only logged on change to avoid log spam.
Clip Warning (0x89)
~~~~~~~~~~~~~~~~~~~
======== ==========================================
Bits Description
======== ==========================================
[3:0] CH1-CH4 clip detected respectively
======== ==========================================
Fires when the audio signal magnitude exceeds the clip detection
threshold. Requires Clip Detect to be enabled. Only logged when a
stream is active.
Driver Known Limitations
========================
Clock Fault Behaviour
---------------------
On Stream Stop
~~~~~~~~~~~~~~
Every time a playback stream stops the FAULT pin briefly asserts. The
ASoC PCM trigger stop sequence calls DAIs in reverse order, so the CPU
DAI stops SCLK before the codec can transition to sleep. The device
detects the clock halt and latches ``CLK_FAULT_LATCHED``, which asserts
the FAULT pin. The driver clears the latch in the ``mute_stream``
callback that follows, so the FAULT pin flicker lasts only a few
milliseconds. Audio output is not affected and no kernel log message
is produced.
On Rapid Rate Switching
~~~~~~~~~~~~~~~~~~~~~~~
When streams are started in rapid succession, an intermittent
``Clock Fault Latched: 0x01`` message may appear in the kernel log.
A (conservative) ~0.5 second gap between sessions eliminates this.
References
==========
- TAS675x Technical Reference Manual: SLOU589A
- Device Tree Bindings: Documentation/devicetree/bindings/sound/ti,tas67524.yaml
- ALSA Control Name Conventions: Documentation/sound/designs/control-names.rst

View File

@ -2,7 +2,7 @@
ALSA SoC Layer
==============
The documentation is spilt into the following sections:-
The documentation is split into the following sections:-
.. toctree::
:maxdepth: 2

View File

@ -75,4 +75,4 @@ Each SoC DSP driver usually supplies the following features :-
3. DMA IO to/from DSP buffers (if applicable)
4. Definition of DSP front end (FE) PCM devices.
Please see DPCM.txt for a description of item 4.
Please see dpcm.rst for a description of item 4.

View File

@ -103,7 +103,7 @@ Returns 0 on success, and -EOPNOTSUPP on failure.
- ``usbdev``: the usb device that was discovered
- ``sdev``: capabilities of the device
**snd_soc_usb_connect()** notifies the ASoC USB DCPM BE DAI link of a USB
**snd_soc_usb_connect()** notifies the ASoC USB DPCM BE DAI link of a USB
audio device detection. This can be utilized in the BE DAI
driver to keep track of available USB audio devices. This is intended
to be called by the USB offload driver residing in USB SND.
@ -118,7 +118,7 @@ Returns 0 on success, negative error code on failure.
- ``usbdev``: the usb device that was removed
- ``sdev``: capabilities to free
**snd_soc_usb_disconnect()** notifies the ASoC USB DCPM BE DAI link of a USB
**snd_soc_usb_disconnect()** notifies the ASoC USB DPCM BE DAI link of a USB
audio device removal. This is intended to be called by the USB offload
driver that resides in USB SND.

View File

@ -15060,6 +15060,15 @@ F: arch/loongarch/
F: drivers/*/*loongarch*
F: drivers/cpufreq/loongson3_cpufreq.c
LOONGSON AUDIO (ASoC) DRIVERS
M: Binbin Zhou <zhoubinbin@loongson.cn>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
F: Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
F: sound/soc/loongson/loongson_*.c
F: sound/soc/loongson/loongson_*.h
LOONGSON GPIO DRIVER
M: Yinbo Zhu <zhuyinbo@loongson.cn>
L: linux-gpio@vger.kernel.org
@ -25131,6 +25140,13 @@ F: include/sound/dmaengine_pcm.h
F: sound/core/pcm_dmaengine.c
F: sound/soc/soc-generic-dmaengine-pcm.c
SOUND - SOC LAYER / GPIO AUDIO AMPLIFIER
M: Herve Codina <herve.codina@bootlin.com>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/gpio-audio-amp.yaml
F: sound/soc/codecs/simple-amplifier.c
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
M: Liam Girdwood <lgirdwood@gmail.com>
M: Mark Brown <broonie@kernel.org>
@ -26465,17 +26481,20 @@ TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS
M: Shenghao Ding <shenghao-ding@ti.com>
M: Kevin Lu <kevin-lu@ti.com>
M: Baojun Xu <baojun.xu@ti.com>
M: Sen Wang <sen@ti.com>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/ti,tas2552.yaml
F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml
F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml
F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
F: Documentation/devicetree/bindings/sound/ti,tas67524.yaml
F: Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
F: Documentation/sound/codecs/tas675x*
F: include/sound/tas2*.h
F: include/sound/tlv320*.h
F: sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@ -26489,6 +26508,7 @@ F: sound/soc/codecs/pcm3168a*.*
F: sound/soc/codecs/pcm5102a.c
F: sound/soc/codecs/pcm512x*.*
F: sound/soc/codecs/tas2*.*
F: sound/soc/codecs/tas675x*.*
F: sound/soc/codecs/tlv320*.*
F: sound/soc/codecs/tpa6130a2.*

View File

@ -58,8 +58,15 @@ static unsigned long ac97_reset_config[] = {
GPIO95_AC97_nRESET,
};
void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
void pxa27x_configure_ac97reset(struct gpio_desc *gpiod, bool to_gpio)
{
int reset_gpio;
if (!gpiod)
return;
reset_gpio = desc_to_gpio(gpiod);
/*
* This helper function is used to work around a bug in the pxa27x's
* ac97 controller during a warm reset. The configuration of the

View File

@ -1132,6 +1132,7 @@ EXPORT_SYMBOL(release_firmware);
/* Async support */
struct firmware_work {
struct work_struct work;
struct list_head list;
struct module *module;
const char *name;
struct device *device;
@ -1140,6 +1141,17 @@ struct firmware_work {
u32 opt_flags;
};
static LIST_HEAD(firmware_work_list);
static DEFINE_SPINLOCK(firmware_work_lock);
static void firmware_work_free(struct firmware_work *fw_work)
{
put_device(fw_work->device); /* taken in request_firmware_nowait() */
module_put(fw_work->module);
kfree_const(fw_work->name);
kfree(fw_work);
}
static void request_firmware_work_func(struct work_struct *work)
{
struct firmware_work *fw_work;
@ -1150,11 +1162,15 @@ static void request_firmware_work_func(struct work_struct *work)
_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0,
fw_work->opt_flags);
fw_work->cont(fw, fw_work->context);
put_device(fw_work->device); /* taken in request_firmware_nowait() */
module_put(fw_work->module);
kfree_const(fw_work->name);
kfree(fw_work);
spin_lock_irq(&firmware_work_lock);
if (!list_empty(&fw_work->list)) {
list_del_init(&fw_work->list);
spin_unlock_irq(&firmware_work_lock);
firmware_work_free(fw_work);
return;
}
spin_unlock_irq(&firmware_work_lock);
}
@ -1164,6 +1180,7 @@ static int _request_firmware_nowait(
void (*cont)(const struct firmware *fw, void *context), bool nowarn)
{
struct firmware_work *fw_work;
unsigned long flags;
fw_work = kzalloc_obj(struct firmware_work, gfp);
if (!fw_work)
@ -1196,7 +1213,12 @@ static int _request_firmware_nowait(
get_device(fw_work->device);
INIT_WORK(&fw_work->work, request_firmware_work_func);
spin_lock_irqsave(&firmware_work_lock, flags);
list_add_tail(&fw_work->list, &firmware_work_list);
schedule_work(&fw_work->work);
spin_unlock_irqrestore(&firmware_work_lock, flags);
return 0;
}
@ -1259,6 +1281,44 @@ int firmware_request_nowait_nowarn(
}
EXPORT_SYMBOL_GPL(firmware_request_nowait_nowarn);
/**
* request_firmware_nowait_cancel() - cancel an async firmware request
* @device: device for which the firmware is being loaded
* @context: context passed to request_firmware_nowait()
* @cont: callback passed to request_firmware_nowait()
*
* Cancel a pending request_firmware_nowait() request for @device, @context
* and @cont. If the associated work has already started, this function waits
* until the callback has returned. If the callback has already completed, this
* function does nothing.
*
* This function may sleep.
*/
void request_firmware_nowait_cancel(struct device *device, void *context,
void (*cont)(const struct firmware *fw,
void *context))
{
struct firmware_work *fw_work = NULL;
struct firmware_work *tmp;
spin_lock_irq(&firmware_work_lock);
list_for_each_entry_reverse(tmp, &firmware_work_list, list) {
if (tmp->device == device && tmp->context == context &&
tmp->cont == cont) {
fw_work = tmp;
list_del_init(&fw_work->list);
break;
}
}
spin_unlock_irq(&firmware_work_lock);
if (!fw_work)
return;
cancel_work_sync(&fw_work->work);
firmware_work_free(fw_work);
}
EXPORT_SYMBOL_GPL(request_firmware_nowait_cancel);
#ifdef CONFIG_FW_CACHE
static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);

View File

@ -1372,6 +1372,34 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
}
EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
/**
* sdw_slave_wait_for_init - Wait for device initialisation
* @slave: Pointer to the SoundWire peripheral.
* @timeout_ms: Timeout in milliseconds.
*
* Wait for a peripheral device to enumerate and be initialised by the
* SoundWire core.
*
* Return: Zero on success, and a negative error code on failure.
*/
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
{
unsigned long time;
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(timeout_ms));
if (!time) {
dev_err(&slave->dev, "Initialization not complete\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}
slave->unattach_request = 0;
return 0;
}
EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
static int sdw_slave_set_frequency(struct sdw_slave *slave)
{
int scale_index;

View File

@ -110,6 +110,9 @@ int request_firmware_nowait(
struct module *module, bool uevent,
const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context));
void request_firmware_nowait_cancel(struct device *device, void *context,
void (*cont)(const struct firmware *fw,
void *context));
int request_firmware_direct(const struct firmware **fw, const char *name,
struct device *device);
int request_firmware_into_buf(const struct firmware **firmware_p,
@ -157,6 +160,13 @@ static inline int request_firmware_nowait(
return -EINVAL;
}
static inline void request_firmware_nowait_cancel(struct device *device,
void *context,
void (*cont)(const struct firmware *fw,
void *context))
{
}
static inline void release_firmware(const struct firmware *fw)
{
}

View File

@ -1476,6 +1476,13 @@ static inline int of_property_read_s32(const struct device_node *np,
return of_property_read_u32(np, propname, (u32*) out_value);
}
static inline int of_property_read_s32_index(const struct device_node *np,
const char *propname, u32 index,
s32 *out_value)
{
return of_property_read_u32_index(np, propname, index, (u32 *)out_value);
}
#define of_for_each_phandle(it, err, np, ln, cn, cc) \
for (of_phandle_iterator_init((it), (np), (ln), (cn), (cc)), \
err = of_phandle_iterator_next(it); \

View File

@ -6,27 +6,6 @@
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
/*
* @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95)
* a -1 value means no gpio will be used for reset
* @codec_pdata: AC97 codec platform_data
* reset_gpio should only be specified for pxa27x CPUs where a silicon
* bug prevents correct operation of the reset line. If not specified,
* the default behaviour on these CPUs is to consider gpio 113 as the
* AC97 reset line, which is the default on most boards.
*/
typedef struct {
int (*startup)(struct snd_pcm_substream *, void *);
void (*shutdown)(struct snd_pcm_substream *, void *);
void (*suspend)(void *);
void (*resume)(void *);
void *priv;
int reset_gpio;
void *codec_pdata[AC97_BUS_MAX_DEVICES];
} pxa2xx_audio_ops_t;
extern void pxa_set_ac97_info(pxa2xx_audio_ops_t *ops);
extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
extern void pxa27x_configure_ac97reset(struct gpio_desc *reset_gpio, bool to_gpio);
#endif

View File

@ -1093,6 +1093,8 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
/* messaging and data APIs */
int sdw_read(struct sdw_slave *slave, u32 addr);
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
@ -1136,6 +1138,12 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
return -EINVAL;
}
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
{
WARN_ONCE(1, "SoundWire API is disabled");
return -EINVAL;
}
/* messaging and data APIs */
static inline int sdw_read(struct sdw_slave *slave, u32 addr)
{

View File

@ -108,6 +108,9 @@ static inline void ac97_set_drvdata(struct ac97_codec_device *adev,
dev_set_drvdata(ac97_codec_dev2dev(adev), data);
}
void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev);
static inline void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev)
{
return NULL;
}
#endif

View File

@ -62,14 +62,13 @@ struct ac97_controller_ops {
#if IS_ENABLED(CONFIG_AC97_BUS_NEW)
struct ac97_controller *snd_ac97_controller_register(
const struct ac97_controller_ops *ops, struct device *dev,
unsigned short slots_available, void **codecs_pdata);
unsigned short slots_available);
void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl);
#else
static inline struct ac97_controller *
snd_ac97_controller_register(const struct ac97_controller_ops *ops,
struct device *dev,
unsigned short slots_available,
void **codecs_pdata)
unsigned short slots_available)
{
return ERR_PTR(-ENODEV);
}

File diff suppressed because it is too large Load Diff

View File

@ -75,6 +75,27 @@ struct snd_device {
#define snd_device(n) list_entry(n, struct snd_device, list)
/*
* A simple reference counter with a wait queue;
* typically used for usage counts, and you can synchronize at finishing
* via snd_refcount_sync(), which is woken up when the refcount reaches to
* zero again.
*/
struct snd_refcount {
atomic_t count;
wait_queue_head_t waiter;
};
void snd_refcount_init(struct snd_refcount *ref);
static inline void snd_refcount_get(struct snd_refcount *ref)
{
atomic_inc(&ref->count);
}
void snd_refcount_put(struct snd_refcount *ref);
void snd_refcount_sync(struct snd_refcount *ref);
/* main structure for soundcard */
struct snd_card {
@ -139,15 +160,16 @@ struct snd_card {
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
atomic_t power_ref;
wait_queue_head_t power_sleep;
wait_queue_head_t power_ref_sleep;
struct snd_refcount power_ref;
#endif
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
struct snd_mixer_oss *mixer_oss;
int mixer_oss_change_count;
#endif
unsigned char private_data_area[] __aligned(__alignof__(unsigned long long));
};
#define dev_to_snd_card(p) container_of(p, struct snd_card, card_dev)
@ -174,7 +196,7 @@ static inline void snd_power_change_state(struct snd_card *card, unsigned int st
*/
static inline void snd_power_ref(struct snd_card *card)
{
atomic_inc(&card->power_ref);
snd_refcount_get(&card->power_ref);
}
/**
@ -183,8 +205,7 @@ static inline void snd_power_ref(struct snd_card *card)
*/
static inline void snd_power_unref(struct snd_card *card)
{
if (atomic_dec_and_test(&card->power_ref))
wake_up(&card->power_ref_sleep);
snd_refcount_put(&card->power_ref);
}
/**
@ -196,7 +217,7 @@ static inline void snd_power_unref(struct snd_card *card)
*/
static inline void snd_power_sync_ref(struct snd_card *card)
{
wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
snd_refcount_sync(&card->power_ref);
}
/* init.c */
@ -317,6 +338,8 @@ static inline void snd_card_unref(struct snd_card *card)
put_device(&card->card_dev);
}
DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
/* device.c */

View File

@ -286,6 +286,8 @@ struct snd_ctl_elem_value;
#define CS35L56_MBOX_TIMEOUT_US 5000
#define CS35L56_MBOX_POLL_US 250
#define CS35L56_FW_REQ_ACTIVE_TIMEOUT_MS 250
#define CS35L56_PS0_POLL_US 500
#define CS35L56_PS0_TIMEOUT_US 50000
#define CS35L56_PS3_POLL_US 500

View File

@ -125,7 +125,6 @@ struct snd_emux {
*/
struct snd_emux_port {
struct snd_midi_channel_set chset;
struct snd_emux *emu;
char port_mode; /* operation mode */
@ -138,6 +137,7 @@ struct snd_emux_port {
#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
struct snd_seq_oss_arg *oss_arg;
#endif
struct snd_midi_channel_set chset;
};
/* port_mode */

View File

@ -60,7 +60,7 @@ struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus);
struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid);
int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable);
void hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable);
/* microphone privacy specific function supported by ACE3+ architecture */
void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
@ -186,10 +186,9 @@ hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus) { return NULL; }
static inline struct mutex *
hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid) { return NULL; }
static inline int
static inline void
hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
return 0;
}
static inline void

View File

@ -188,8 +188,7 @@ struct hda_codec {
/* PCM to create, set by hda_codec_ops.build_pcms callback */
struct list_head pcm_list_head;
refcount_t pcm_ref;
wait_queue_head_t remove_sleep;
struct snd_refcount pcm_ref;
/* codec specific info */
void *spec;
@ -259,6 +258,7 @@ struct hda_codec {
unsigned int forced_resume:1; /* forced resume for jack */
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
unsigned int ctl_dev_id:1; /* old control element id build behaviour */
unsigned int eld_jack_detect:1; /* Machine jack-detection by ELD */
unsigned long power_on_acct;
unsigned long power_off_acct;
@ -438,9 +438,12 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm)
{
refcount_inc(&pcm->codec->pcm_ref);
snd_refcount_get(&pcm->codec->pcm_ref);
}
static inline void snd_hda_codec_pcm_put(struct hda_pcm *pcm)
{
snd_refcount_put(&pcm->codec->pcm_ref);
}
void snd_hda_codec_pcm_put(struct hda_pcm *pcm);
int snd_hda_codec_prepare(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,

View File

@ -2,55 +2,7 @@
#ifndef PXA2XX_LIB_H
#define PXA2XX_LIB_H
#include <uapi/sound/asound.h>
#include <linux/platform_device.h>
/* PCM */
struct snd_pcm_substream;
struct snd_pcm_hw_params;
struct snd_soc_pcm_runtime;
struct snd_pcm;
struct snd_soc_component;
extern int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_open(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_close(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm);
extern int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd);
extern int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
extern int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
extern int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
extern int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
extern int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd);
extern snd_pcm_uframes_t
pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream);
/* AC97 */
extern int pxa2xx_ac97_read(int slot, unsigned short reg);
extern int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val);
extern bool pxa2xx_ac97_try_warm_reset(void);
extern bool pxa2xx_ac97_try_cold_reset(void);
extern void pxa2xx_ac97_finish_reset(void);
extern int pxa2xx_ac97_hw_suspend(void);
extern int pxa2xx_ac97_hw_resume(void);
extern int pxa2xx_ac97_hw_probe(struct platform_device *dev);
extern void pxa2xx_ac97_hw_remove(struct platform_device *dev);
#include <linux/types.h>
/* modem registers, used by touchscreen driver */
u32 pxa2xx_ac97_read_modr(void);

View File

@ -26,6 +26,8 @@ struct sdca_dev;
* @name: Human-readable string.
* @type: Function topology type.
* @adr: ACPI address (used for SDCA register access).
* @duplicate: Internal flag to indicate if other functions of the same type
* exist.
*/
struct sdca_function_desc {
struct fwnode_handle *node;
@ -33,6 +35,8 @@ struct sdca_function_desc {
const char *name;
u32 type;
u8 adr;
bool duplicate;
};
/**

View File

@ -13,6 +13,7 @@
struct device;
struct regmap;
struct sdca_function_data;
struct sdca_pde_delay;
struct snd_ctl_elem_value;
struct snd_kcontrol;
struct snd_kcontrol_new;
@ -99,4 +100,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
int function_id, int entity_id,
int from_ps, int to_ps,
const struct sdca_pde_delay *pde_delays,
int num_delays);
#endif // __SDCA_ASOC_H__

View File

@ -1452,7 +1452,6 @@ static inline u32 sdca_range_search(struct sdca_control_range *range,
}
int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
struct sdca_function_desc *desc,
struct sdca_function_data *function);
const char *sdca_find_terminal_name(enum sdca_terminal_type type);

View File

@ -18,10 +18,13 @@ struct snd_soc_jack;
* struct jack_state - Jack state structure to keep data between interrupts
* @kctl: Pointer to the ALSA control attached to this jack
* @jack: Pointer to the ASoC jack struct for this jack
* @mask: Possible reported jack status bits for this jack
*/
struct jack_state {
struct snd_kcontrol *kctl;
struct snd_soc_jack *jack;
unsigned int mask;
};
int sdca_jack_alloc_state(struct sdca_interrupt *interrupt);

View File

@ -22,6 +22,7 @@ struct snd_seq_device {
void *private_data; /* private data for the caller */
void (*private_free)(struct snd_seq_device *device);
struct device dev;
unsigned char args[]; /* driver-specific argument */
};
#define to_seq_dev(_dev) \
@ -64,7 +65,7 @@ void snd_seq_device_load_drivers(void);
int snd_seq_device_new(struct snd_card *card, int device, const char *id,
int argsize, struct snd_seq_device **result);
#define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
#define SNDRV_SEQ_DEVICE_ARGPTR(dev) ((void *)(dev)->args)
int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
struct module *mod);

View File

@ -55,14 +55,14 @@ struct snd_midi_channel_set {
int client; /* Client for this port */
int port; /* The port number */
int max_channels; /* Size of the channels array */
struct snd_midi_channel *channels;
unsigned char midi_mode; /* MIDI operating mode */
unsigned char gs_master_volume; /* SYSEX master volume: 0-127 */
unsigned char gs_chorus_mode;
unsigned char gs_reverb_mode;
int max_channels; /* Size of the channels array */
struct snd_midi_channel channels[] __counted_by(max_channels);
};
struct snd_midi_op {

View File

@ -12,6 +12,7 @@
struct _snd_wavefront_midi;
struct _snd_wavefront_card;
struct _snd_wavefront;
struct snd_wss;
typedef struct _snd_wavefront_midi snd_wavefront_midi_t;
typedef struct _snd_wavefront_card snd_wavefront_card_t;
@ -46,6 +47,8 @@ extern void snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *);
extern void snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *);
extern void snd_wavefront_midi_interrupt (snd_wavefront_card_t *);
extern int snd_wavefront_midi_start (snd_wavefront_card_t *);
void snd_wavefront_midi_suspend(snd_wavefront_card_t *card);
void snd_wavefront_midi_resume(snd_wavefront_card_t *card);
struct _snd_wavefront {
unsigned long irq; /* "you were one, one of the few ..." */
@ -93,6 +96,7 @@ struct _snd_wavefront {
int samples_used; /* how many */
char interrupts_are_midi; /* h/w MPU interrupts enabled ? */
char rom_samples_rdonly; /* can we write on ROM samples */
char midi_in_to_synth; /* route external MIDI to synth */
spinlock_t irq_lock;
wait_queue_head_t interrupt_sleeper;
snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */
@ -101,6 +105,7 @@ struct _snd_wavefront {
struct _snd_wavefront_card {
snd_wavefront_t wavefront;
struct snd_wss *chip;
#ifdef CONFIG_PNP
struct pnp_dev *wss;
struct pnp_dev *ctrl;
@ -110,8 +115,10 @@ struct _snd_wavefront_card {
};
extern void snd_wavefront_internal_interrupt (snd_wavefront_card_t *card);
void snd_wavefront_cache_firmware(snd_wavefront_t *dev);
extern int snd_wavefront_start (snd_wavefront_t *dev);
extern int snd_wavefront_detect (snd_wavefront_card_t *card);
int snd_wavefront_resume_synth(snd_wavefront_card_t *card);
extern int snd_wavefront_cmd (snd_wavefront_t *, int, unsigned char *,
unsigned char *);

View File

@ -47,6 +47,8 @@ int snd_soc_card_late_probe(struct snd_soc_card *card);
void snd_soc_card_fixup_controls(struct snd_soc_card *card);
int snd_soc_card_remove(struct snd_soc_card *card);
void snd_soc_card_set_topology_name(struct snd_soc_card *card, const char *preifx);
int snd_soc_card_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);

View File

@ -199,9 +199,7 @@ struct snd_soc_component_driver {
bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
int be_pcm_base; /* base device ID for all BE PCMs */
#ifdef CONFIG_DEBUG_FS
const char *debugfs_prefix;
#endif
};
struct snd_soc_component {
@ -250,7 +248,6 @@ struct snd_soc_component {
void *mark_pm;
struct dentry *debugfs_root;
const char *debugfs_prefix;
};
#define for_each_component_dais(component, dai)\

View File

@ -17,6 +17,7 @@
struct snd_pcm_substream;
struct snd_soc_dapm_widget;
struct snd_compr_stream;
struct clk;
/*
* DAI hardware audio formats.
@ -80,10 +81,10 @@ struct snd_compr_stream;
/*
* define GATED -> CONT. GATED will be selected if both are selected.
* see
* snd_soc_runtime_get_dai_fmt()
* soc_dai_convert_possiblefmt_to_daifmt()
*/
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT 16
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_GATED (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CONT (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
@ -139,14 +140,6 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_BP_FC SND_SOC_DAIFMT_CBP_CFC
#define SND_SOC_DAIFMT_BC_FC SND_SOC_DAIFMT_CBC_CFC
/* Describes the possible PCM format */
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFP (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFP (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFC (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFC (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
@ -188,9 +181,10 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
void snd_soc_dai_set_bclk_clk(struct snd_soc_dai *dai, struct clk *bclk);
/* Digital Audio interface formatting */
int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd);
u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority);
unsigned int snd_soc_dai_auto_select_format(const struct snd_soc_pcm_runtime *rtd);
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
@ -473,6 +467,10 @@ struct snd_soc_dai {
unsigned int symmetric_channels;
unsigned int symmetric_sample_bits;
/* shared BCLK clock for cross-DAI rate constraints */
struct clk *bclk;
unsigned int bclk_ratio; /* BCLK = rate * bclk_ratio (0 = use channels * sample_bits) */
/* parent platform/codec */
struct snd_soc_component *component;

View File

@ -636,6 +636,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_s
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
int snd_soc_dapm_ignore_suspend_widgets(struct snd_soc_card *card);
int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
@ -673,6 +674,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
/* dapm sys fs - used by the core */
extern struct attribute *snd_soc_dapm_dev_attrs[];
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent);
void snd_soc_dapm_debugfs_pop_time(struct dentry *parent);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
@ -685,6 +687,7 @@ int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin);
bool snd_soc_dapm_pin_has_prefix(struct snd_soc_card *card, const char *pin);
void snd_soc_dapm_mark_endpoints_dirty(struct snd_soc_card *card);
/* dapm path query */

View File

@ -431,7 +431,7 @@ struct snd_soc_jack_pin;
int snd_soc_register_card(struct snd_soc_card *card);
void snd_soc_unregister_card(struct snd_soc_card *card);
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
int devm_snd_soc_register_deferrable_card(struct device *dev, struct snd_soc_card *card);
#define devm_snd_soc_register_deferrable_card(d, c) devm_snd_soc_register_card(d, c)
#ifdef CONFIG_PM_SLEEP
int snd_soc_suspend(struct device *dev);
int snd_soc_resume(struct device *dev);
@ -976,9 +976,6 @@ struct snd_soc_card {
const char *long_name;
const char *driver_name;
const char *components;
#ifdef CONFIG_DMI
char dmi_longname[80];
#endif /* CONFIG_DMI */
#ifdef CONFIG_PCI
/*
@ -990,7 +987,7 @@ struct snd_soc_card {
bool pci_subsystem_set;
#endif /* CONFIG_PCI */
char topology_shortname[32];
char *topology_shortname;
struct device *dev;
struct snd_card *snd_card;
@ -1057,10 +1054,14 @@ struct snd_soc_card {
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
const char **ignore_suspend_widgets;
int num_ignore_suspend_widgets;
const struct snd_soc_dapm_widget *of_dapm_widgets;
int num_of_dapm_widgets;
const struct snd_soc_dapm_route *of_dapm_routes;
int num_of_dapm_routes;
const char **of_ignore_suspend_widgets;
int num_of_ignore_suspend_widgets;
/* lists of probed devices belonging to this card */
struct list_head component_dev_list;
@ -1081,11 +1082,8 @@ struct snd_soc_card {
#ifdef CONFIG_PM_SLEEP
struct work_struct deferred_resume_work;
#endif
u32 pop_time;
/* bit field */
unsigned int instantiated:1;
unsigned int topology_shortname_created:1;
unsigned int fully_routed:1;
unsigned int probed:1;
unsigned int component_chaining:1;
@ -1339,6 +1337,7 @@ void snd_soc_of_parse_node_prefix(struct device_node *np,
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname);
int snd_soc_of_parse_ignore_suspend_widgets(struct snd_soc_card *card, const char *propname);
unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt);
unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame);

View File

@ -223,6 +223,17 @@ int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card,
struct asoc_sdw_codec_info *info,
bool playback);
/* es9356 codec support */
int asoc_sdw_es9356_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_es9356_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_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 *num_dais, int *num_devs);
@ -272,7 +283,14 @@ int asoc_sdw_ti_amp_init(struct snd_soc_card *card,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_ti_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_ti_tac5xx2_spk_rtd_init(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai);
int asoc_sdw_ti_amp_initial_settings(struct snd_soc_card *card,
const char *name_prefix);
int asoc_sdw_ti_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_ti_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_es9356_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_es9356_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_es9356_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
#endif

View File

@ -120,6 +120,7 @@ enum audio_device {
TAS2568,
TAS2570,
TAS2572,
TAS2573,
TAS2574,
TAS2781,
TAS5802,

View File

@ -75,6 +75,7 @@ struct snd_timer {
struct list_head ack_list_head;
struct list_head sack_list_head; /* slow ack list head */
struct work_struct task_work;
struct kref kref;
int max_instances; /* upper limit of timer instances */
int num_instances; /* current number of timer instances */
};
@ -131,4 +132,9 @@ int snd_timer_pause(struct snd_timer_instance *timeri);
void snd_timer_interrupt(struct snd_timer *timer, unsigned long ticks_left);
struct snd_timer *snd_timeri_timer_get(struct snd_timer_instance *timeri);
void snd_timeri_timer_put(struct snd_timer *timer);
DEFINE_FREE(snd_timeri_timer, struct snd_timer *, if (_T) snd_timeri_timer_put(_T))
#endif /* __SOUND_TIMER_H */

View File

@ -206,24 +206,6 @@ void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
}
EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_unregister);
/**
* snd_ac97_codec_get_platdata - get platform_data
* @adev: the ac97 codec device
*
* For legacy platforms, in order to have platform_data in codec drivers
* available, while ac97 device are auto-created upon probe, this retrieves the
* platdata which was setup on ac97 controller registration.
*
* Returns the platform data pointer
*/
void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev)
{
struct ac97_controller *ac97_ctrl = adev->ac97_ctrl;
return ac97_ctrl->codecs_pdata[adev->num];
}
EXPORT_SYMBOL_GPL(snd_ac97_codec_get_platdata);
static void ac97_ctrl_codecs_unregister(struct ac97_controller *ac97_ctrl)
{
int i;
@ -337,7 +319,6 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
* @dev: the device providing the ac97 DC function
* @slots_available: mask of the ac97 codecs that can be scanned and probed
* bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3
* @codecs_pdata: codec platform data
*
* Register a digital controller which can control up to 4 ac97 codecs. This is
* the controller side of the AC97 AC-link, while the slave side are the codecs.
@ -346,18 +327,15 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
*/
struct ac97_controller *snd_ac97_controller_register(
const struct ac97_controller_ops *ops, struct device *dev,
unsigned short slots_available, void **codecs_pdata)
unsigned short slots_available)
{
struct ac97_controller *ac97_ctrl;
int ret, i;
int ret;
ac97_ctrl = kzalloc_obj(*ac97_ctrl);
if (!ac97_ctrl)
return ERR_PTR(-ENOMEM);
for (i = 0; i < AC97_BUS_MAX_CODECS && codecs_pdata; i++)
ac97_ctrl->codecs_pdata[i] = codecs_pdata[i];
ac97_ctrl->ops = ops;
ac97_ctrl->slots_available = slots_available;
ac97_ctrl->parent = dev;

View File

@ -73,7 +73,6 @@ int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
if (snd_ac97_check_id(ac97, id, id_mask))
return 0;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);
@ -81,6 +80,7 @@ EXPORT_SYMBOL_GPL(snd_ac97_reset);
const struct bus_type ac97_bus_type = {
.name = "ac97",
};
EXPORT_SYMBOL(ac97_bus_type);
static int __init ac97_bus_init(void)
{
@ -96,7 +96,5 @@ static void __exit ac97_bus_exit(void)
module_exit(ac97_bus_exit);
EXPORT_SYMBOL(ac97_bus_type);
MODULE_DESCRIPTION("Legacy AC97 bus interface");
MODULE_LICENSE("GPL");

View File

@ -948,6 +948,8 @@ static void layout_attached_codec(struct aoa_codec *codec)
if (lineout == 1)
ldev->gpio.methods->set_lineout(codec->gpio, 1);
ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
if (!ctl)
return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name, "Headphone Switch");
ldev->lineout_ctrl = ctl;
@ -961,12 +963,16 @@ static void layout_attached_codec(struct aoa_codec *codec)
if (ldev->have_lineout_detect) {
ctl = snd_ctl_new1(&lineout_detect_choice,
ldev);
if (!ctl)
return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
"Headphone Detect Autoswitch");
aoa_snd_ctl_add(ctl);
ctl = snd_ctl_new1(&lineout_detected,
ldev);
if (!ctl)
return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
"Headphone Detected");

View File

@ -19,10 +19,3 @@ config SND_ARMAACI
select SND_AC97_CODEC
endif # SND_ARM
config SND_PXA2XX_LIB
tristate
select SND_DMAENGINE_PCM
config SND_PXA2XX_LIB_AC97
bool

View File

@ -5,7 +5,3 @@
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
snd-aaci-y := aaci.o
obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o
snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o
snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o

View File

@ -1550,7 +1550,6 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
unsigned int size)
{
struct user_element *ue = snd_kcontrol_chip(kctl);
unsigned int *container;
unsigned int mask = 0;
int i;
int change;
@ -1564,17 +1563,16 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
if (check_user_elem_overflow(ue->card, (ssize_t)(size - ue->tlv_data_size)))
return -ENOMEM;
container = vmemdup_user(buf, size);
unsigned int *container __free(kvfree) = vmemdup_user(buf, size);
if (IS_ERR(container))
return PTR_ERR(container);
change = ue->tlv_data_size != size;
if (!change)
change = memcmp(ue->tlv_data, container, size) != 0;
if (!change) {
kvfree(container);
if (!change)
return 0;
}
if (ue->tlv_data == NULL) {
/* Now TLV data is available. */
@ -1587,7 +1585,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
kvfree(ue->tlv_data);
}
ue->tlv_data = container;
ue->tlv_data = no_free_ptr(container);
ue->tlv_data_size = size;
// decremented at private_free.
ue->card->user_ctl_alloc_size += size;
@ -1628,7 +1626,6 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag,
/* called in controls_rwsem write lock */
static int snd_ctl_elem_init_enum_names(struct user_element *ue)
{
char *names, *p;
size_t buf_len, name_len;
unsigned int i;
const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
@ -1641,27 +1638,28 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue)
if (check_user_elem_overflow(ue->card, buf_len))
return -ENOMEM;
names = vmemdup_user((const void __user *)user_ptrval, buf_len);
char *names __free(kvfree) = vmemdup_user((const void __user *)user_ptrval,
buf_len);
if (IS_ERR(names))
return PTR_ERR(names);
/* check that there are enough valid names */
p = names;
char *p = names;
for (i = 0; i < ue->info.value.enumerated.items; ++i) {
if (buf_len == 0) {
kvfree(names);
if (buf_len == 0)
return -EINVAL;
}
name_len = strnlen(p, buf_len);
if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
kvfree(names);
if (name_len == 0 || name_len >= 64 || name_len == buf_len)
return -EINVAL;
}
p += name_len + 1;
buf_len -= name_len + 1;
}
ue->priv_data = names;
ue->priv_data = no_free_ptr(names);
ue->info.value.enumerated.names_ptr = 0;
// increment the allocation size; decremented again at private_free.
ue->card->user_ctl_alloc_size += ue->info.value.enumerated.names_length;
@ -2293,7 +2291,6 @@ EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
*/
void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
{
struct snd_card *card;
int card_number;
scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
@ -2301,11 +2298,12 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
snd_ctl_layer = lops;
}
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
card = snd_card_ref(card_number);
struct snd_card *card __free(snd_card_unref) =
snd_card_ref(card_number);
if (card) {
scoped_guard(rwsem_read, &card->controls_rwsem)
lops->lregister(card);
snd_card_unref(card);
}
}
}

View File

@ -240,8 +240,6 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
}
}
DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
unsigned int group, bool set)
{
@ -758,18 +756,17 @@ static int __init snd_ctl_led_init(void)
static void __exit snd_ctl_led_exit(void)
{
struct snd_ctl_led *led;
struct snd_card *card;
unsigned int group, card_number;
snd_ctl_disconnect_layer(&snd_ctl_led_lops);
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
if (!snd_ctl_led_card_valid[card_number])
continue;
card = snd_card_ref(card_number);
if (card) {
struct snd_card *card __free(snd_card_unref) =
snd_card_ref(card_number);
if (card)
snd_ctl_led_sysfs_remove(card);
snd_card_unref(card);
}
}
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];

View File

@ -20,7 +20,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
#define NANO_SEC 1000000000UL /* 10^9 in sec */
static unsigned int resolution;
static unsigned int resolution __ro_after_init;
struct snd_hrtimer {
struct snd_timer *timer;

View File

@ -181,7 +181,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
if (extra_size < 0)
extra_size = 0;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
card = kzalloc_flex(*card, private_data_area, extra_size);
if (!card)
return -ENOMEM;
@ -232,7 +232,8 @@ int snd_devm_card_new(struct device *parent, int idx, const char *xid,
int err;
*card_ret = NULL;
card = devres_alloc(__snd_card_release, sizeof(*card) + extra_size,
card = devres_alloc(__snd_card_release,
struct_size(card, private_data_area, extra_size),
GFP_KERNEL);
if (!card)
return -ENOMEM;
@ -280,7 +281,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
int err;
if (extra_size > 0)
card->private_data = (char *)card + sizeof(struct snd_card);
card->private_data = card->private_data_area;
if (xid)
strscpy(card->id, xid, sizeof(card->id));
err = 0;
@ -327,8 +328,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
mutex_init(&card->memory_mutex);
#ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep);
init_waitqueue_head(&card->power_ref_sleep);
atomic_set(&card->power_ref, 0);
snd_refcount_init(&card->power_ref);
#endif
init_waitqueue_head(&card->remove_sleep);
card->sync_irq = -1;
@ -1139,7 +1139,7 @@ EXPORT_SYMBOL(snd_card_file_remove);
* typically around calling control ops.
*
* The caller needs to pull down the refcount via snd_power_unref() later
* no matter whether the error is returned from this function or not.
* when this function returns 0.
*
* Return: Zero if successful, or a negative error code.
*/
@ -1152,7 +1152,11 @@ int snd_power_ref_and_wait(struct snd_card *card)
card->shutdown ||
snd_power_get_state(card) == SNDRV_CTL_POWER_D0,
snd_power_unref(card), snd_power_ref(card));
return card->shutdown ? -ENODEV : 0;
if (card->shutdown) {
snd_power_unref(card);
return -ENODEV;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
@ -1169,7 +1173,8 @@ int snd_power_wait(struct snd_card *card)
int ret;
ret = snd_power_ref_and_wait(card);
snd_power_unref(card);
if (!ret)
snd_power_unref(card);
return ret;
}
EXPORT_SYMBOL(snd_power_wait);

View File

@ -250,18 +250,15 @@ static const char * const jack_events_name[] = {
/* the recommended buffer size is 256 */
static int parse_mask_bits(unsigned int mask_bits, char *buf, size_t buf_size)
{
int len = scnprintf(buf, buf_size, "0x%04x", mask_bits);
int i;
scnprintf(buf, buf_size, "0x%04x", mask_bits);
for (i = 0; i < ARRAY_SIZE(jack_events_name); i++)
if (mask_bits & (1 << i)) {
strlcat(buf, " ", buf_size);
strlcat(buf, jack_events_name[i], buf_size);
}
strlcat(buf, "\n", buf_size);
if (mask_bits & (1 << i))
len += scnprintf(buf + len, buf_size - len, " %s", jack_events_name[i]);
len += scnprintf(buf + len, buf_size - len, "\n");
return strlen(buf);
return len;
}
static ssize_t jack_kctl_mask_bits_read(struct file *file,

View File

@ -174,3 +174,27 @@ void snd_fasync_free(struct snd_fasync *fasync)
kfree(fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_free);
/*
* generic refcount helper
*/
void snd_refcount_init(struct snd_refcount *ref)
{
atomic_set(&ref->count, 0);
init_waitqueue_head(&ref->waiter);
}
EXPORT_SYMBOL_GPL(snd_refcount_init);
void snd_refcount_put(struct snd_refcount *ref)
{
if (atomic_dec_and_test(&ref->count))
wake_up(&ref->waiter);
}
EXPORT_SYMBOL_GPL(snd_refcount_put);
void snd_refcount_sync(struct snd_refcount *ref)
{
wait_event(ref->waiter, !atomic_read(&ref->count));
}
EXPORT_SYMBOL_GPL(snd_refcount_sync);

View File

@ -32,8 +32,8 @@
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
static int dsp_map[SNDRV_CARDS];
static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
static int dsp_map[SNDRV_CARDS] __ro_after_init;
static int adsp_map[SNDRV_CARDS] __ro_after_init = {[0 ... (SNDRV_CARDS-1)] = 1};
static bool nonblock_open = 1;
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");

View File

@ -146,7 +146,7 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
return -ENXIO;
if (snd_BUG_ON(!src_format || !dst_format))
return -ENXIO;
plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
plugin = kzalloc_flex(*plugin, extra_data, extra);
if (plugin == NULL)
return -ENOMEM;
plugin->name = name;

View File

@ -293,7 +293,7 @@ static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
return -ENOTTY;
if (substream->stream != dir)
return -EINVAL;
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (get_user(buf, &data32->buf) ||
@ -338,7 +338,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
return -ENOTTY;
if (substream->stream != dir)
return -EINVAL;
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
ch = substream->runtime->channels;

View File

@ -645,6 +645,14 @@ snd_pcm_state_t snd_pcm_get_state(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_get_state);
static bool snd_pcm_state_open_or_disconnected(struct snd_pcm_substream *substream)
{
snd_pcm_state_t state = snd_pcm_get_state(substream);
return state == SNDRV_PCM_STATE_OPEN ||
state == SNDRV_PCM_STATE_DISCONNECTED;
}
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
int event)
{
@ -1973,13 +1981,15 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream)
static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_state_t cur_state = snd_pcm_get_state(substream);
int f_flags = (__force int)state;
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (cur_state == SNDRV_PCM_STATE_OPEN ||
cur_state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (snd_pcm_running(substream))
if (cur_state == SNDRV_PCM_STATE_RUNNING ||
(cur_state == SNDRV_PCM_STATE_DRAINING &&
substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EBUSY;
substream->f_flags = f_flags;
return 0;
@ -2139,7 +2149,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
card = substream->pcm->card;
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (file) {
@ -3303,10 +3313,9 @@ static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream,
struct snd_xferi __user *_xferi)
{
struct snd_xferi xferi;
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t result;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (put_user(0, &_xferi->result))
return -EFAULT;
@ -3329,7 +3338,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
void *bufs __free(kfree) = NULL;
snd_pcm_sframes_t result;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (runtime->channels > 128)
return -EINVAL;
@ -3392,7 +3401,7 @@ static int snd_pcm_common_ioctl(struct file *file,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
res = snd_power_wait(substream->pcm->card);
@ -3523,7 +3532,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
snd_pcm_uframes_t *frames = arg;
snd_pcm_sframes_t result;
if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
switch (cmd) {
@ -3568,8 +3577,7 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_state_open_or_disconnected(substream))
return -EBADFD;
if (!frame_aligned(runtime, count))
return -EINVAL;
@ -3593,8 +3601,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_state_open_or_disconnected(substream))
return -EBADFD;
if (!frame_aligned(runtime, count))
return -EINVAL;
@ -3620,8 +3627,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_state_open_or_disconnected(substream))
return -EBADFD;
if (!user_backed_iter(to))
return -EINVAL;
@ -3660,8 +3666,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
if (snd_pcm_state_open_or_disconnected(substream))
return -EBADFD;
if (!user_backed_iter(from))
return -EINVAL;

View File

@ -28,8 +28,8 @@ MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");
#ifdef CONFIG_SND_OSSEMUL
static int midi_map[SNDRV_CARDS];
static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
static int midi_map[SNDRV_CARDS] __ro_after_init;
static int amidi_map[SNDRV_CARDS] __ro_after_init = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
module_param_array(amidi_map, int, NULL, 0444);

View File

@ -39,8 +39,10 @@ static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct s
*/
int
snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
*lockp = NULL;
switch (q->s.code) {
case SEQ_EXTENDED:
return extended_event(dp, q, ev);
@ -69,7 +71,7 @@ snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd
if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
break;
if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev, lockp);
break;
case SEQ_ECHO:

View File

@ -91,9 +91,11 @@ union evrec {
#define ev_is_long(ev) ((ev)->s.code >= 128)
#define ev_length(ev) ((ev)->s.code >= 128 ? LONG_EVENT_SIZE : SHORT_EVENT_SIZE)
int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *q);
int snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
DEFINE_FREE(seq_oss_use_lock, snd_use_lock_t *, if (_T) snd_use_lock_free(_T))
#endif /* __SEQ_OSS_EVENT_H */

View File

@ -27,8 +27,8 @@ static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
module_param(maxqlen, int, 0444);
MODULE_PARM_DESC(maxqlen, "maximum queue length");
static int system_client = -1; /* ALSA sequencer client number */
static int system_port = -1;
static int system_client __ro_after_init = -1; /* ALSA sequencer client number */
static int system_port __ro_after_init = -1;
static int num_clients;
static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];

View File

@ -51,9 +51,11 @@ static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
memset(&tmpev, 0, sizeof(tmpev));
snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
tmpev.time.tick = 0;
if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
snd_use_lock_t *lock __free(seq_oss_use_lock) = NULL;
if (!snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev, &lock))
snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
}
return 0;
}
@ -175,4 +177,3 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
}
return 0;
}

View File

@ -593,7 +593,8 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
* non-zero : invalid - ignored
*/
int
snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
struct seq_oss_midi *mdev __free(seq_oss_midi) =
get_mididev(dp, dev);
@ -602,6 +603,9 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
/* the caller must release this later */
*lockp = &mdev->use_lock;
snd_use_lock_use(*lockp);
return 0;
}
return -EINVAL;

View File

@ -26,7 +26,7 @@ void snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode);
int snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev);
void snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
struct snd_seq_event *ev);
struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private);
int snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf);

View File

@ -34,16 +34,10 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
{
struct seq_oss_readq *q;
q = kzalloc_obj(*q);
q = kzalloc_flex(*q, q, maxlen);
if (!q)
return NULL;
q->q = kzalloc_objs(union evrec, maxlen);
if (!q->q) {
kfree(q);
return NULL;
}
q->maxlen = maxlen;
q->qlen = 0;
q->head = q->tail = 0;
@ -61,10 +55,7 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
void
snd_seq_oss_readq_delete(struct seq_oss_readq *q)
{
if (q) {
kfree(q->q);
kfree(q);
}
kfree(q);
}
/*
@ -73,13 +64,17 @@ snd_seq_oss_readq_delete(struct seq_oss_readq *q)
void
snd_seq_oss_readq_clear(struct seq_oss_readq *q)
{
if (q->qlen) {
q->qlen = 0;
q->head = q->tail = 0;
scoped_guard(spinlock_irqsave, &q->lock) {
if (q->qlen) {
q->qlen = 0;
q->head = 0;
q->tail = 0;
}
q->input_time = (unsigned long)-1;
}
/* if someone sleeping, wake'em up */
wake_up(&q->midi_sleep);
q->input_time = (unsigned long)-1;
}
/*
@ -136,11 +131,11 @@ int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
/*
* copy an event to input queue:
* return zero if enqueued
* caller must hold lock
*/
int
snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
static int snd_seq_oss_readq_put_event_locked(struct seq_oss_readq *q,
union evrec *ev)
{
guard(spinlock_irqsave)(&q->lock);
if (q->qlen >= q->maxlen - 1)
return -ENOMEM;
@ -148,12 +143,27 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
q->tail = (q->tail + 1) % q->maxlen;
q->qlen++;
/* wake up sleeper */
wake_up(&q->midi_sleep);
return 0;
}
/*
* copy an event to input queue:
* return zero if enqueued
*/
int
snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
{
int rc;
scoped_guard(spinlock_irqsave, &q->lock) {
rc = snd_seq_oss_readq_put_event_locked(q, ev);
if (!rc)
wake_up(&q->midi_sleep);
}
return rc;
}
/*
* pop queue
@ -209,23 +219,31 @@ snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *w
int
snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode)
{
if (curt != q->input_time) {
union evrec rec;
memset(&rec, 0, sizeof(rec));
switch (seq_mode) {
case SNDRV_SEQ_OSS_MODE_SYNTH:
rec.echo = (curt << 8) | SEQ_WAIT;
snd_seq_oss_readq_put_event(q, &rec);
break;
case SNDRV_SEQ_OSS_MODE_MUSIC:
rec.t.code = EV_TIMING;
rec.t.cmd = TMR_WAIT_ABS;
rec.t.time = curt;
snd_seq_oss_readq_put_event(q, &rec);
break;
int queued = 0;
scoped_guard(spinlock_irqsave, &q->lock) {
if (curt != q->input_time) {
union evrec rec;
memset(&rec, 0, sizeof(rec));
switch (seq_mode) {
case SNDRV_SEQ_OSS_MODE_SYNTH:
rec.echo = (curt << 8) | SEQ_WAIT;
queued = !snd_seq_oss_readq_put_event_locked(q, &rec);
break;
case SNDRV_SEQ_OSS_MODE_MUSIC:
rec.t.code = EV_TIMING;
rec.t.cmd = TMR_WAIT_ABS;
rec.t.time = curt;
queued = !snd_seq_oss_readq_put_event_locked(q, &rec);
break;
}
q->input_time = curt;
}
q->input_time = curt;
}
if (queued)
wake_up(&q->midi_sleep);
return 0;
}

View File

@ -10,13 +10,13 @@
#define __SEQ_OSS_READQ_H
#include "seq_oss_device.h"
#include "seq_oss_event.h"
/*
* definition of read queue
*/
struct seq_oss_readq {
union evrec *q;
int qlen;
int maxlen;
int head, tail;
@ -24,6 +24,7 @@ struct seq_oss_readq {
unsigned long input_time;
wait_queue_head_t midi_sleep;
spinlock_t lock;
union evrec q[] __counted_by(maxlen);
};
struct seq_oss_readq *snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen);

View File

@ -57,7 +57,8 @@ snd_seq_oss_read(struct seq_oss_devinfo *dp, char __user *buf, int count)
break;
}
ev_len = ev_length(&rec);
if (ev_len < count) {
if (count < ev_len) {
err = -EINVAL;
snd_seq_oss_readq_unlock(readq, flags);
break;
}
@ -164,7 +165,9 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
event.type = SNDRV_SEQ_EVENT_NOTEOFF;
snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
if (snd_seq_oss_process_event(dp, rec, &event))
snd_use_lock_t *lock __free(seq_oss_use_lock) = NULL;
if (snd_seq_oss_process_event(dp, rec, &event, &lock))
return 0; /* invalid event - no need to insert queue */
event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);

View File

@ -441,6 +441,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
memcpy(&tmpev, &cell->event, aligned_size);
tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
tmpev.data.ext.ptr = NULL;
if (copy_to_user(buf, &tmpev, aligned_size)) {
err = -EFAULT;
break;
@ -535,18 +536,44 @@ static int bounce_error_event(struct snd_seq_client *client,
! client->accept_input)
return 0; /* ignored */
if (event->type == SNDRV_SEQ_EVENT_BOUNCE ||
event->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
return err; /* avoid re-bouncing */
/* set up quoted error */
memset(&bounce_ev, 0, sizeof(bounce_ev));
bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
if (client->type == USER_CLIENT) {
/*
* For user clients, send SNDRV_SEQ_EVENT_BOUNCE with the
* original event embedded as variable-length data. This
* avoids exposing data.quote.event (a kernel pointer) to
* userspace. The variable-length path in snd_seq_event_dup()
* copies the event data from data.ext.ptr into chained cells,
* and snd_seq_expand_var_event() copies only the data content
* -- never the pointer -- to userspace.
*/
bounce_ev.type = SNDRV_SEQ_EVENT_BOUNCE;
bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
bounce_ev.data.ext.len = sizeof(struct snd_seq_event);
bounce_ev.data.ext.ptr = (char *)event;
} else {
/*
* For kernel clients, quote the event pointer directly.
* Kernel consumers can safely dereference the pointer.
*/
bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
bounce_ev.data.quote.origin = event->dest;
bounce_ev.data.quote.event = event;
bounce_ev.data.quote.value = -err; /* use positive value */
}
bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
bounce_ev.dest.client = client->number;
bounce_ev.dest.port = event->source.port;
bounce_ev.data.quote.origin = event->dest;
bounce_ev.data.quote.event = event;
bounce_ev.data.quote.value = -err; /* use positive value */
result = snd_seq_deliver_single_event(NULL, &bounce_ev, atomic, hop + 1);
if (result < 0) {
client->event_lost++;
@ -1287,7 +1314,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
port_idx = -1;
if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
err = snd_seq_create_port(client, port_idx, &port);
err = snd_seq_create_port(client, &port);
if (err < 0)
return err;
@ -1306,9 +1333,13 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
}
}
info->addr = port->addr;
snd_seq_set_port_info(port, info);
err = snd_seq_insert_port(client, port_idx, port);
if (err < 0) {
kfree(port);
return err;
}
info->addr = port->addr;
if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);

View File

@ -72,7 +72,7 @@ struct snd_seq_dummy_port {
int connect;
};
static int my_client = -1;
static int my_client __ro_after_init = -1;
/*
* event input callback - just redirect events to subscribers

View File

@ -101,13 +101,17 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
struct snd_seq_event *event)
{
struct snd_seq_event_cell *cell;
struct snd_seq_pool *pool;
bool linked;
int err;
if (snd_BUG_ON(!f))
return -EINVAL;
guard(snd_seq_fifo)(f);
err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
retry:
pool = READ_ONCE(f->pool);
err = snd_seq_event_dup(pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
if (err < 0) {
if ((err == -ENOMEM) || (err == -EAGAIN))
atomic_inc(&f->overflow);
@ -115,14 +119,24 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
}
/* append new cells to fifo */
linked = false;
scoped_guard(spinlock_irqsave, &f->lock) {
if (f->tail != NULL)
f->tail->next = cell;
f->tail = cell;
if (f->head == NULL)
f->head = cell;
cell->next = NULL;
f->cells++;
if (cell->pool == f->pool) {
if (f->tail)
f->tail->next = cell;
f->tail = cell;
if (!f->head)
f->head = cell;
cell->next = NULL;
f->cells++;
linked = true;
}
}
if (!linked) {
/* Retry against the replacement pool after resize publishes it. */
snd_seq_cell_free(cell);
goto retry;
}
/* wakeup client */
@ -194,13 +208,21 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
struct snd_seq_event_cell *cell)
{
bool linked = false;
if (cell) {
guard(spinlock_irqsave)(&f->lock);
cell->next = f->head;
f->head = cell;
if (!f->tail)
f->tail = cell;
f->cells++;
scoped_guard(spinlock_irqsave, &f->lock) {
if (cell->pool == f->pool) {
cell->next = f->head;
f->head = cell;
if (!f->tail)
f->tail = cell;
f->cells++;
linked = true;
}
}
if (!linked)
snd_seq_cell_free(cell);
}
}
@ -237,7 +259,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
oldpool = f->pool;
oldhead = f->head;
/* exchange pools */
f->pool = newpool;
WRITE_ONCE(f->pool, newpool);
f->head = NULL;
f->tail = NULL;
f->cells = 0;

View File

@ -211,7 +211,7 @@ int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count,
len -= offset;
if (len > count)
len = count;
err = expand_var_event(event, offset, count, buf, true);
err = expand_var_event(event, offset, len, buf, true);
if (err < 0)
return err;
return len;

View File

@ -24,6 +24,7 @@ Possible options for midisynth module:
#include <sound/seq_device.h>
#include <sound/seq_midi_event.h>
#include <sound/initval.h>
#include "seq_lock.h"
MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
@ -42,6 +43,8 @@ struct seq_midisynth {
int device;
int subdevice;
struct snd_rawmidi_file input_rfile;
spinlock_t output_lock; /* protects output_rfile publication */
snd_use_lock_t output_use_lock; /* in-flight event_input users */
struct snd_rawmidi_file output_rfile;
int seq_client;
int seq_port;
@ -125,31 +128,42 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
struct seq_midisynth *msynth = private_data;
unsigned char msg[10]; /* buffer for constructing midi messages */
struct snd_rawmidi_substream *substream;
int err = 0;
int len;
if (snd_BUG_ON(!msynth))
return -EINVAL;
substream = msynth->output_rfile.output;
if (substream == NULL)
return -ENODEV;
scoped_guard(spinlock_irqsave, &msynth->output_lock) {
substream = msynth->output_rfile.output;
if (!substream)
return -ENODEV;
snd_use_lock_use(&msynth->output_use_lock);
}
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
/* invalid event */
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
goto out;
}
snd_seq_dump_var_event(ev, __dump_midi, substream);
snd_midi_event_reset_decode(msynth->parser);
} else {
if (msynth->parser == NULL)
return -EIO;
if (!msynth->parser) {
err = -EIO;
goto out;
}
len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
if (len < 0)
return 0;
goto out;
if (dump_midi(substream, msg, len) < 0)
snd_midi_event_reset_decode(msynth->parser);
}
return 0;
out:
snd_use_lock_free(&msynth->output_use_lock);
return err;
}
@ -163,6 +177,8 @@ static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
msynth->card = card;
msynth->device = device;
msynth->subdevice = subdevice;
spin_lock_init(&msynth->output_lock);
snd_use_lock_init(&msynth->output_use_lock);
return 0;
}
@ -215,12 +231,13 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
{
int err;
struct seq_midisynth *msynth = private_data;
struct snd_rawmidi_file rfile = {};
struct snd_rawmidi_params params;
/* open midi port */
err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile);
&rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
@ -229,12 +246,14 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
params.avail_min = 1;
params.buffer_size = output_buffer_size;
params.no_active_sensing = 1;
err = snd_rawmidi_output_params(msynth->output_rfile.output, &params);
err = snd_rawmidi_output_params(rfile.output, &params);
if (err < 0) {
snd_rawmidi_kernel_release(&msynth->output_rfile);
snd_rawmidi_kernel_release(&rfile);
return err;
}
snd_midi_event_reset_decode(msynth->parser);
scoped_guard(spinlock_irqsave, &msynth->output_lock)
msynth->output_rfile = rfile;
return 0;
}
@ -242,11 +261,19 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
struct seq_midisynth *msynth = private_data;
struct snd_rawmidi_file rfile = {};
if (snd_BUG_ON(!msynth->output_rfile.output))
scoped_guard(spinlock_irqsave, &msynth->output_lock) {
rfile = msynth->output_rfile;
msynth->output_rfile = (struct snd_rawmidi_file){};
}
if (snd_BUG_ON(!rfile.output))
return -EINVAL;
snd_rawmidi_drain_output(msynth->output_rfile.output);
return snd_rawmidi_kernel_release(&msynth->output_rfile);
snd_use_lock_sync(&msynth->output_use_lock);
snd_rawmidi_drain_output(rfile.output);
return snd_rawmidi_kernel_release(&rfile);
}
/* delete given midi synth port */

View File

@ -81,9 +81,6 @@ snd_midi_process_event(const struct snd_midi_op *ops,
pr_debug("ALSA: seq_midi_emul: ev or chanbase NULL (snd_midi_process_event)\n");
return;
}
if (chanset->channels == NULL)
return;
if (snd_seq_ev_is_channel_type(ev)) {
dest_channel = ev->data.note.channel;
if (dest_channel >= chanset->max_channels) {
@ -642,23 +639,6 @@ static void snd_midi_channel_init(struct snd_midi_channel *p, int n)
p->drum_channel = 1; /* Default ch 10 as drums */
}
/*
* Allocate and initialise a set of midi channel control blocks.
*/
static struct snd_midi_channel *snd_midi_channel_init_set(int n)
{
struct snd_midi_channel *chan;
int i;
chan = kmalloc_objs(struct snd_midi_channel, n);
if (chan) {
for (i = 0; i < n; i++)
snd_midi_channel_init(chan+i, i);
}
return chan;
}
/*
* reset all midi channels
*/
@ -687,13 +667,18 @@ reset_all_channels(struct snd_midi_channel_set *chset)
struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n)
{
struct snd_midi_channel_set *chset;
int i;
chset = kmalloc_flex(*chset, channels, n);
if (!chset)
return NULL;
chset->max_channels = n;
chset->private_data = NULL;
for (i = 0; i < n; i++)
snd_midi_channel_init(&chset->channels[i], i);
chset = kmalloc_obj(*chset);
if (chset) {
chset->channels = snd_midi_channel_init_set(n);
chset->private_data = NULL;
chset->max_channels = n;
}
return chset;
}
EXPORT_SYMBOL(snd_midi_channel_alloc_set);
@ -717,7 +702,6 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)
{
if (chset == NULL)
return;
kfree(chset->channels);
kfree(chset);
}
EXPORT_SYMBOL(snd_midi_channel_free_set);

View File

@ -108,14 +108,13 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
}
/* create a port, port number or a negative error code is returned
/* create a port, 0 on success or a negative error code is returned
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
int snd_seq_create_port(struct snd_seq_client *client, int port,
int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret)
{
struct snd_seq_client_port *new_port, *p;
int num;
struct snd_seq_client_port *new_port;
*port_ret = NULL;
@ -141,15 +140,25 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);
*port_ret = new_port;
return 0;
}
/* insert the port; return the port address or a negative error code */
int snd_seq_insert_port(struct snd_seq_client *client, int port,
struct snd_seq_client_port *new_port)
{
struct snd_seq_client_port *p;
int num;
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
kfree(new_port);
if (p->addr.port == port)
return -EBUSY;
}
if (p->addr.port > num) {
insert_before = &p->list;
break;
@ -161,8 +170,8 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
list_add_tail(&new_port->list, insert_before);
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
*port_ret = new_port;
if (!new_port->name[0])
sprintf(new_port->name, "port-%d", num);
return num;
}

View File

@ -98,10 +98,14 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T))
/* create a port, port number or a negative error code is returned */
int snd_seq_create_port(struct snd_seq_client *client, int port_index,
/* create a port, 0 on success or a negative error code is returned */
int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret);
/* insert the port; return the port address or a negative error code */
int snd_seq_insert_port(struct snd_seq_client *client, int port,
struct snd_seq_client_port *new_port);
/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);

View File

@ -132,7 +132,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
struct snd_seq_event_cell * cell)
{
struct snd_seq_event_cell *cur, *prev;
int count;
int remaining;
int prior;
if (snd_BUG_ON(!f || !cell))
@ -162,10 +162,16 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
prev = NULL; /* previous cell */
cur = f->head; /* cursor */
count = 10000; /* FIXME: enough big, isn't it? */
remaining = f->cells;
while (cur != NULL) {
/* compare timestamps */
int rel = compare_timestamp_rel(&cell->event, &cur->event);
if (remaining-- <= 0) {
pr_err("ALSA: seq: inconsistent prioq cell count\n");
return -EINVAL;
}
if (rel < 0)
/* new cell has earlier schedule time, */
break;
@ -176,10 +182,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
/* move cursor to next cell */
prev = cur;
cur = cur->next;
if (! --count) {
pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
}
/* insert it before cursor */

View File

@ -333,10 +333,10 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr)
static int initialize_timer(struct snd_seq_timer *tmr)
{
struct snd_timer *t;
unsigned long freq;
t = tmr->timeri->timer;
struct snd_timer *t __free(snd_timeri_timer) =
snd_timeri_timer_get(tmr->timeri);
if (!t)
return -EINVAL;
@ -456,7 +456,12 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
ti = tmr->timeri;
if (!ti)
break;
snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
struct snd_timer *t __free(snd_timeri_timer) =
snd_timeri_timer_get(ti);
snd_iprintf(buffer, "Timer for queue %i : %s\n",
q->queue,
t ? t->name : "DEAD");
resolution = snd_timer_resolution(ti) * tmr->ticks;
snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);

View File

@ -234,7 +234,10 @@ int snd_seq_device_new(struct snd_card *card, int device, const char *id,
if (snd_BUG_ON(!id))
return -EINVAL;
dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
if (argsize < 0)
return -EINVAL;
dev = kzalloc_flex(*dev, args, argsize);
if (!dev)
return -ENOMEM;

View File

@ -132,8 +132,8 @@ static LIST_HEAD(snd_timer_slave_list);
/* list of open master instances that can accept slave links */
static LIST_HEAD(snd_timer_master_list);
/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);
/* rwlock for timer instance (for trigger actions) */
static DEFINE_RWLOCK(timeri_lock);
#define MAX_SLAVE_INSTANCES 1000
static int num_slaves;
@ -229,6 +229,44 @@ static void snd_timer_request(struct snd_timer_id *tid)
#endif
/*
* refcount management of timer object
*/
static void snd_timer_kref_release(struct kref *kref);
static inline void snd_timer_ref_get(struct snd_timer *timer)
{
kref_get(&timer->kref);
}
static inline void snd_timer_ref_put(struct snd_timer *timer)
{
kref_put(&timer->kref, snd_timer_kref_release);
}
/*
* Return the assigned timer for the instance, NULL if not present;
* the caller is responsible to call snd_timeri_timer_put(), or use auto-cleanup
*/
struct snd_timer *snd_timeri_timer_get(struct snd_timer_instance *timeri)
{
struct snd_timer *t;
guard(read_lock_irqsave)(&timeri_lock);
t = timeri->timer;
if (!t)
return NULL;
snd_timer_ref_get(t);
return t;
}
EXPORT_SYMBOL_GPL(snd_timeri_timer_get);
void snd_timeri_timer_put(struct snd_timer *timer)
{
snd_timer_ref_put(timer);
}
EXPORT_SYMBOL_GPL(snd_timeri_timer_put);
/* move the slave if it belongs to the master; return 1 if match */
static int check_matching_master_slave(struct snd_timer_instance *master,
struct snd_timer_instance *slave)
@ -240,7 +278,8 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
guard(spinlock_irq)(&slave_active_lock);
snd_timer_ref_get(master->timer);
guard(write_lock_irq)(&timeri_lock);
guard(spinlock)(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
@ -386,6 +425,7 @@ int snd_timer_open(struct snd_timer_instance *timeri,
if (snd_timer_has_slave_key(timeri))
list_add_tail(&timeri->master_list, &snd_timer_master_list);
timer->num_instances++;
snd_timer_ref_get(timer);
err = snd_timer_check_master(timeri);
list_added:
if (err < 0)
@ -406,12 +446,13 @@ static void remove_slave_links(struct snd_timer_instance *timeri,
{
struct snd_timer_instance *slave, *tmp;
guard(spinlock_irq)(&slave_active_lock);
guard(write_lock_irq)(&timeri_lock);
guard(spinlock)(&timer->lock);
timeri->timer = NULL;
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
timer->num_instances--;
snd_timer_ref_put(timer);
slave->master = NULL;
slave->timer = NULL;
list_del_init(&slave->ack_list);
@ -461,17 +502,16 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
remove_slave_links(timeri, timer);
/* slave doesn't need to release timer resources below */
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
timer = NULL;
}
if (!(timeri->flags & SNDRV_TIMER_IFLG_SLAVE)) {
if (list_empty(&timer->open_list_head) && timer->hw.close)
timer->hw.close(timer);
/* release a card refcount for safe disconnection */
if (timer->card)
*card_devp_to_put = &timer->card->card_dev;
module_put(timer->module);
}
if (timer) {
if (list_empty(&timer->open_list_head) && timer->hw.close)
timer->hw.close(timer);
/* release a card refcount for safe disconnection */
if (timer->card)
*card_devp_to_put = &timer->card->card_dev;
module_put(timer->module);
snd_timer_ref_put(timer);
}
}
@ -503,12 +543,13 @@ static unsigned long snd_timer_hw_resolution(struct snd_timer *timer)
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{
struct snd_timer * timer;
unsigned long ret = 0;
if (timeri == NULL)
return 0;
timer = timeri->timer;
struct snd_timer *timer __free(snd_timeri_timer)
= snd_timeri_timer_get(timeri);
if (timer) {
guard(spinlock_irqsave)(&timer->lock);
ret = snd_timer_hw_resolution(timer);
@ -560,7 +601,7 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
if (!timer)
return -EINVAL;
guard(spinlock_irqsave)(&timer->lock);
guard(spinlock)(&timer->lock);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
return -EINVAL;
if (timer->card && timer->card->shutdown)
@ -608,7 +649,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
static int snd_timer_start_slave(struct snd_timer_instance *timeri,
bool start)
{
guard(spinlock_irqsave)(&slave_active_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
return -EINVAL;
if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING)
@ -632,7 +672,7 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
timer = timeri->timer;
if (!timer)
return -EINVAL;
guard(spinlock_irqsave)(&timer->lock);
guard(spinlock)(&timer->lock);
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
@ -671,7 +711,6 @@ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
{
bool running;
guard(spinlock_irqsave)(&slave_active_lock);
running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (timeri->timer) {
@ -692,6 +731,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
{
if (timeri == NULL || ticks < 1)
return -EINVAL;
guard(read_lock_irqsave)(&timeri_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
return snd_timer_start_slave(timeri, true);
else
@ -706,6 +746,7 @@ EXPORT_SYMBOL(snd_timer_start);
*/
int snd_timer_stop(struct snd_timer_instance *timeri)
{
guard(read_lock_irqsave)(&timeri_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
return snd_timer_stop_slave(timeri, true);
else
@ -722,6 +763,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
return -EINVAL;
guard(read_lock_irqsave)(&timeri_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
return snd_timer_start_slave(timeri, false);
else
@ -734,6 +776,7 @@ EXPORT_SYMBOL(snd_timer_continue);
*/
int snd_timer_pause(struct snd_timer_instance * timeri)
{
guard(read_lock_irqsave)(&timeri_lock);
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
return snd_timer_stop_slave(timeri, false);
else
@ -961,6 +1004,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
spin_lock_init(&timer->lock);
INIT_WORK(&timer->task_work, snd_timer_work);
timer->max_instances = 1000; /* default limit per timer */
kref_init(&timer->kref);
if (card != NULL) {
timer->module = card->module;
err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
@ -975,6 +1019,15 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
}
EXPORT_SYMBOL(snd_timer_new);
static void snd_timer_kref_release(struct kref *kref)
{
struct snd_timer *timer = container_of(kref, struct snd_timer, kref);
if (timer->private_free)
timer->private_free(timer);
kfree(timer);
}
static int snd_timer_free(struct snd_timer *timer)
{
struct snd_timer_instance *ti, *n;
@ -982,20 +1035,21 @@ static int snd_timer_free(struct snd_timer *timer)
if (!timer)
return 0;
guard(mutex)(&register_mutex);
if (! list_empty(&timer->open_list_head)) {
list_for_each_entry_safe(ti, n, &timer->open_list_head, open_list) {
struct device *card_dev_to_put = NULL;
scoped_guard(mutex, &register_mutex) {
if (!list_empty(&timer->open_list_head)) {
list_for_each_entry_safe(ti, n, &timer->open_list_head, open_list) {
struct device *card_dev_to_put = NULL;
snd_timer_close_locked(ti, &card_dev_to_put);
put_device(card_dev_to_put);
snd_timer_close_locked(ti, &card_dev_to_put);
put_device(card_dev_to_put);
}
}
list_del(&timer->device_list);
}
list_del(&timer->device_list);
if (timer->private_free)
timer->private_free(timer);
kfree(timer);
disable_work_sync(&timer->task_work);
snd_timer_ref_put(timer);
return 0;
}
@ -1778,12 +1832,13 @@ static int snd_timer_user_info(struct file *file,
struct snd_timer_info __user *_info)
{
struct snd_timer_user *tu;
struct snd_timer *t;
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
t = tu->timeri->timer;
struct snd_timer *t __free(snd_timeri_timer) =
snd_timeri_timer_get(tu->timeri);
if (!t)
return -EBADFD;
@ -1808,14 +1863,14 @@ static int snd_timer_user_params(struct file *file,
{
struct snd_timer_user *tu;
struct snd_timer_params params;
struct snd_timer *t;
int err;
guard(mutex)(&register_mutex);
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
t = tu->timeri->timer;
struct snd_timer *t __free(snd_timeri_timer) =
snd_timeri_timer_get(tu->timeri);
if (!t)
return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))

View File

@ -49,12 +49,13 @@ static int snd_timer_user_info_compat(struct file *file,
{
struct snd_timer_user *tu;
struct snd_timer_info32 info;
struct snd_timer *t;
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
t = tu->timeri->timer;
struct snd_timer *t __free(snd_timeri_timer) =
snd_timeri_timer_get(tu->timeri);
if (!t)
return -EBADFD;
memset(&info, 0, sizeof(info));

View File

@ -100,8 +100,7 @@ struct loopback_cable {
spinlock_t lock;
struct loopback_pcm *streams[2];
/* in-flight peer stops running outside cable->lock */
atomic_t stop_count;
wait_queue_head_t stop_wait;
struct snd_refcount stop_count;
struct snd_pcm_hardware hw;
/* flags */
unsigned int valid;
@ -371,7 +370,7 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
return -EIO;
else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) {
/* close must not free the peer runtime below */
atomic_inc(&cable->stop_count);
snd_refcount_get(&cable->stop_count);
stop_capture = true;
}
}
@ -404,8 +403,7 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
if (stop_capture) {
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
if (atomic_dec_and_test(&cable->stop_count))
wake_up(&cable->stop_wait);
snd_refcount_put(&cable->stop_count);
}
return 0;
@ -728,7 +726,6 @@ static void loopback_jiffies_timer_function(struct timer_list *t)
if (dpcm->period_update_pending) {
dpcm->period_update_pending = 0;
period_elapsed = true;
break;
}
}
}
@ -1071,7 +1068,7 @@ static void free_cable(struct snd_pcm_substream *substream)
}
/* Pair with the stop_count increment in loopback_check_format(). */
wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
snd_refcount_sync(&cable->stop_count);
if (other_alive)
return;
@ -1275,8 +1272,7 @@ static int loopback_open(struct snd_pcm_substream *substream)
goto unlock;
}
spin_lock_init(&cable->lock);
atomic_set(&cable->stop_count, 0);
init_waitqueue_head(&cable->stop_wait);
snd_refcount_init(&cable->stop_count);
cable->hw = loopback_pcm_hardware;
if (loopback->timer_source)
cable->ops = &loopback_snd_timer_ops;

View File

@ -46,7 +46,7 @@ module_param_array(uart_enter, bool, NULL, 0444);
MODULE_PARM_DESC(uart_enter, "Issue UART_ENTER command at open.");
static struct platform_device *platform_devices[SNDRV_CARDS];
static int pnp_registered;
static int pnp_registered __ro_after_init;
static unsigned int snd_mpu401_devices;
static int snd_mpu401_create(struct device *devptr, int dev,
@ -123,7 +123,7 @@ static struct platform_driver snd_mpu401_driver = {
static const struct pnp_device_id snd_mpu401_pnpids[] = {
{ .id = "PNPb006" },
{ .id = "" }
{ }
};
MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids);

Some files were not shown because too many files have changed in this diff Show More