mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
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:
commit
056e065a6b
|
|
@ -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>;
|
||||
};
|
||||
48
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.yaml
Normal file
48
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.yaml
Normal 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>;
|
||||
};
|
||||
|
|
@ -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 = <®_audio>;
|
||||
VD-supply = <®_audio>;
|
||||
VLS-supply = <®_audio>;
|
||||
VLC-supply = <®_audio>;
|
||||
reset-gpios = <&gpio 1>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ properties:
|
|||
items:
|
||||
- const: mclk
|
||||
|
||||
port:
|
||||
$ref: audio-graph-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
270
Documentation/devicetree/bindings/sound/gpio-audio-amp.yaml
Normal file
270
Documentation/devicetree/bindings/sound/gpio-audio-amp.yaml
Normal 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 = <®ulator>;
|
||||
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 = <®ulator>;
|
||||
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 = <®ulator>;
|
||||
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 = <®ulator>;
|
||||
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 = <®ulator>;
|
||||
vddio-supply = <®ulator1>;
|
||||
vdda1-supply = <®ulator2>;
|
||||
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>;
|
||||
};
|
||||
...
|
||||
|
|
@ -37,7 +37,13 @@ patternProperties:
|
|||
items:
|
||||
enum:
|
||||
- i2s
|
||||
- left_j
|
||||
- right_j
|
||||
- dsp_a
|
||||
- dsp_b
|
||||
- pdm
|
||||
- msb
|
||||
- lsb
|
||||
|
||||
dai-tdm-slot-num: true
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
|
|
@ -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>;
|
||||
};
|
||||
113
Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
Normal file
113
Documentation/devicetree/bindings/sound/mediatek,mt8196-afe.yaml
Normal 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";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -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";
|
||||
};
|
||||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
280
Documentation/devicetree/bindings/sound/ti,tas67524.yaml
Normal file
280
Documentation/devicetree/bindings/sound/ti,tas67524.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ Codec-Specific Information
|
|||
:maxdepth: 2
|
||||
|
||||
cs35l56
|
||||
tas675x
|
||||
|
|
|
|||
820
Documentation/sound/codecs/tas675x.rst
Normal file
820
Documentation/sound/codecs/tas675x.rst
Normal 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 = 80–100 °C, 2 = 100–120 °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 CH1–CH4),
|
||||
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: 0xD1–0xD2 (CH1), 0xD3–0xD4 (CH2), 0xD5–0xD6 (CH3), 0xD7–0xD8 (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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
20
MAINTAINERS
20
MAINTAINERS
|
|
@ -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.*
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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); \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
2519
include/sound/acp7x_chip_offset_byte.h
Normal file
2519
include/sound/acp7x_chip_offset_byte.h
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)\
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ enum audio_device {
|
|||
TAS2568,
|
||||
TAS2570,
|
||||
TAS2572,
|
||||
TAS2573,
|
||||
TAS2574,
|
||||
TAS2781,
|
||||
TAS5802,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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, ¶ms);
|
||||
err = snd_rawmidi_output_params(rfile.output, ¶ms);
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)(®ister_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, ®ister_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)(®ister_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(¶ms, _params, sizeof(params)))
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue
Block a user