sound updates for 5.16-rc1

Lots of code development have been see in ASoC side as usual, while
 the continued development on memalloc helper and USB-audio low-
 latency support are found in the rest.  Note that a few changes in the
 unusual places like arch/sh are included, which are a part of ASoC DAI
 format cleanups.
 
 ALSA core:
 - Continued memallloc helper updates and cleanups, now supporting
   non-coherent and non-contiguous pages
 - Fixes for races in mixer OSS layer
 
 ASoC:
 - A new version of the audio graph card which supports a wider range
   of systems
 - Several conversions to YAML DT bindings
 - Continuing cleanups to the SOF and Intel code
 - Move of the Cirrus DSP framework into drivers/firmware to allow for
   future use by non-audio DSPs
 - An overhaul of the cs42l42 driver, correcting many problems
 - DAI format terminology conversions over many drivers for cleanups
 - Support for AMD Vangogh and Yelow Cap, Cirrus CS35L41, Maxim
   MAX98520 and MAX98360A, Mediatek MT8195, Nuvoton NAU8821, nVidia
   Tegra210, NXP i.MX8ULP, Qualcomm AudioReach, Realtek ALC5682I-VS,
   RT5682S, and RT9120 and Rockchip RV1126 and RK3568
 
 USB-audio:
 - Continued improvements on low-latency playback
 - Quirks for Pioneer devices, Line6 HX-Stomp XL, Audient iD14
 
 HD-audio:
 - Reduce excessive udelay() calls on Intel platforms; this should
   reduce the CPU load with PulseAudio
 - Quirks for HP and Clevo laptops
 
 FireWire:
 - Support for meter information on MOTU
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmGCYqkOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE9JDQ//bjjRIVH+JmvhNgLJgJdtdpidaplKUtimEsWk
 8/bFJT0lqPjGMz43bALaj4UTvO2N39ZIW8FVmHDVGh54Xuw8Qu+M/NKiD3J2p4xO
 Pc2rljsiJr7G2VfcBEyDb74wF4fdiFqe6N8PsIT2EG7GxhZiZ6i4+7sdpKoXqmgv
 9ltUzPrtIQQva8c0ER+xHNG1sYVX0bh9vzRIA1aEosYmCPqMIatFBocqwT6fM4Ls
 Ko3GK3GBOnlfVoN+O/ZOsR6Lv6XYApUyp2HqCSrnZK1KvVY4ptYP8XLVwPdEi3OX
 5l0oilOvAch2KIj++K2yzk+xpoEQZ/MIO/1eehLN2ioWyayUNNbeHM0fl3dmdLUQ
 Gow8DbA9o63auERTt6qJs6ed7KOmXewKT9IKiSK6f991JaD0n7nCbcw6yRx1OqWA
 CafXVIVW1CsqTGJuMZzdzBvBZ2ex9OpdhpUw2v12vf2OXKQax9WsfJjVL+qmA0PC
 zbb6viwRKLhAYzoPh/pdHOLm2cvRvdJZstnW8w5+52g96LEF9v4bale7aPi4bqdi
 0o5l/0VGjiXjicT2tf/x8WhuExqPSA64L21adshZ0vmSrPmaGJb6IX4j4zd9TW5L
 v3xUUyKRmq3j7fYN2fN2hGh2qGq+EcdcfNyWOj2XrJm+JFB50/Ac1hcYd5WIZKrh
 xn1luaw=
 =UBNY
 -----END PGP SIGNATURE-----

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

Pull sound updates from Takashi Iwai:
 "Lots of code development have been see in ASoC side as usual, while
  the continued development on memalloc helper and USB-audio low-
  latency support are found in the rest.

  Note that a few changes in the unusual places like arch/sh are
  included, which are a part of ASoC DAI format cleanups.

  ALSA core:

   - Continued memalloc helper updates and cleanups, now supporting
     non-coherent and non-contiguous pages

   - Fixes for races in mixer OSS layer

  ASoC:

   - A new version of the audio graph card which supports a wider range
     of systems

   - Several conversions to YAML DT bindings

   - Continuing cleanups to the SOF and Intel code

   - Move of the Cirrus DSP framework into drivers/firmware to allow for
     future use by non-audio DSPs

   - An overhaul of the cs42l42 driver, correcting many problems

   - DAI format terminology conversions over many drivers for cleanups

   - Support for AMD Vangogh and Yelow Cap, Cirrus CS35L41, Maxim
     MAX98520 and MAX98360A, Mediatek MT8195, Nuvoton NAU8821, nVidia
     Tegra210, NXP i.MX8ULP, Qualcomm AudioReach, Realtek ALC5682I-VS,
     RT5682S, and RT9120 and Rockchip RV1126 and RK3568

  USB-audio:

   - Continued improvements on low-latency playback

   - Quirks for Pioneer devices, Line6 HX-Stomp XL, Audient iD14

  HD-audio:

   - Reduce excessive udelay() calls on Intel platforms; this should
     reduce the CPU load with PulseAudio

   - Quirks for HP and Clevo laptops

  FireWire:

   - Support for meter information on MOTU"

* tag 'sound-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (513 commits)
  ALSA: usb-audio: Add quirk for Audient iD14
  ALSA: hda/realtek: Add quirk for Clevo PC70HS
  ALSA: usb-audio: Line6 HX-Stomp XL USB_ID for 48k-fixed quirk
  ALSA: usb-audio: Add registration quirk for JBL Quantum 400
  ASoC: rsnd: Fix an error handling path in 'rsnd_node_count()'
  ASoC: tlv320aic3x: Make aic3x_remove() return void
  ASoC: Intel: soc-acpi: use const for all uses of snd_soc_acpi_codecs
  ASoC: Intel: soc-acpi-cht: shrink tables using compatible IDs
  ASoC: Intel: soc-acpi-byt: shrink tables using compatible IDs
  ASoC: Intel: sof_rt5682: use comp_ids to enumerate rt5682s
  ASoC: Intel: sof_rt5682: detect codec variant in probe function
  ASoC: soc-acpi: add comp_ids field for machine driver matching
  ASoC: mediatek: mt8195: add mt8195-mt6359-rt1011-rt5682 bindings document
  ASoC: mediatek: mt8195: add machine driver with mt6359, rt1011 and rt5682
  ASoC: Stop dummy from overriding hwparams
  ASoC: topology: Change topology device to card device
  ASoC: topology: Use correct device for prints
  ASoC: topology: Check for dapm widget completeness
  ASoC: topology: Add header payload_size verification
  ASoC: core: Remove invalid snd_soc_component_set_jack call
  ...
This commit is contained in:
Linus Torvalds 2021-11-03 07:49:25 -07:00
commit ff0700f036
477 changed files with 48256 additions and 8003 deletions

View File

@ -1,134 +0,0 @@
Qualcomm APR (Asynchronous Packet Router) binding
This binding describes the Qualcomm APR. APR is a IPC protocol for
communication between Application processor and QDSP. APR is mainly
used for audio/voice services on the QDSP.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2"
- qcom,apr-domain
Usage: required
Value type: <u32>
Definition: Destination processor ID.
Possible values are :
1 - APR simulator
2 - PC
3 - MODEM
4 - ADSP
5 - APPS
6 - MODEM2
7 - APPS2
= APR SERVICES
Each subnode of the APR node represents service tied to this apr. The name
of the nodes are not important. The properties of these nodes are defined
by the individual bindings for the specific service
- All APR services MUST contain the following property:
- reg
Usage: required
Value type: <u32>
Definition: APR Service ID
Possible values are :
3 - DSP Core Service
4 - Audio Front End Service.
5 - Voice Stream Manager Service.
6 - Voice processing manager.
7 - Audio Stream Manager Service.
8 - Audio Device Manager Service.
9 - Multimode voice manager.
10 - Core voice stream.
11 - Core voice processor.
12 - Ultrasound stream manager.
13 - Listen stream manager.
- qcom,protection-domain
Usage: optional
Value type: <stringlist>
Definition: Must list the protection domain service name and path
that the particular apr service has a dependency on.
Possible values are :
"avs/audio", "msm/adsp/audio_pd".
"kernel/elf_loader", "msm/modem/wlan_pd".
"tms/servreg", "msm/adsp/audio_pd".
"tms/servreg", "msm/modem/wlan_pd".
"tms/servreg", "msm/slpi/sensor_pd".
= EXAMPLE
The following example represents a QDSP based sound card on a MSM8996 device
which uses apr as communication between Apps and QDSP.
apr {
compatible = "qcom,apr-v2";
qcom,apr-domain = <APR_DOMAIN_ADSP>;
apr-service@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
};
apr-service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
dais {
#sound-dai-cells = <1>;
dai@1 {
reg = <HDMI_RX>;
};
};
};
apr-service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
...
};
apr-service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
...
};
};
= EXAMPLE 2
The following example represents a QDSP based sound card with protection domain
dependencies specified. Here some of the apr services are dependent on services
running on protection domain hosted on ADSP/SLPI remote processors while others
have no such dependency.
apr {
compatible = "qcom,apr-v2";
qcom,glink-channels = "apr_audio_svc";
qcom,apr-domain = <APR_DOMAIN_ADSP>;
apr-service@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
};
q6afe: apr-service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
...
};
q6asm: apr-service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
qcom,protection-domain = "tms/servreg", "msm/slpi/sensor_pd";
...
};
q6adm: apr-service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
...
};
};

View File

@ -0,0 +1,177 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/qcom/qcom,apr.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm APR/GPR (Asynchronous/Generic Packet Router) binding
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
This binding describes the Qualcomm APR/GPR, APR/GPR is a IPC protocol for
communication between Application processor and QDSP. APR/GPR is mainly
used for audio/voice services on the QDSP.
properties:
compatible:
enum:
- qcom,apr-v2
- qcom,gpr
qcom,apr-domain:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 3, 4, 5, 6, 7]
description:
Selects the processor domain for apr
1 = APR simulator
2 = PC Domain
3 = Modem Domain
4 = ADSP Domain
5 = Application processor Domain
6 = Modem2 Domain
7 = Application Processor2 Domain
deprecated: true
qcom,domain:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
description:
Selects the processor domain for apr
1 = APR simulator
2 = PC Domain
3 = Modem Domain
4 = ADSP Domain
5 = Application processor Domain
6 = Modem2 Domain
7 = Application Processor2 Domain
Selects the processor domain for gpr
1 = Modem Domain
2 = Audio DSP Domain
3 = Application Processor Domain
'#address-cells':
const: 1
'#size-cells':
const: 0
#APR/GPR Services
patternProperties:
"^service@[1-9a-d]$":
type: object
description:
APR/GPR node's client devices use subnodes for desired static port services.
properties:
compatible:
enum:
- qcom,q6core
- qcom,q6asm
- qcom,q6afe
- qcom,q6adm
- qcom,q6apm
- qcom,q6prm
reg:
minimum: 1
maximum: 13
description:
APR Service ID
3 = DSP Core Service
4 = Audio Front End Service.
5 = Voice Stream Manager Service.
6 = Voice processing manager.
7 = Audio Stream Manager Service.
8 = Audio Device Manager Service.
9 = Multimode voice manager.
10 = Core voice stream.
11 = Core voice processor.
12 = Ultrasound stream manager.
13 = Listen stream manager.
GPR Service ID
1 = Audio Process Manager Service
2 = Proxy Resource Manager Service.
3 = AMDB Service.
4 = Voice processing manager.
qcom,protection-domain:
$ref: /schemas/types.yaml#/definitions/string-array
description: protection domain service name and path for apr service
possible values are
"avs/audio", "msm/adsp/audio_pd".
"kernel/elf_loader", "msm/modem/wlan_pd".
"tms/servreg", "msm/adsp/audio_pd".
"tms/servreg", "msm/modem/wlan_pd".
"tms/servreg", "msm/slpi/sensor_pd".
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
"^.*@[0-9a-f]+$":
type: object
description:
Service based devices like clock controllers or digital audio interfaces.
additionalProperties: false
required:
- compatible
- qcom,domain
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qcom,apr.h>
apr {
compatible = "qcom,apr-v2";
qcom,domain = <APR_DOMAIN_ADSP>;
#address-cells = <1>;
#size-cells = <0>;
q6core: service@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
q6afe: service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
q6asm: service@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
q6adm: service@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
};
- |
#include <dt-bindings/soc/qcom,gpr.h>
gpr {
compatible = "qcom,gpr";
qcom,domain = <GPR_DOMAIN_ID_ADSP>;
#address-cells = <1>;
#size-cells = <0>;
service@1 {
compatible = "qcom,q6apm";
reg = <GPR_APM_MODULE_IID>;
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
};
};

View File

@ -34,6 +34,10 @@ properties:
resets:
maxItems: 1
AVDD-supply:
description:
Analogue power supply.
required:
- "#sound-dai-cells"
- compatible
@ -41,6 +45,7 @@ required:
- clocks
- clock-names
- resets
- AVDD-supply
additionalProperties: false
@ -56,4 +61,5 @@ examples:
clocks = <&clkc CLKID_AUDIO_CODEC>;
clock-names = "pclk";
resets = <&reset RESET_AUDIO_CODEC>;
AVDD-supply = <&vddao_1v8>;
};

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/audio-graph-card2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Audio Graph Card2 Device Tree Bindings
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
properties:
compatible:
enum:
- audio-graph-card2
links:
$ref: /schemas/types.yaml#/definitions/phandle-array
label:
maxItems: 1
routing:
description: |
A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's source.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
multi:
description: Multi-CPU/Codec node
dpcm:
description: DPCM node
codec2codec:
description: Codec to Codec node
required:
- compatible
- links
additionalProperties: false
examples:
- |
sound {
compatible = "audio-graph-card2";
links = <&cpu_port>;
};
cpu {
compatible = "cpu-driver";
cpu_port: port { cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; };
};
codec {
compatible = "codec-driver";
port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; };
};

View File

@ -1,13 +0,0 @@
Bluetooth-SCO audio CODEC
This device support generic Bluetooth SCO link.
Required properties:
- compatible : "delta,dfbmcs320" or "linux,bt-sco"
Example:
codec: bt_sco {
compatible = "delta,dfbmcs320";
};

View File

@ -0,0 +1,157 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/cirrus,cs35l41.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cirrus Logic CS35L41 Speaker Amplifier
maintainers:
- david.rhodes@cirrus.com
description: |
CS35L41 is a boosted mono Class D amplifier with DSP
speaker protection and equalization
properties:
compatible:
enum:
- cirrus,cs35l40
- cirrus,cs35l41
reg:
maxItems: 1
'#sound-dai-cells':
description:
The first cell indicating the audio interface.
const: 1
reset-gpios:
maxItems: 1
VA-supply:
description: voltage regulator phandle for the VA supply
VP-supply:
description: voltage regulator phandle for the VP supply
cirrus,boost-peak-milliamp:
description:
Boost-converter peak current limit in mA.
Configures the peak current by monitoring the current through the boost FET.
Range starts at 1600 mA and goes to a maximum of 4500 mA with increments
of 50 mA. See section 4.3.6 of the datasheet for details.
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 1600
maximum: 4500
default: 4500
cirrus,boost-ind-nanohenry:
description:
Boost inductor value, expressed in nH. Valid
values include 1000, 1200, 1500 and 2200.
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 1000
maximum: 2200
cirrus,boost-cap-microfarad:
description:
Total equivalent boost capacitance on the VBST
and VAMP pins, derated at 11 volts DC. The value must be rounded to the
nearest integer and expressed in uF.
$ref: "/schemas/types.yaml#/definitions/uint32"
cirrus,asp-sdout-hiz:
description:
Audio serial port SDOUT Hi-Z control. Sets the Hi-Z
configuration for SDOUT pin of amplifier.
0 = Logic 0 during unused slots, and while all transmit channels disabled
1 = Hi-Z during unused slots but logic 0 while all transmit channels disabled
2 = (Default) Logic 0 during unused slots, but Hi-Z while all transmit channels disabled
3 = Hi-Z during unused slots and while all transmit channels disabled
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 3
default: 2
cirrus,gpio1-polarity-invert:
description:
Boolean which specifies whether the GPIO1
level is inverted. If this property is not present the level is not inverted.
type: boolean
cirrus,gpio1-output-enable:
description:
Boolean which specifies whether the GPIO1 pin
is configured as an output. If this property is not present the
pin will be configured as an input.
type: boolean
cirrus,gpio1-src-select:
description:
Configures the function of the GPIO1 pin.
Note that the options are different from the GPIO2 pin
0 = High Impedance (Default)
1 = GPIO
2 = Sync
3 = MCLK input
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 3
cirrus,gpio2-polarity-invert:
description:
Boolean which specifies whether the GPIO2
level is inverted. If this property is not present the level is not inverted.
type: boolean
cirrus,gpio2-output-enable:
description:
Boolean which specifies whether the GPIO2 pin
is configured as an output. If this property is not present the
pin will be configured as an input.
type: boolean
cirrus,gpio2-src-select:
description:
Configures the function of the GPIO2 pin.
Note that the options are different from the GPIO1 pin.
0 = High Impedance (Default)
1 = GPIO
2 = Open Drain INTB
3 = MCLK input
4 = Push-pull INTB (active low)
5 = Push-pull INT (active high)
$ref: "/schemas/types.yaml#/definitions/uint32"
minimum: 0
maximum: 5
required:
- compatible
- reg
- "#sound-dai-cells"
- cirrus,boost-peak-milliamp
- cirrus,boost-ind-nanohenry
- cirrus,boost-cap-microfarad
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
cs35l41: cs35l41@2 {
#sound-dai-cells = <1>;
compatible = "cirrus,cs35l41";
reg = <2>;
VA-supply = <&dummy_vreg>;
VP-supply = <&dummy_vreg>;
reset-gpios = <&gpio 110 0>;
cirrus,boost-peak-milliamp = <4500>;
cirrus,boost-ind-nanohenry = <1000>;
cirrus,boost-cap-microfarad = <15>;
};
};

View File

@ -19,13 +19,14 @@ Optional properties:
(See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
for further information relating to interrupt properties)
- cirrus,ts-inv : Boolean property. For jacks that invert the tip sense
polarity. Normal jacks will short tip sense pin to HS1 when headphones are
plugged in and leave tip sense floating when not plugged in. Inverting jacks
short tip sense when unplugged and float when plugged in.
- cirrus,ts-inv : Boolean property. Sets the behaviour of the jack plug
detect switch.
0 = (Default) Non-inverted
1 = Inverted
0 = (Default) Shorted to tip when unplugged, open when plugged.
This is "inverted tip sense (ITS)" in the datasheet.
1 = Open when unplugged, shorted to tip when plugged.
This is "normal tip sense (TS)" in the datasheet.
- cirrus,ts-dbnc-rise : Debounce the rising edge of TIP_SENSE_PLUG. With no
debounce, the tip sense pin might be noisy on a plug event.

View File

@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/linux,bt-sco.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bluetooth SCO Audio Codec Device Tree Bindings
maintainers:
- Mark Brown <broonie@kernel.org>
properties:
'#sound-dai-cells':
enum:
- 0
# For Wideband PCM
- 1
compatible:
enum:
- delta,dfbmcs320
- linux,bt-sco
required:
- '#sound-dai-cells'
- compatible
additionalProperties: false
examples:
- |
codec {
#sound-dai-cells = <0>;
compatible = "linux,bt-sco";
};
...

View File

@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/linux,spdif-dit.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dummy SPDIF Transmitter Device Tree Bindings
maintainers:
- Mark Brown <broonie@kernel.org>
properties:
compatible:
const: linux,spdif-dit
"#sound-dai-cells":
const: 0
required:
- "#sound-dai-cells"
- compatible
additionalProperties: false
examples:
- |
spdif-out {
#sound-dai-cells = <0>;
compatible = "linux,spdif-dit";
};
...

View File

@ -30,6 +30,9 @@ Required properties:
- reg : the I2C address of the device for I2C
Optional properties:
- reset-gpios : GPIO to reset the device
Example:
codec: max98927@3a {

View File

@ -0,0 +1,36 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/maxim,max98520.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim Integrated MAX98520 Speaker Amplifier Driver
maintainers:
- George Song <george.song@maximintegrated.com>
properties:
compatible:
const: maxim,max98520
reg:
maxItems: 1
description: I2C address of the device.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
max98520: amplifier@38 {
compatible = "maxim,max98520";
reg = <0x38>;
};
};

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mt8192-afe-pcm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek AFE PCM controller for mt8192
maintainers:
- Jiaxin Yu <jiaxin.yu@mediatek.com>
- Shane Chien <shane.chien@mediatek.com>
properties:
compatible:
const: mediatek,mt8192-audio
interrupts:
maxItems: 1
resets:
maxItems: 1
reset-names:
const: audiosys
mediatek,apmixedsys:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek apmixedsys controller
mediatek,infracfg:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek infracfg controller
mediatek,topckgen:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek topckgen controller
power-domains:
maxItems: 1
clocks:
items:
- description: AFE clock
- description: ADDA DAC clock
- description: ADDA DAC pre-distortion clock
- description: audio infra sys clock
- description: audio infra 26M clock
clock-names:
items:
- const: aud_afe_clk
- const: aud_dac_clk
- const: aud_dac_predis_clk
- const: aud_infra_clk
- const: aud_infra_26m_clk
required:
- compatible
- interrupts
- resets
- reset-names
- mediatek,apmixedsys
- mediatek,infracfg
- mediatek,topckgen
- power-domains
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8192-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/power/mt8192-power.h>
#include <dt-bindings/reset/mt8192-resets.h>
afe: mt8192-afe-pcm {
compatible = "mediatek,mt8192-audio";
interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>;
resets = <&watchdog MT8192_TOPRGU_AUDIO_SW_RST>;
reset-names = "audiosys";
mediatek,apmixedsys = <&apmixedsys>;
mediatek,infracfg = <&infracfg>;
mediatek,topckgen = <&topckgen>;
power-domains = <&scpsys MT8192_POWER_DOMAIN_AUDIO>;
clocks = <&audsys CLK_AUD_AFE>,
<&audsys CLK_AUD_DAC>,
<&audsys CLK_AUD_DAC_PREDIS>,
<&infracfg CLK_INFRA_AUDIO>,
<&infracfg CLK_INFRA_AUDIO_26M_B>;
clock-names = "aud_afe_clk",
"aud_dac_clk",
"aud_dac_predis_clk",
"aud_infra_clk",
"aud_infra_26m_clk";
};
...

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mt8195-mt6359-rt1011-rt5682.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek MT8195 with MT6359, RT1011 and RT5682 ASoC sound card driver
maintainers:
- Trevor Wu <trevor.wu@mediatek.com>
description:
This binding describes the MT8195 sound card with RT1011 and RT5682.
properties:
compatible:
const: mediatek,mt8195_mt6359_rt1011_rt5682
mediatek,platform:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8195 ASoC platform.
mediatek,dptx-codec:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8195 Display Port Tx codec node.
mediatek,hdmi-codec:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8195 HDMI codec node.
additionalProperties: false
required:
- compatible
- mediatek,platform
examples:
- |
sound: mt8195-sound {
compatible = "mediatek,mt8195_mt6359_rt1011_rt5682";
mediatek,platform = <&afe>;
pinctrl-names = "default";
pinctrl-0 = <&aud_pins_default>;
};
...

View File

@ -1,24 +0,0 @@
Name prefix:
Card implementing the routing property define the connection between
audio components as list of string pair. Component using the same
sink/source names may use the name prefix property to prepend the
name of their sinks/sources with the provided string.
Optional name prefix property:
- sound-name-prefix : string using as prefix for the sink/source names of
the component.
Example: Two instances of the same component.
amp0: analog-amplifier@0 {
compatible = "simple-audio-amplifier";
enable-gpios = <&gpio GPIOH_3 0>;
sound-name-prefix = "FRONT";
};
amp1: analog-amplifier@1 {
compatible = "simple-audio-amplifier";
enable-gpios = <&gpio GPIOH_4 0>;
sound-name-prefix = "BACK";
};

View File

@ -0,0 +1,21 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/name-prefix.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Component sound name prefix
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
sound-name-prefix:
$ref: /schemas/types.yaml#/definitions/string
description: |
Card implementing the routing property define the connection between
audio components as list of string pair. Component using the same
sink/source names may use this property to prepend the name of their
sinks/sources with the provided string.
additionalProperties: true

View File

@ -0,0 +1,55 @@
Nuvoton NAU88L21 audio codec
This device supports I2C only.
Required properties:
- compatible : Must be "nuvoton,nau8821"
- reg : the I2C address of the device. This is either 0x1B (CSB=0) or 0x54 (CSB=1).
Optional properties:
- nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
- nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
otherwise pin in high impedance state.
- nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
- nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
- nuvoton,vref-impedance: VREF Impedance selection
0 - Open
1 - 25 kOhm
2 - 125 kOhm
3 - 2.5 kOhm
- nuvoton,micbias-voltage: Micbias voltage level.
0 - VDDA
1 - VDDA
2 - VDDA * 1.1
3 - VDDA * 1.2
4 - VDDA * 1.3
5 - VDDA * 1.4
6 - VDDA * 1.53
7 - VDDA * 1.53
- nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- nuvoton,dmic-clk-threshold: the ADC threshold of DMIC clock.
Example:
headset: nau8821@1b {
compatible = "nuvoton,nau8821";
reg = <0x1b>;
interrupt-parent = <&gpio>;
interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
nuvoton,jkdet-enable;
nuvoton,jkdet-pull-enable;
nuvoton,jkdet-pull-up;
nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
nuvoton,vref-impedance = <2>;
nuvoton,micbias-voltage = <6>;
nuvoton,jack-insert-debounce = <7>;
nuvoton,jack-eject-debounce = <7>;
nuvoton,dmic-clk-threshold = 3072000;
};

View File

@ -17,6 +17,9 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^dspk@[0-9a-f]*$"
@ -48,12 +51,6 @@ properties:
sound-name-prefix:
pattern: "^DSPK[1-9]$"
$ref: /schemas/types.yaml#/definitions/string
description:
Used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "DSPK1" or "DSPKx", where x depends on the maximum
available instances on a Tegra SoC.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra210-adx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra210 ADX Device Tree Bindings
description: |
The Audio Demultiplexer (ADX) block takes an input stream with up to
16 channels and demultiplexes it into four output streams of up to 16
channels each. A byte RAM helps to form output frames by any combination
of bytes from the input frame. Its design is identical to that of byte
RAM in the AMX except that the data flow direction is reversed.
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Mohan Kumar <mkumard@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^adx@[0-9a-f]*$"
compatible:
oneOf:
- const: nvidia,tegra210-adx
- items:
- enum:
- nvidia,tegra194-adx
- nvidia,tegra186-adx
- const: nvidia,tegra210-adx
reg:
maxItems: 1
sound-name-prefix:
pattern: "^ADX[1-9]$"
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: |
ADX has one input and four outputs. Accordingly ACIF (Audio Client
Interface) port nodes are defined to represent ADX input (port 0)
and outputs (ports 1 to 4). These are connected to corresponding
ports on AHUB (Audio Hub).
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: ADX ACIF input port
patternProperties:
'^port@[1-4]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: ADX ACIF output ports
required:
- compatible
- reg
additionalProperties: false
examples:
- |
adx@702d3800 {
compatible = "nvidia,tegra210-adx";
reg = <0x702d3800 0x100>;
sound-name-prefix = "ADX1";
};
...

View File

@ -85,6 +85,26 @@ patternProperties:
type: object
$ref: nvidia,tegra186-dspk.yaml#
'^mvc@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-mvc.yaml#
'^sfc@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-sfc.yaml#
'^amx@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-amx.yaml#
'^adx@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-adx.yaml#
'^amixer@[0-9a-f]+$':
type: object
$ref: nvidia,tegra210-mixer.yaml#
required:
- compatible
- reg

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra210-amx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra210 AMX Device Tree Bindings
description: |
The Audio Multiplexer (AMX) block can multiplex up to four input streams
each of which can have maximum 16 channels and generate an output stream
with maximum 16 channels. A byte RAM helps to form an output frame by
any combination of bytes from the input frames.
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Mohan Kumar <mkumard@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^amx@[0-9a-f]*$"
compatible:
oneOf:
- const: nvidia,tegra210-amx
- items:
- const: nvidia,tegra186-amx
- const: nvidia,tegra210-amx
- const: nvidia,tegra194-amx
reg:
maxItems: 1
sound-name-prefix:
pattern: "^AMX[1-9]$"
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: |
AMX has four inputs and one output. Accordingly ACIF (Audio Client
Interfaces) port nodes are defined to represent AMX inputs (port 0
to 3) and output (port 4). These are connected to corresponding
ports on AHUB (Audio Hub).
patternProperties:
'^port@[0-3]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: AMX ACIF input ports
properties:
port@4:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: AMX ACIF output port
required:
- compatible
- reg
additionalProperties: false
examples:
- |
amx@702d3000 {
compatible = "nvidia,tegra210-amx";
reg = <0x702d3000 0x100>;
sound-name-prefix = "AMX1";
};
...

View File

@ -16,6 +16,9 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^dmic@[0-9a-f]*$"
@ -49,12 +52,6 @@ properties:
sound-name-prefix:
pattern: "^DMIC[1-9]$"
$ref: /schemas/types.yaml#/definitions/string
description:
used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
on the maximum available instances on a Tegra SoC.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@ -16,6 +16,9 @@ maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^i2s@[0-9a-f]*$"
@ -65,12 +68,6 @@ properties:
sound-name-prefix:
pattern: "^I2S[1-9]$"
$ref: /schemas/types.yaml#/definitions/string
description:
Used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
on the maximum available instances on a Tegra SoC.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@ -0,0 +1,74 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mixer.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra210 Mixer Device Tree Bindings
description: |
The Mixer supports mixing of up to ten 7.1 audio input streams and
generate five outputs (each of which can be any combination of the
ten input streams).
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Mohan Kumar <mkumard@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^amixer@[0-9a-f]*$"
compatible:
oneOf:
- const: nvidia,tegra210-amixer
- items:
- enum:
- nvidia,tegra194-amixer
- nvidia,tegra186-amixer
- const: nvidia,tegra210-amixer
reg:
maxItems: 1
sound-name-prefix:
pattern: "^MIXER[1-9]$"
ports:
$ref: /schemas/graph.yaml#/properties/ports
description: |
Mixer has ten inputs and five outputs. Accordingly ACIF (Audio
Client Interfaces) port nodes are defined to represent Mixer
inputs (port 0 to 9) and outputs (port 10 to 14). These are
connected to corresponding ports on AHUB (Audio Hub).
patternProperties:
'^port@[0-9]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: Mixer ACIF input ports
'^port@[10-14]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: Mixer ACIF output ports
required:
- compatible
- reg
additionalProperties: false
examples:
- |
amixer@702dbb00 {
compatible = "nvidia,tegra210-amixer";
reg = <0x702dbb00 0x800>;
sound-name-prefix = "MIXER1";
};
...

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mvc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra210 MVC Device Tree Bindings
description: |
The Master Volume Control (MVC) provides gain or attenuation to a digital
signal path. It can be used in input or output signal path for per-stream
volume control or it can be used as master volume control. The MVC block
has one input and one output. The input digital stream can be mono or
multi-channel (up to 7.1 channels) stream. An independent mute control is
also included in the MVC block.
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Mohan Kumar <mkumard@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^mvc@[0-9a-f]*$"
compatible:
oneOf:
- const: nvidia,tegra210-mvc
- items:
- enum:
- nvidia,tegra194-mvc
- nvidia,tegra186-mvc
- const: nvidia,tegra210-mvc
reg:
maxItems: 1
sound-name-prefix:
pattern: "^MVC[1-9]$"
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
MVC ACIF (Audio Client Interface) input port. This is connected
to corresponding ACIF output port on AHUB (Audio Hub).
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
MVC ACIF output port. This is connected to corresponding ACIF
input port on AHUB.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
mvc@702da000 {
compatible = "nvidia,tegra210-mvc";
reg = <0x702da000 0x200>;
sound-name-prefix = "MVC1";
};
...

View File

@ -0,0 +1,73 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra210-sfc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra210 SFC Device Tree Bindings
description: |
The Sampling Frequency Converter (SFC) converts the sampling frequency
of the input signal from one frequency to another. It supports sampling
frequency conversions of streams of up to two channels (stereo).
maintainers:
- Jon Hunter <jonathanh@nvidia.com>
- Mohan Kumar <mkumard@nvidia.com>
- Sameer Pujar <spujar@nvidia.com>
allOf:
- $ref: name-prefix.yaml#
properties:
$nodename:
pattern: "^sfc@[0-9a-f]*$"
compatible:
oneOf:
- const: nvidia,tegra210-sfc
- items:
- enum:
- nvidia,tegra194-sfc
- nvidia,tegra186-sfc
- const: nvidia,tegra210-sfc
reg:
maxItems: 1
sound-name-prefix:
pattern: "^SFC[1-9]$"
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
SFC ACIF (Audio Client Interface) input port. This is connected
to corresponding ACIF output port on AHUB (Audio Hub).
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
SFC ACIF output port. This is connected to corresponding ACIF
input port on AHUB.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
sfc@702d2000 {
compatible = "nvidia,tegra210-sfc";
reg = <0x702d2000 0x200>;
sound-name-prefix = "SFC1";
};
...

View File

@ -9,6 +9,9 @@ title: NXP/Goodix TFA989X (TFA1) Audio Amplifiers
maintainers:
- Stephan Gerhold <stephan@gerhold.net>
allOf:
- $ref: name-prefix.yaml#
properties:
compatible:
enum:
@ -21,11 +24,7 @@ properties:
'#sound-dai-cells':
const: 0
sound-name-prefix:
$ref: /schemas/types.yaml#/definitions/string
description:
Used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
sound-name-prefix: true
vddd-supply:
description: regulator phandle for the VDDD power supply.

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: qcom,sm8250-lpass-rx-macro
enum:
- qcom,sc7280-lpass-rx-macro
- qcom,sm8250-lpass-rx-macro
reg:
maxItems: 1

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: qcom,sm8250-lpass-tx-macro
enum:
- qcom,sc7280-lpass-tx-macro
- qcom,sm8250-lpass-tx-macro
reg:
maxItems: 1

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: qcom,sm8250-lpass-va-macro
enum:
- qcom,sc7280-lpass-va-macro
- qcom,sm8250-lpass-va-macro
reg:
maxItems: 1

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: qcom,sm8250-lpass-wsa-macro
enum:
- qcom,sc7280-lpass-wsa-macro
- qcom,sm8250-lpass-wsa-macro
reg:
maxItems: 1

View File

@ -12,190 +12,9 @@ used by all apr services. Must contain the following properties.
from DSP.
example "qcom,q6afe"
= AFE DAIs (Digial Audio Interface)
"dais" subnode of the AFE node. It represents afe dais, each afe dai is a
subnode of "dais" representing board specific dai setup.
"dais" node should have following properties followed by dai children.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6afe-dais"
- #sound-dai-cells
Usage: required
Value type: <u32>
Definition: Must be 1
- #address-cells
Usage: required
Value type: <u32>
Definition: Must be 1
- #size-cells
Usage: required
Value type: <u32>
Definition: Must be 0
== AFE DAI is subnode of "dais" and represent a dai, it includes board specific
configuration of each dai. Must contain the following properties.
- reg
Usage: required
Value type: <u32>
Definition: Must be dai id
- qcom,sd-lines
Usage: required for mi2s interface
Value type: <prop-encoded-array>
Definition: Must be list of serial data lines used by this dai.
should be one or more of the 0-3 sd lines.
- qcom,tdm-sync-mode:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Synchronization mode.
0 - Short sync bit mode
1 - Long sync mode
2 - Short sync slot mode
- qcom,tdm-sync-src:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Synchronization source.
0 - External source
1 - Internal source
- qcom,tdm-data-out:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Data out signal to drive with other masters.
0 - Disable
1 - Enable
- qcom,tdm-invert-sync:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Invert the sync.
0 - Normal
1 - Invert
- qcom,tdm-data-delay:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Number of bit clock to delay data
with respect to sync edge.
0 - 0 bit clock cycle
1 - 1 bit clock cycle
2 - 2 bit clock cycle
- qcom,tdm-data-align:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Indicate how data is packed
within the slot. For example, 32 slot width in case of
sample bit width is 24.
0 - MSB
1 - LSB
= AFE CLOCKSS
"clocks" subnode of the AFE node. It represents q6afe clocks
"clocks" node should have following properties.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6afe-clocks"
- #clock-cells:
Usage: required
Value type: <u32>
Definition: Must be 2. Clock Id followed by
below valid clock coupling attributes.
1 - for no coupled clock
2 - for dividend of the coupled clock
3 - for divisor of the coupled clock
4 - for inverted and no couple clock
= EXAMPLE
apr-service@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
dais {
compatible = "qcom,q6afe-dais";
#sound-dai-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
dai@1 {
reg = <HDMI_RX>;
};
dai@24 {
reg = <PRIMARY_TDM_RX_0>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
qcom,tdm-invert-sync = <1>;
qcom,tdm-data-delay = <1>;
qcom,tdm-data-align = <0>;
};
dai@25 {
reg = <PRIMARY_TDM_TX_0>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
qcom,tdm-invert-sync = <1>;
qcom,tdm-data-delay <1>:
qcom,tdm-data-align = <0>;
};
dai@16 {
reg = <PRIMARY_MI2S_RX>;
qcom,sd-lines = <0 2>;
};
dai@17 {
reg = <PRIMARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
dai@18 {
reg = <SECONDARY_MI2S_RX>;
qcom,sd-lines = <0 3>;
};
dai@19 {
reg = <SECONDARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
dai@20 {
reg = <TERTIARY_MI2S_RX>;
qcom,sd-lines = <1 3>;
};
dai@21 {
reg = <TERTIARY_MI2S_TX>;
qcom,sd-lines = <0>;
};
dai@22 {
reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
dai@23 {
reg = <QUATERNARY_MI2S_TX>;
qcom,sd-lines = <1>;
};
};
clocks {
compatible = "qcom,q6afe-clocks";
#clock-cells = <2>;
};
};

View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6apm-dai.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Audio Process Manager Digital Audio Interfaces binding
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
This binding describes the Qualcomm APM DAIs in DSP
properties:
compatible:
const: qcom,q6apm-dais
reg:
maxItems: 1
iommus:
maxItems: 1
required:
- compatible
- iommus
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qcom,gpr.h>
gpr {
compatible = "qcom,gpr";
#address-cells = <1>;
#size-cells = <0>;
qcom,domain = <GPR_DOMAIN_ID_ADSP>;
service@1 {
compatible = "qcom,q6apm";
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
apm-dai@1 {
compatible = "qcom,q6apm-dais";
iommus = <&apps_smmu 0x1801 0x0>;
reg = <1>;
};
};
};

View File

@ -14,7 +14,7 @@ used by the apr service device.
from DSP.
example "qcom,q6asm-v2.0"
= ASM DAIs (Digial Audio Interface)
= ASM DAIs (Digital Audio Interface)
"dais" subnode of the ASM node represents dai specific configuration
- compatible:

View File

@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-clocks.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm DSP LPASS Clock Controller binding
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
This binding describes the Qualcomm DSP Clock Controller
properties:
compatible:
enum:
- qcom,q6afe-clocks
- qcom,q6prm-lpass-clocks
reg:
maxItems: 1
'#clock-cells':
const: 2
description:
Clock Id is followed by clock coupling attributes.
1 = for no coupled clock
2 = for dividend of the coupled clock
3 = for divisor of the coupled clock
4 = for inverted and no couple clock
required:
- compatible
- reg
- "#clock-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qcom,apr.h>
#include <dt-bindings/sound/qcom,q6afe.h>
apr {
#address-cells = <1>;
#size-cells = <0>;
apr-service@4 {
reg = <APR_SVC_AFE>;
#address-cells = <1>;
#size-cells = <0>;
clock-controller@2 {
compatible = "qcom,q6afe-clocks";
reg = <2>;
#clock-cells = <2>;
};
};
};
- |
#include <dt-bindings/soc/qcom,gpr.h>
gpr {
compatible = "qcom,gpr";
qcom,domain = <GPR_DOMAIN_ID_ADSP>;
#address-cells = <1>;
#size-cells = <0>;
service@2 {
reg = <GPR_PRM_MODULE_IID>;
compatible = "qcom,q6prm";
#address-cells = <1>;
#size-cells = <0>;
clock-controller@2 {
compatible = "qcom,q6prm-lpass-clocks";
reg = <2>;
#clock-cells = <2>;
};
};
};

View File

@ -0,0 +1,205 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/qcom,q6dsp-lpass-ports.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm DSP LPASS(Low Power Audio SubSystem) Audio Ports binding
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
This binding describes the Qualcomm DSP LPASS Audio ports
properties:
compatible:
enum:
- qcom,q6afe-dais
- qcom,q6apm-lpass-dais
reg:
maxItems: 1
'#sound-dai-cells':
const: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
#Digital Audio Interfaces
patternProperties:
'^dai@[0-9]+$':
type: object
description:
Q6DSP Digital Audio Interfaces.
properties:
reg:
description:
Digital Audio Interface ID
qcom,sd-lines:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
List of serial data lines used by this dai.should be one or more of the 0-3 sd lines.
minItems: 1
maxItems: 4
uniqueItems: true
items:
minimum: 0
maximum: 3
qcom,tdm-sync-mode:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
description:
TDM Synchronization mode
0 = Short sync bit mode
1 = Long sync mode
2 = Short sync slot mode
qcom,tdm-sync-src:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
description:
TDM Synchronization source
0 = External source
1 = Internal source
qcom,tdm-data-out:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
description:
TDM Data out signal to drive with other masters
0 = Disable
1 = Enable
qcom,tdm-invert-sync:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
description:
TDM Invert the sync
0 = Normal
1 = Invert
qcom,tdm-data-delay:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
description:
TDM Number of bit clock to delay data
0 = 0 bit clock cycle
1 = 1 bit clock cycle
2 = 2 bit clock cycle
qcom,tdm-data-align:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
description:
Indicate how data is packed within the slot. For example, 32 slot
width in case of sample bit width is 24TDM Invert the sync.
0 = MSB
1 = LSB
required:
- reg
allOf:
- if:
properties:
reg:
contains:
# TDM DAI ID range from PRIMARY_TDM_RX_0 - QUINARY_TDM_TX_7
items:
minimum: 24
maximum: 103
then:
required:
- qcom,tdm-sync-mode
- qcom,tdm-sync-src
- qcom,tdm-data-out
- qcom,tdm-invert-sync
- qcom,tdm-data-delay
- qcom,tdm-data-align
- if:
properties:
reg:
contains:
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
# QUINARY_MI2S_RX - QUINARY_MI2S_TX
items:
oneOf:
- minimum: 16
maximum: 23
- minimum: 127
maximum: 128
then:
required:
- qcom,sd-lines
additionalProperties: false
required:
- compatible
- reg
- "#sound-dai-cells"
- "#address-cells"
- "#size-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qcom,apr.h>
#include <dt-bindings/sound/qcom,q6afe.h>
apr {
#address-cells = <1>;
#size-cells = <0>;
apr-service@4 {
reg = <APR_SVC_AFE>;
#address-cells = <1>;
#size-cells = <0>;
q6afedai@1 {
compatible = "qcom,q6afe-dais";
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
#sound-dai-cells = <1>;
dai@22 {
reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0 1 2 3>;
};
};
};
};
- |
#include <dt-bindings/soc/qcom,gpr.h>
gpr {
compatible = "qcom,gpr";
#address-cells = <1>;
#size-cells = <0>;
qcom,domain = <GPR_DOMAIN_ID_ADSP>;
service@1 {
compatible = "qcom,q6apm";
reg = <GPR_APM_MODULE_IID>;
#address-cells = <1>;
#size-cells = <0>;
q6apmdai@1 {
compatible = "qcom,q6apm-lpass-dais";
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
#sound-dai-cells = <1>;
dai@22 {
reg = <QUATERNARY_MI2S_RX>;
qcom,sd-lines = <0 1 2 3>;
};
};
};
};

View File

@ -0,0 +1,117 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/realtek,rt5682s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek rt5682s codec devicetree bindings
maintainers:
- Derek Fang <derek.fang@realtek.com>
description: |
Rt5682s(ALC5682I-VS) is a rt5682i variant which supports I2C only.
properties:
compatible:
const: realtek,rt5682s
reg:
maxItems: 1
description: I2C address of the device.
interrupts:
description: The CODEC's interrupt output.
realtek,dmic1-data-pin:
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 0 # dmic1 data is not used
- 1 # using GPIO2 pin as dmic1 data pin
- 2 # using GPIO5 pin as dmic1 data pin
description: |
Specify which GPIO pin be used as DMIC1 data pin.
realtek,dmic1-clk-pin:
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 0 # dmic1 clk is not used
- 1 # using GPIO1 pin as dmic1 clock pin
- 2 # using GPIO3 pin as dmic1 clock pin
description: |
Specify which GPIO pin be used as DMIC1 clk pin.
realtek,jd-src:
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 0 # No JD is used
- 1 # using JD1 as JD source
description: |
Specify which JD source be used.
realtek,ldo1-en-gpios:
description: |
The GPIO that controls the CODEC's LDO1_EN pin.
realtek,dmic-clk-rate-hz:
description: |
Set the clock rate (hz) for the requirement of the particular DMIC.
realtek,dmic-delay-ms:
description: |
Set the delay time (ms) for the requirement of the particular DMIC.
realtek,dmic-clk-driving-high:
type: boolean
description: |
Set the high driving of the DMIC clock out.
clocks:
items:
- description: phandle and clock specifier for codec MCLK.
clock-names:
items:
- const: mclk
"#clock-cells":
const: 1
clock-output-names:
minItems: 2
maxItems: 2
description: Name given for DAI word clock and bit clock outputs.
additionalProperties: false
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
compatible = "realtek,rt5682s";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(U, 6) IRQ_TYPE_LEVEL_HIGH>;
realtek,ldo1-en-gpios =
<&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
realtek,dmic1-data-pin = <1>;
realtek,dmic1-clk-pin = <1>;
realtek,jd-src = <1>;
#clock-cells = <1>;
clock-output-names = "rt5682-dai-wclk", "rt5682-dai-bclk";
clocks = <&osc>;
clock-names = "mclk";
};
};

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/richtek,rt9120.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Richtek RT9120 Class-D audio amplifier
maintainers:
- ChiYuan Huang <cy_huang@richtek.com>
description: |
The RT9120 is a high efficiency, I2S-input, stereo audio power amplifier
delivering 2*20W into 8 Ohm BTL speaker loads. It supports the wide input
voltage range from 4.5V to 26.4V to meet the need on most common
applications like as TV, monitors. home entertainment, electronic music
equipment.
properties:
compatible:
enum:
- richtek,rt9120
reg:
description: I2C device address
maxItems: 1
pwdnn-gpios:
description: GPIO used for power down, low active
maxItems: 1
dvdd-supply:
description: |
Supply for the default on DVDD power, voltage domain must be 3P3V or 1P8V
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
- dvdd-supply
- '#sound-dai-cells'
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
rt9120@1a {
compatible = "richtek,rt9120";
reg = <0x1a>;
pwdnn-gpios = <&gpio26 2 0>;
dvdd-supply = <&vdd_io_reg>;
#sound-dai-cells = <0>;
};
};

View File

@ -0,0 +1,182 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip,i2s-tdm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip I2S/TDM Controller
description:
The Rockchip I2S/TDM Controller is a Time Division Multiplexed
audio interface found in various Rockchip SoCs, allowing up
to 8 channels of audio over a serial interface.
maintainers:
- Nicolas Frattaroli <frattaroli.nicolas@gmail.com>
properties:
compatible:
enum:
- rockchip,px30-i2s-tdm
- rockchip,rk1808-i2s-tdm
- rockchip,rk3308-i2s-tdm
- rockchip,rk3568-i2s-tdm
- rockchip,rv1126-i2s-tdm
reg:
maxItems: 1
interrupts:
maxItems: 1
dmas:
minItems: 1
maxItems: 2
dma-names:
minItems: 1
maxItems: 2
items:
enum:
- rx
- tx
clocks:
minItems: 3
items:
- description: clock for TX
- description: clock for RX
- description: AHB clock driving the interface
- description:
Parent clock for mclk_tx (only required when using mclk-calibrate)
- description:
Parent clock for mclk_rx (only required when using mclk-calibrate)
- description:
Clock for sample rates that are an integer multiple of 8000
(only required when using mclk-calibrate)
- description:
Clock for sample rates that are an integer multiple of 11025
(only required when using mclk-calibrate)
clock-names:
minItems: 3
items:
- const: mclk_tx
- const: mclk_rx
- const: hclk
- const: mclk_tx_src
- const: mclk_rx_src
- const: mclk_root0
- const: mclk_root1
resets:
minItems: 1
maxItems: 2
description: resets for the tx and rx directions
reset-names:
minItems: 1
maxItems: 2
items:
enum:
- tx-m
- rx-m
rockchip,grf:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The phandle of the syscon node for the GRF register.
rockchip,trcm-sync-tx-only:
type: boolean
description: Use TX BCLK/LRCK for both TX and RX.
rockchip,trcm-sync-rx-only:
type: boolean
description: Use RX BCLK/LRCK for both TX and RX.
"#sound-dai-cells":
const: 0
rockchip,i2s-rx-route:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Defines the mapping of I2S RX sdis to I2S data bus lines.
By default, they are mapped one-to-one.
rockchip,i2s-rx-route = <3> would mean sdi3 is receiving from data0.
maxItems: 4
items:
enum: [0, 1, 2, 3]
rockchip,i2s-tx-route:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Defines the mapping of I2S TX sdos to I2S data bus lines.
By default, they are mapped one-to-one.
rockchip,i2s-tx-route = <3> would mean sdo3 is sending to data0.
maxItems: 4
items:
enum: [0, 1, 2, 3]
rockchip,io-multiplex:
description:
Specify that the GPIO lines on the I2S bus are multiplexed such that
the direction (input/output) needs to be dynamically adjusted.
type: boolean
required:
- compatible
- reg
- interrupts
- dmas
- dma-names
- clocks
- clock-names
- resets
- reset-names
- rockchip,grf
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/rk3568-cru.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/rockchip.h>
bus {
#address-cells = <2>;
#size-cells = <2>;
i2s@fe410000 {
compatible = "rockchip,rk3568-i2s-tdm";
reg = <0x0 0xfe410000 0x0 0x1000>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru MCLK_I2S1_8CH_TX>, <&cru MCLK_I2S1_8CH_RX>,
<&cru HCLK_I2S1_8CH>;
clock-names = "mclk_tx", "mclk_rx", "hclk";
dmas = <&dmac1 3>, <&dmac1 2>;
dma-names = "rx", "tx";
resets = <&cru SRST_M_I2S1_8CH_TX>, <&cru SRST_M_I2S1_8CH_RX>;
reset-names = "tx-m", "rx-m";
rockchip,trcm-sync-tx-only;
rockchip,grf = <&grf>;
#sound-dai-cells = <0>;
pinctrl-names = "default";
pinctrl-0 =
<&i2s1m0_sclktx
&i2s1m0_sclkrx
&i2s1m0_lrcktx
&i2s1m0_lrckrx
&i2s1m0_sdi0
&i2s1m0_sdi1
&i2s1m0_sdi2
&i2s1m0_sdi3
&i2s1m0_sdo0
&i2s1m0_sdo1
&i2s1m0_sdo2
&i2s1m0_sdo3>;
};
};

View File

@ -1,46 +0,0 @@
* Rockchip PDM controller
Required properties:
- compatible: "rockchip,pdm"
- "rockchip,px30-pdm"
- "rockchip,rk1808-pdm"
- "rockchip,rk3308-pdm"
- reg: physical base address of the controller and length of memory mapped
region.
- dmas: DMA specifiers for rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: should include "rx".
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
- clock-names: should contain following:
- "pdm_hclk": clock for PDM BUS
- "pdm_clk" : clock for PDM controller
- resets: a list of phandle + reset-specifer paris, one for each entry in reset-names.
- reset-names: reset names, should include "pdm-m".
- pinctrl-names: Must contain a "default" entry.
- pinctrl-N: One property must exist for each entry in
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
for details of the property values.
Example for rk3328 PDM controller:
pdm: pdm@ff040000 {
compatible = "rockchip,pdm";
reg = <0x0 0xff040000 0x0 0x1000>;
clocks = <&clk_pdm>, <&clk_gates28 0>;
clock-names = "pdm_clk", "pdm_hclk";
dmas = <&pdma 16>;
#dma-cells = <1>;
dma-names = "rx";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pdmm0_clk
&pdmm0_sdi0
&pdmm0_sdi1
&pdmm0_sdi2
&pdmm0_sdi3>;
pinctrl-1 = <&pdmm0_clk_sleep
&pdmm0_sdi0_sleep
&pdmm0_sdi1_sleep
&pdmm0_sdi2_sleep
&pdmm0_sdi3_sleep>;
};

View File

@ -0,0 +1,120 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip,pdm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip PDM controller
description:
The Pulse Density Modulation Interface Controller (PDMC) is
a PDM interface controller and decoder that support PDM format.
It integrates a clock generator driving the PDM microphone
and embeds filters which decimate the incoming bit stream to
obtain most common audio rates.
maintainers:
- Heiko Stuebner <heiko@sntech.de>
properties:
compatible:
enum:
- rockchip,pdm
- rockchip,px30-pdm
- rockchip,rk1808-pdm
- rockchip,rk3308-pdm
- rockchip,rk3568-pdm
- rockchip,rv1126-pdm
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: clock for PDM controller
- description: clock for PDM BUS
clock-names:
items:
- const: pdm_clk
- const: pdm_hclk
dmas:
maxItems: 1
dma-names:
items:
- const: rx
power-domains:
maxItems: 1
resets:
items:
- description: reset for PDM controller
reset-names:
items:
- const: pdm-m
rockchip,path-map:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Defines the mapping of PDM SDIx to PDM PATHx.
By default, they are mapped one-to-one.
maxItems: 4
uniqueItems: true
items:
enum: [ 0, 1, 2, 3 ]
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/rk3328-cru.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/rockchip.h>
bus {
#address-cells = <2>;
#size-cells = <2>;
pdm@ff040000 {
compatible = "rockchip,pdm";
reg = <0x0 0xff040000 0x0 0x1000>;
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_PDM>, <&cru HCLK_PDM>;
clock-names = "pdm_clk", "pdm_hclk";
dmas = <&dmac 16>;
dma-names = "rx";
#sound-dai-cells = <0>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pdmm0_clk
&pdmm0_sdi0
&pdmm0_sdi1
&pdmm0_sdi2
&pdmm0_sdi3>;
pinctrl-1 = <&pdmm0_clk_sleep
&pdmm0_sdi0_sleep
&pdmm0_sdi1_sleep
&pdmm0_sdi2_sleep
&pdmm0_sdi3_sleep>;
};
};

View File

@ -42,7 +42,7 @@ Optional properties:
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
- sound-name-prefix: Please refer to name-prefix.txt
- sound-name-prefix: Please refer to name-prefix.yaml
- ports: A Codec may have a single or multiple I2S interfaces. These
interfaces on Codec side can be described under 'ports' or 'port'.

View File

@ -1,17 +0,0 @@
Simple Amplifier Audio Driver
Required properties:
- compatible : "dioo,dio2125" or "simple-audio-amplifier"
Optional properties:
- enable-gpios : the gpio connected to the enable pin of the simple amplifier
- VCC-supply : power supply for the device, as covered
in Documentation/devicetree/bindings/regulator/regulator.txt
Example:
amp: analog-amplifier {
compatible = "simple-audio-amplifier";
VCC-supply = <&regulator>;
enable-gpios = <&gpio GPIOH_3 0>;
};

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/simple-audio-amplifier.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Simple Audio Amplifier Device Tree Bindings
maintainers:
- Jerome Brunet <jbrunet@baylibre.com>
properties:
compatible:
enum:
- dioo,dio2125
- simple-audio-amplifier
enable-gpios:
maxItems: 1
VCC-supply:
description: >
power supply for the device
sound-name-prefix:
$ref: /schemas/types.yaml#/definitions/string
description: >
See ./name-prefix.txt
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/meson8-gpio.h>
analog-amplifier {
compatible = "simple-audio-amplifier";
VCC-supply = <&regulator>;
enable-gpios = <&gpio GPIOH_3 0>;
};
...

View File

@ -13,6 +13,9 @@ description: |
Simple audio multiplexers are driven using gpios, allowing to select which of
their input line is connected to the output line.
allOf:
- $ref: name-prefix.yaml#
properties:
compatible:
const: simple-audio-mux
@ -21,11 +24,7 @@ properties:
description: |
GPIOs used to select the input line.
sound-name-prefix:
$ref: /schemas/types.yaml#/definitions/string
description:
Used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
sound-name-prefix: true
required:
- compatible

View File

@ -46,7 +46,27 @@ properties:
patternProperties:
"^port@[0-9]$":
description: FIXME, Need to define what each port is.
description: |
Port number of DT node is specified by the following DAI channels that
depends on SoC.
ld11-aio,ld20-aio:
0: hdmi
1: pcmin2
2: line
3: hpcmout1
4: pcmout3
5: hiecout1
6: epcmout2
7: epcmout3
8: hieccompout1
pxs2-aio:
0: hdmi
1: line
2: aux
3: hiecout1
4: iecout1
5: hieccompout1
6: ieccompout1
$ref: audio-graph-port.yaml#
unevaluatedProperties: false

View File

@ -40,7 +40,11 @@ properties:
patternProperties:
"^port@[0-9]$":
description: FIXME, Need to define what each port is.
description: |
Port number of DT node is specified by the following DAI channels.
0: line1
1: hp
2: line2
$ref: audio-graph-port.yaml#
unevaluatedProperties: false

View File

@ -1,10 +0,0 @@
Device-Tree bindings for dummy spdif transmitter
Required properties:
- compatible: should be "linux,spdif-dit".
Example node:
codec: spdif-transmitter {
compatible = "linux,spdif-dit";
};

View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/test-component.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Test Component Device Tree Bindings
maintainers:
- Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
properties:
compatible:
enum:
- test-cpu
- test-cpu-verbose
- test-cpu-verbose-dai
- test-cpu-verbose-component
- test-codec
- test-codec-verbose
- test-codec-verbose-dai
- test-codec-verbose-component
required:
- compatible
additionalProperties: true
examples:
- |
test_cpu {
compatible = "test-cpu";
};

View File

@ -0,0 +1,118 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/wlf,wm8962.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Wolfson WM8962 Ultra-Low Power Stereo CODEC
maintainers:
- patches@opensource.cirrus.com
properties:
compatible:
const: wlf,wm8962
reg:
maxItems: 1
clocks:
maxItems: 1
"#sound-dai-cells":
const: 0
AVDD-supply:
description: Analogue supply.
CPVDD-supply:
description: Charge pump power supply.
DBVDD-supply:
description: Digital Buffer Supply.
DCVDD-supply:
description: Digital Core Supply.
MICVDD-supply:
description: Microphone bias amp supply.
PLLVDD-supply:
description: PLL Supply
SPKVDD1-supply:
description: Supply for left speaker drivers.
SPKVDD2-supply:
description: Supply for right speaker drivers.
spk-mono:
$ref: /schemas/types.yaml#/definitions/flag
description:
If present, the SPK_MONO bit of R51 (Class D Control 2) gets set,
indicating that the speaker is in mono mode.
mic-cfg:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Default register value for R48 (Additional Control 4).
If absent, the default should be the register default.
gpio-cfg:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 6
maxItems: 6
description:
A list of GPIO configuration register values. If absent, no
configuration of these registers is performed. Note that only values
within [0x0, 0xffff] are valid. Any other value is regarded as setting
the GPIO register to its reset value 0x0.
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
- AVDD-supply
- CPVDD-supply
- DBVDD-supply
- DCVDD-supply
- MICVDD-supply
- PLLVDD-supply
- SPKVDD1-supply
- SPKVDD2-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx6qdl-clock.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
wm8962: codec@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;
clocks = <&clks IMX6QDL_CLK_CKO>;
DCVDD-supply = <&reg_audio>;
DBVDD-supply = <&reg_audio>;
AVDD-supply = <&reg_audio>;
CPVDD-supply = <&reg_audio>;
MICVDD-supply = <&reg_audio>;
PLLVDD-supply = <&reg_audio>;
SPKVDD1-supply = <&reg_audio>;
SPKVDD2-supply = <&reg_audio>;
gpio-cfg = <
0x0000 /* 0:Default */
0x0000 /* 1:Default */
0x0013 /* 2:FN_DMICCLK */
0x0000 /* 3:Default */
0x8014 /* 4:FN_DMICCDAT */
0x0000 /* 5:Default */
>;
};
};

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/wlf,wm8978.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Wolfson WM8978 Codec Device Tree Bindings
maintainers:
- patches@opensource.cirrus.com
properties:
'#sound-dai-cells':
const: 0
compatible:
const: wlf,wm8978
reg:
maxItems: 1
spi-max-frequency:
maximum: 526000
required:
- '#sound-dai-cells'
- compatible
- reg
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
codec@0 {
#sound-dai-cells = <0>;
compatible = "wlf,wm8978";
reg = <0>;
spi-max-frequency = <500000>;
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
#sound-dai-cells = <0>;
compatible = "wlf,wm8978";
reg = <0x1a>;
};
};
...

View File

@ -1,43 +0,0 @@
WM8962 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "wlf,wm8962"
- reg : the I2C address of the device.
Optional properties:
- clocks : The clock source of the mclk
- spk-mono: This is a boolean property. If present, the SPK_MONO bit
of R51 (Class D Control 2) gets set, indicating that the speaker is
in mono mode.
- mic-cfg : Default register value for R48 (Additional Control 4).
If absent, the default should be the register default.
- gpio-cfg : A list of GPIO configuration register values. The list must
be 6 entries long. If absent, no configuration of these registers is
performed. And note that only the value within [0x0, 0xffff] is valid.
Any other value is regarded as setting the GPIO register by its reset
value 0x0.
Example:
wm8962: codec@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;
clocks = <&clks IMX6QDL_CLK_CKO>;
gpio-cfg = <
0x0000 /* 0:Default */
0x0000 /* 1:Default */
0x0013 /* 2:FN_DMICCLK */
0x0000 /* 3:Default */
0x8014 /* 4:FN_DMICCDAT */
0x0000 /* 5:Default */
>;
};

View File

@ -100,6 +100,15 @@ amidi_map
MIDI device number maps assigned to the 2st OSS device;
Default: 1
Module snd-soc-core
-------------------
The soc core module. It is used by all ALSA card drivers.
It takes the following options which have global effects.
prealloc_buffer_size_kbytes
Specify prealloc buffer size in kbytes (default: 512).
Common parameters for top sound card modules
--------------------------------------------

View File

@ -40,7 +40,7 @@ e.g.
.prepare = wm8731_pcm_prepare,
.hw_params = wm8731_hw_params,
.shutdown = wm8731_shutdown,
.digital_mute = wm8731_mute,
.mute_stream = wm8731_mute,
.set_sysclk = wm8731_set_dai_sysclk,
.set_fmt = wm8731_set_dai_fmt,
};
@ -60,7 +60,7 @@ e.g.
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
.ops = &wm8731_dai_ops,
.symmetric_rates = 1,
.symmetric_rate = 1,
};
@ -177,10 +177,10 @@ when the mute is applied or freed.
i.e.
::
static int wm8974_mute(struct snd_soc_dai *dai, int mute)
static int wm8974_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct snd_soc_component *component = dai->component;
u16 mute_reg = snd_soc_component_read32(component, WM8974_DAC) & 0xffbf;
u16 mute_reg = snd_soc_component_read(component, WM8974_DAC) & 0xffbf;
if (mute)
snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40);

View File

@ -4468,6 +4468,17 @@ L: patches@opensource.cirrus.com
S: Maintained
F: sound/soc/codecs/cs*
CIRRUS LOGIC DSP FIRMWARE DRIVER
M: Simon Trimmer <simont@opensource.cirrus.com>
M: Charles Keepax <ckeepax@opensource.cirrus.com>
M: Richard Fitzgerald <rf@opensource.cirrus.com>
L: patches@opensource.cirrus.com
S: Supported
W: https://github.com/CirrusLogic/linux-drivers/wiki
T: git https://github.com/CirrusLogic/linux-drivers.git
F: drivers/firmware/cirrus/*
F: include/linux/firmware/cirrus/*
CIRRUS LOGIC EP93XX ETHERNET DRIVER
M: Hartley Sweeten <hsweeten@visionengravers.com>
L: netdev@vger.kernel.org
@ -16227,6 +16238,13 @@ F: Documentation/ABI/*/sysfs-driver-hid-roccat*
F: drivers/hid/hid-roccat*
F: include/linux/hid-roccat*
ROCKCHIP I2S TDM DRIVER
M: Nicolas Frattaroli <frattaroli.nicolas@gmail.com>
L: linux-rockchip@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/sound/rockchip,i2s-tdm.yaml
F: sound/soc/rockchip/rockchip_i2s_tdm.*
ROCKCHIP ISP V1 DRIVER
M: Helen Koike <helen.koike@collabora.com>
M: Dafna Hirschfeld <dafna.hirschfeld@collabora.com>

View File

@ -886,7 +886,7 @@ static struct asoc_simple_card_info fsi_da7210_info = {
.card = "FSIB-DA7210",
.codec = "da7210.0-001a",
.platform = "sh_fsi.0",
.daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
.daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP,
.cpu_dai = {
.name = "fsib-dai",
},

View File

@ -305,7 +305,7 @@ static struct asoc_simple_card_info fsi_ak4642_info = {
.card = "FSIA-AK4642",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
.daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP,
.cpu_dai = {
.name = "fsia-dai",
},

View File

@ -295,6 +295,7 @@ config TURRIS_MOX_RWTM
source "drivers/firmware/arm_ffa/Kconfig"
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/cirrus/Kconfig"
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
source "drivers/firmware/imx/Kconfig"

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
obj-y += arm_ffa/
obj-y += arm_scmi/
obj-y += broadcom/
obj-y += cirrus/
obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-$(CONFIG_EFI) += efi/

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
config CS_DSP
tristate
default n

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
#
obj-$(CONFIG_CS_DSP) += cs_dsp.o

File diff suppressed because it is too large Load Diff

View File

@ -199,7 +199,7 @@ config QCOM_WCNSS_CTRL
firmware to a newly booted WCNSS chip.
config QCOM_APR
tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
tristate "Qualcomm APR/GPR Bus (Asynchronous/Generic Packet Router)"
depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
depends on NET

View File

@ -15,13 +15,23 @@
#include <linux/rpmsg.h>
#include <linux/of.h>
struct apr {
enum {
PR_TYPE_APR = 0,
PR_TYPE_GPR,
};
/* Some random values tbh which does not collide with static modules */
#define GPR_DYNAMIC_PORT_START 0x10000000
#define GPR_DYNAMIC_PORT_END 0x20000000
struct packet_router {
struct rpmsg_endpoint *ch;
struct device *dev;
spinlock_t svcs_lock;
spinlock_t rx_lock;
struct idr svcs_idr;
int dest_domain_id;
int type;
struct pdr_handle *pdr;
struct workqueue_struct *rxwq;
struct work_struct rx_work;
@ -44,26 +54,103 @@ struct apr_rx_buf {
*/
int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt)
{
struct apr *apr = dev_get_drvdata(adev->dev.parent);
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
struct apr_hdr *hdr;
unsigned long flags;
int ret;
spin_lock_irqsave(&adev->lock, flags);
spin_lock_irqsave(&adev->svc.lock, flags);
hdr = &pkt->hdr;
hdr->src_domain = APR_DOMAIN_APPS;
hdr->src_svc = adev->svc_id;
hdr->src_svc = adev->svc.id;
hdr->dest_domain = adev->domain_id;
hdr->dest_svc = adev->svc_id;
hdr->dest_svc = adev->svc.id;
ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size);
spin_unlock_irqrestore(&adev->lock, flags);
spin_unlock_irqrestore(&adev->svc.lock, flags);
return ret ? ret : hdr->pkt_size;
}
EXPORT_SYMBOL_GPL(apr_send_pkt);
void gpr_free_port(gpr_port_t *port)
{
struct packet_router *gpr = port->pr;
unsigned long flags;
spin_lock_irqsave(&gpr->svcs_lock, flags);
idr_remove(&gpr->svcs_idr, port->id);
spin_unlock_irqrestore(&gpr->svcs_lock, flags);
kfree(port);
}
EXPORT_SYMBOL_GPL(gpr_free_port);
gpr_port_t *gpr_alloc_port(struct apr_device *gdev, struct device *dev,
gpr_port_cb cb, void *priv)
{
struct packet_router *pr = dev_get_drvdata(gdev->dev.parent);
gpr_port_t *port;
struct pkt_router_svc *svc;
int id;
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port)
return ERR_PTR(-ENOMEM);
svc = port;
svc->callback = cb;
svc->pr = pr;
svc->priv = priv;
svc->dev = dev;
spin_lock_init(&svc->lock);
spin_lock(&pr->svcs_lock);
id = idr_alloc_cyclic(&pr->svcs_idr, svc, GPR_DYNAMIC_PORT_START,
GPR_DYNAMIC_PORT_END, GFP_ATOMIC);
if (id < 0) {
dev_err(dev, "Unable to allocate dynamic GPR src port\n");
kfree(port);
spin_unlock(&pr->svcs_lock);
return ERR_PTR(id);
}
svc->id = id;
spin_unlock(&pr->svcs_lock);
return port;
}
EXPORT_SYMBOL_GPL(gpr_alloc_port);
static int pkt_router_send_svc_pkt(struct pkt_router_svc *svc, struct gpr_pkt *pkt)
{
struct packet_router *pr = svc->pr;
struct gpr_hdr *hdr;
unsigned long flags;
int ret;
hdr = &pkt->hdr;
spin_lock_irqsave(&svc->lock, flags);
ret = rpmsg_trysend(pr->ch, pkt, hdr->pkt_size);
spin_unlock_irqrestore(&svc->lock, flags);
return ret ? ret : hdr->pkt_size;
}
int gpr_send_pkt(struct apr_device *gdev, struct gpr_pkt *pkt)
{
return pkt_router_send_svc_pkt(&gdev->svc, pkt);
}
EXPORT_SYMBOL_GPL(gpr_send_pkt);
int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt)
{
return pkt_router_send_svc_pkt(port, pkt);
}
EXPORT_SYMBOL_GPL(gpr_send_port_pkt);
static void apr_dev_release(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
@ -74,7 +161,7 @@ static void apr_dev_release(struct device *dev)
static int apr_callback(struct rpmsg_device *rpdev, void *buf,
int len, void *priv, u32 addr)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
struct packet_router *apr = dev_get_drvdata(&rpdev->dev);
struct apr_rx_buf *abuf;
unsigned long flags;
@ -100,11 +187,11 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
return 0;
}
static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
static int apr_do_rx_callback(struct packet_router *apr, struct apr_rx_buf *abuf)
{
uint16_t hdr_size, msg_type, ver, svc_id;
struct apr_device *svc = NULL;
struct pkt_router_svc *svc;
struct apr_device *adev;
struct apr_driver *adrv = NULL;
struct apr_resp_pkt resp;
struct apr_hdr *hdr;
@ -145,12 +232,15 @@ static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
svc_id = hdr->dest_svc;
spin_lock_irqsave(&apr->svcs_lock, flags);
svc = idr_find(&apr->svcs_idr, svc_id);
if (svc && svc->dev.driver)
adrv = to_apr_driver(svc->dev.driver);
if (svc && svc->dev->driver) {
adev = svc_to_apr_device(svc);
adrv = to_apr_driver(adev->dev.driver);
}
spin_unlock_irqrestore(&apr->svcs_lock, flags);
if (!adrv) {
dev_err(apr->dev, "APR: service is not registered\n");
if (!adrv || !adev) {
dev_err(apr->dev, "APR: service is not registered (%d)\n",
svc_id);
return -EINVAL;
}
@ -164,20 +254,82 @@ static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf)
if (resp.payload_size > 0)
resp.payload = buf + hdr_size;
adrv->callback(svc, &resp);
adrv->callback(adev, &resp);
return 0;
}
static int gpr_do_rx_callback(struct packet_router *gpr, struct apr_rx_buf *abuf)
{
uint16_t hdr_size, ver;
struct pkt_router_svc *svc = NULL;
struct gpr_resp_pkt resp;
struct gpr_hdr *hdr;
unsigned long flags;
void *buf = abuf->buf;
int len = abuf->len;
hdr = buf;
ver = hdr->version;
if (ver > GPR_PKT_VER + 1)
return -EINVAL;
hdr_size = hdr->hdr_size;
if (hdr_size < GPR_PKT_HEADER_WORD_SIZE) {
dev_err(gpr->dev, "GPR: Wrong hdr size:%d\n", hdr_size);
return -EINVAL;
}
if (hdr->pkt_size < GPR_PKT_HEADER_BYTE_SIZE || hdr->pkt_size != len) {
dev_err(gpr->dev, "GPR: Wrong packet size\n");
return -EINVAL;
}
resp.hdr = *hdr;
resp.payload_size = hdr->pkt_size - (hdr_size * 4);
/*
* NOTE: hdr_size is not same as GPR_HDR_SIZE as remote can include
* optional headers in to gpr_hdr which should be ignored
*/
if (resp.payload_size > 0)
resp.payload = buf + (hdr_size * 4);
spin_lock_irqsave(&gpr->svcs_lock, flags);
svc = idr_find(&gpr->svcs_idr, hdr->dest_port);
spin_unlock_irqrestore(&gpr->svcs_lock, flags);
if (!svc) {
dev_err(gpr->dev, "GPR: Port(%x) is not registered\n",
hdr->dest_port);
return -EINVAL;
}
if (svc->callback)
svc->callback(&resp, svc->priv, 0);
return 0;
}
static void apr_rxwq(struct work_struct *work)
{
struct apr *apr = container_of(work, struct apr, rx_work);
struct packet_router *apr = container_of(work, struct packet_router, rx_work);
struct apr_rx_buf *abuf, *b;
unsigned long flags;
if (!list_empty(&apr->rx_list)) {
list_for_each_entry_safe(abuf, b, &apr->rx_list, node) {
apr_do_rx_callback(apr, abuf);
switch (apr->type) {
case PR_TYPE_APR:
apr_do_rx_callback(apr, abuf);
break;
case PR_TYPE_GPR:
gpr_do_rx_callback(apr, abuf);
break;
default:
break;
}
spin_lock_irqsave(&apr->rx_lock, flags);
list_del(&abuf->node);
spin_unlock_irqrestore(&apr->rx_lock, flags);
@ -201,7 +353,7 @@ static int apr_device_match(struct device *dev, struct device_driver *drv)
while (id->domain_id != 0 || id->svc_id != 0) {
if (id->domain_id == adev->domain_id &&
id->svc_id == adev->svc_id)
id->svc_id == adev->svc.id)
return 1;
id++;
}
@ -213,22 +365,27 @@ static int apr_device_probe(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv = to_apr_driver(dev->driver);
int ret;
return adrv->probe(adev);
ret = adrv->probe(adev);
if (!ret)
adev->svc.callback = adrv->gpr_callback;
return ret;
}
static void apr_device_remove(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv;
struct apr *apr = dev_get_drvdata(adev->dev.parent);
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
if (dev->driver) {
adrv = to_apr_driver(dev->driver);
if (adrv->remove)
adrv->remove(adev);
spin_lock(&apr->svcs_lock);
idr_remove(&apr->svcs_idr, adev->svc_id);
idr_remove(&apr->svcs_idr, adev->svc.id);
spin_unlock(&apr->svcs_lock);
}
}
@ -255,28 +412,43 @@ struct bus_type aprbus = {
EXPORT_SYMBOL_GPL(aprbus);
static int apr_add_device(struct device *dev, struct device_node *np,
const struct apr_device_id *id)
u32 svc_id, u32 domain_id)
{
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct apr_device *adev = NULL;
struct pkt_router_svc *svc;
int ret;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
spin_lock_init(&adev->lock);
adev->svc_id = svc_id;
svc = &adev->svc;
svc->id = svc_id;
svc->pr = apr;
svc->priv = adev;
svc->dev = dev;
spin_lock_init(&svc->lock);
adev->domain_id = domain_id;
adev->svc_id = id->svc_id;
adev->domain_id = id->domain_id;
adev->version = id->svc_version;
if (np)
snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np);
else
strscpy(adev->name, id->name, APR_NAME_SIZE);
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
id->domain_id, id->svc_id);
switch (apr->type) {
case PR_TYPE_APR:
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
domain_id, svc_id);
break;
case PR_TYPE_GPR:
dev_set_name(&adev->dev, "gprsvc:%s:%x:%x", adev->name,
domain_id, svc_id);
break;
default:
break;
}
adev->dev.bus = &aprbus;
adev->dev.parent = dev;
@ -285,14 +457,13 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->dev.driver = NULL;
spin_lock(&apr->svcs_lock);
idr_alloc(&apr->svcs_idr, adev, id->svc_id,
id->svc_id + 1, GFP_ATOMIC);
idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
spin_unlock(&apr->svcs_lock);
of_property_read_string_index(np, "qcom,protection-domain",
1, &adev->service_path);
dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev));
dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev));
ret = device_register(&adev->dev);
if (ret) {
@ -306,7 +477,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
static int of_apr_add_pd_lookups(struct device *dev)
{
const char *service_name, *service_path;
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct device_node *node;
struct pdr_service *pds;
int ret;
@ -336,13 +507,14 @@ static int of_apr_add_pd_lookups(struct device *dev)
static void of_register_apr_devices(struct device *dev, const char *svc_path)
{
struct apr *apr = dev_get_drvdata(dev);
struct packet_router *apr = dev_get_drvdata(dev);
struct device_node *node;
const char *service_path;
int ret;
for_each_child_of_node(dev->of_node, node) {
struct apr_device_id id = { {0} };
u32 svc_id;
u32 domain_id;
/*
* This function is called with svc_path NULL during
@ -372,13 +544,13 @@ static void of_register_apr_devices(struct device *dev, const char *svc_path)
continue;
}
if (of_property_read_u32(node, "reg", &id.svc_id))
if (of_property_read_u32(node, "reg", &svc_id))
continue;
id.domain_id = apr->dest_domain_id;
domain_id = apr->dest_domain_id;
if (apr_add_device(dev, node, &id))
dev_err(dev, "Failed to add apr %d svc\n", id.svc_id);
if (apr_add_device(dev, node, svc_id, domain_id))
dev_err(dev, "Failed to add apr %d svc\n", svc_id);
}
}
@ -398,7 +570,7 @@ static int apr_remove_device(struct device *dev, void *svc_path)
static void apr_pd_status(int state, char *svc_path, void *priv)
{
struct apr *apr = (struct apr *)priv;
struct packet_router *apr = (struct packet_router *)priv;
switch (state) {
case SERVREG_SERVICE_STATE_UP:
@ -413,16 +585,26 @@ static void apr_pd_status(int state, char *svc_path, void *priv)
static int apr_probe(struct rpmsg_device *rpdev)
{
struct device *dev = &rpdev->dev;
struct apr *apr;
struct packet_router *apr;
int ret;
apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL);
if (!apr)
return -ENOMEM;
ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id);
ret = of_property_read_u32(dev->of_node, "qcom,domain", &apr->dest_domain_id);
if (of_device_is_compatible(dev->of_node, "qcom,gpr")) {
apr->type = PR_TYPE_GPR;
} else {
if (ret) /* try deprecated apr-domain property */
ret = of_property_read_u32(dev->of_node, "qcom,apr-domain",
&apr->dest_domain_id);
apr->type = PR_TYPE_APR;
}
if (ret) {
dev_err(dev, "APR Domain ID not specified in DT\n");
dev_err(dev, "Domain ID not specified in DT\n");
return ret;
}
@ -465,7 +647,7 @@ destroy_wq:
static void apr_remove(struct rpmsg_device *rpdev)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
struct packet_router *apr = dev_get_drvdata(&rpdev->dev);
pdr_handle_release(apr->pdr);
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
@ -502,20 +684,21 @@ void apr_driver_unregister(struct apr_driver *drv)
}
EXPORT_SYMBOL_GPL(apr_driver_unregister);
static const struct of_device_id apr_of_match[] = {
static const struct of_device_id pkt_router_of_match[] = {
{ .compatible = "qcom,apr"},
{ .compatible = "qcom,apr-v2"},
{ .compatible = "qcom,gpr"},
{}
};
MODULE_DEVICE_TABLE(of, apr_of_match);
MODULE_DEVICE_TABLE(of, pkt_router_of_match);
static struct rpmsg_driver apr_driver = {
static struct rpmsg_driver packet_router_driver = {
.probe = apr_probe,
.remove = apr_remove,
.callback = apr_callback,
.drv = {
.name = "qcom,apr",
.of_match_table = apr_of_match,
.of_match_table = pkt_router_of_match,
},
};
@ -525,7 +708,7 @@ static int __init apr_init(void)
ret = bus_register(&aprbus);
if (!ret)
ret = register_rpmsg_driver(&apr_driver);
ret = register_rpmsg_driver(&packet_router_driver);
else
bus_unregister(&aprbus);
@ -535,7 +718,7 @@ static int __init apr_init(void)
static void __exit apr_exit(void)
{
bus_unregister(&aprbus);
unregister_rpmsg_driver(&apr_driver);
unregister_rpmsg_driver(&packet_router_driver);
}
subsys_initcall(apr_init);

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
#ifndef __DT_BINDINGS_QCOM_GPR_H
#define __DT_BINDINGS_QCOM_GPR_H
/* DOMAINS */
#define GPR_DOMAIN_ID_MODEM 1
#define GPR_DOMAIN_ID_ADSP 2
#define GPR_DOMAIN_ID_APPS 3
/* Static Services */
#define GPR_APM_MODULE_IID 1
#define GPR_PRM_MODULE_IID 2
#define GPR_AMDB_MODULE_IID 3
#define GPR_VCPM_MODULE_IID 4
#endif /* __DT_BINDINGS_QCOM_GPR_H */

View File

@ -10,6 +10,37 @@
#define LPASS_DP_RX 5
#define LPASS_CDC_DMA_RX0 6
#define LPASS_CDC_DMA_RX1 7
#define LPASS_CDC_DMA_RX2 8
#define LPASS_CDC_DMA_RX3 9
#define LPASS_CDC_DMA_RX4 10
#define LPASS_CDC_DMA_RX5 11
#define LPASS_CDC_DMA_RX6 12
#define LPASS_CDC_DMA_RX7 13
#define LPASS_CDC_DMA_RX8 14
#define LPASS_CDC_DMA_RX9 15
#define LPASS_CDC_DMA_TX0 16
#define LPASS_CDC_DMA_TX1 17
#define LPASS_CDC_DMA_TX2 18
#define LPASS_CDC_DMA_TX3 19
#define LPASS_CDC_DMA_TX4 20
#define LPASS_CDC_DMA_TX5 21
#define LPASS_CDC_DMA_TX6 22
#define LPASS_CDC_DMA_TX7 23
#define LPASS_CDC_DMA_TX8 24
#define LPASS_CDC_DMA_VA_TX0 25
#define LPASS_CDC_DMA_VA_TX1 26
#define LPASS_CDC_DMA_VA_TX2 27
#define LPASS_CDC_DMA_VA_TX3 28
#define LPASS_CDC_DMA_VA_TX4 29
#define LPASS_CDC_DMA_VA_TX5 30
#define LPASS_CDC_DMA_VA_TX6 31
#define LPASS_CDC_DMA_VA_TX7 32
#define LPASS_CDC_DMA_VA_TX8 33
#define LPASS_MCLK0 0
#endif /* __DT_QCOM_LPASS_H */

View File

@ -2,207 +2,8 @@
#ifndef __DT_BINDINGS_Q6_AFE_H__
#define __DT_BINDINGS_Q6_AFE_H__
/* Audio Front End (AFE) virtual ports IDs */
#define HDMI_RX 1
#define SLIMBUS_0_RX 2
#define SLIMBUS_0_TX 3
#define SLIMBUS_1_RX 4
#define SLIMBUS_1_TX 5
#define SLIMBUS_2_RX 6
#define SLIMBUS_2_TX 7
#define SLIMBUS_3_RX 8
#define SLIMBUS_3_TX 9
#define SLIMBUS_4_RX 10
#define SLIMBUS_4_TX 11
#define SLIMBUS_5_RX 12
#define SLIMBUS_5_TX 13
#define SLIMBUS_6_RX 14
#define SLIMBUS_6_TX 15
#define PRIMARY_MI2S_RX 16
#define PRIMARY_MI2S_TX 17
#define SECONDARY_MI2S_RX 18
#define SECONDARY_MI2S_TX 19
#define TERTIARY_MI2S_RX 20
#define TERTIARY_MI2S_TX 21
#define QUATERNARY_MI2S_RX 22
#define QUATERNARY_MI2S_TX 23
#define PRIMARY_TDM_RX_0 24
#define PRIMARY_TDM_TX_0 25
#define PRIMARY_TDM_RX_1 26
#define PRIMARY_TDM_TX_1 27
#define PRIMARY_TDM_RX_2 28
#define PRIMARY_TDM_TX_2 29
#define PRIMARY_TDM_RX_3 30
#define PRIMARY_TDM_TX_3 31
#define PRIMARY_TDM_RX_4 32
#define PRIMARY_TDM_TX_4 33
#define PRIMARY_TDM_RX_5 34
#define PRIMARY_TDM_TX_5 35
#define PRIMARY_TDM_RX_6 36
#define PRIMARY_TDM_TX_6 37
#define PRIMARY_TDM_RX_7 38
#define PRIMARY_TDM_TX_7 39
#define SECONDARY_TDM_RX_0 40
#define SECONDARY_TDM_TX_0 41
#define SECONDARY_TDM_RX_1 42
#define SECONDARY_TDM_TX_1 43
#define SECONDARY_TDM_RX_2 44
#define SECONDARY_TDM_TX_2 45
#define SECONDARY_TDM_RX_3 46
#define SECONDARY_TDM_TX_3 47
#define SECONDARY_TDM_RX_4 48
#define SECONDARY_TDM_TX_4 49
#define SECONDARY_TDM_RX_5 50
#define SECONDARY_TDM_TX_5 51
#define SECONDARY_TDM_RX_6 52
#define SECONDARY_TDM_TX_6 53
#define SECONDARY_TDM_RX_7 54
#define SECONDARY_TDM_TX_7 55
#define TERTIARY_TDM_RX_0 56
#define TERTIARY_TDM_TX_0 57
#define TERTIARY_TDM_RX_1 58
#define TERTIARY_TDM_TX_1 59
#define TERTIARY_TDM_RX_2 60
#define TERTIARY_TDM_TX_2 61
#define TERTIARY_TDM_RX_3 62
#define TERTIARY_TDM_TX_3 63
#define TERTIARY_TDM_RX_4 64
#define TERTIARY_TDM_TX_4 65
#define TERTIARY_TDM_RX_5 66
#define TERTIARY_TDM_TX_5 67
#define TERTIARY_TDM_RX_6 68
#define TERTIARY_TDM_TX_6 69
#define TERTIARY_TDM_RX_7 70
#define TERTIARY_TDM_TX_7 71
#define QUATERNARY_TDM_RX_0 72
#define QUATERNARY_TDM_TX_0 73
#define QUATERNARY_TDM_RX_1 74
#define QUATERNARY_TDM_TX_1 75
#define QUATERNARY_TDM_RX_2 76
#define QUATERNARY_TDM_TX_2 77
#define QUATERNARY_TDM_RX_3 78
#define QUATERNARY_TDM_TX_3 79
#define QUATERNARY_TDM_RX_4 80
#define QUATERNARY_TDM_TX_4 81
#define QUATERNARY_TDM_RX_5 82
#define QUATERNARY_TDM_TX_5 83
#define QUATERNARY_TDM_RX_6 84
#define QUATERNARY_TDM_TX_6 85
#define QUATERNARY_TDM_RX_7 86
#define QUATERNARY_TDM_TX_7 87
#define QUINARY_TDM_RX_0 88
#define QUINARY_TDM_TX_0 89
#define QUINARY_TDM_RX_1 90
#define QUINARY_TDM_TX_1 91
#define QUINARY_TDM_RX_2 92
#define QUINARY_TDM_TX_2 93
#define QUINARY_TDM_RX_3 94
#define QUINARY_TDM_TX_3 95
#define QUINARY_TDM_RX_4 96
#define QUINARY_TDM_TX_4 97
#define QUINARY_TDM_RX_5 98
#define QUINARY_TDM_TX_5 99
#define QUINARY_TDM_RX_6 100
#define QUINARY_TDM_TX_6 101
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
#define DISPLAY_PORT_RX 104
#define WSA_CODEC_DMA_RX_0 105
#define WSA_CODEC_DMA_TX_0 106
#define WSA_CODEC_DMA_RX_1 107
#define WSA_CODEC_DMA_TX_1 108
#define WSA_CODEC_DMA_TX_2 109
#define VA_CODEC_DMA_TX_0 110
#define VA_CODEC_DMA_TX_1 111
#define VA_CODEC_DMA_TX_2 112
#define RX_CODEC_DMA_RX_0 113
#define TX_CODEC_DMA_TX_0 114
#define RX_CODEC_DMA_RX_1 115
#define TX_CODEC_DMA_TX_1 116
#define RX_CODEC_DMA_RX_2 117
#define TX_CODEC_DMA_TX_2 118
#define RX_CODEC_DMA_RX_3 119
#define TX_CODEC_DMA_TX_3 120
#define RX_CODEC_DMA_RX_4 121
#define TX_CODEC_DMA_TX_4 122
#define RX_CODEC_DMA_RX_5 123
#define TX_CODEC_DMA_TX_5 124
#define RX_CODEC_DMA_RX_6 125
#define RX_CODEC_DMA_RX_7 126
#define QUINARY_MI2S_RX 127
#define QUINARY_MI2S_TX 128
/* This file exists due to backward compatibility reasons, Please do not DELETE! */
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
#define LPASS_CLK_ID_SEC_MI2S_IBIT 3
#define LPASS_CLK_ID_SEC_MI2S_EBIT 4
#define LPASS_CLK_ID_TER_MI2S_IBIT 5
#define LPASS_CLK_ID_TER_MI2S_EBIT 6
#define LPASS_CLK_ID_QUAD_MI2S_IBIT 7
#define LPASS_CLK_ID_QUAD_MI2S_EBIT 8
#define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9
#define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10
#define LPASS_CLK_ID_SPEAKER_I2S_OSR 11
#define LPASS_CLK_ID_QUI_MI2S_IBIT 12
#define LPASS_CLK_ID_QUI_MI2S_EBIT 13
#define LPASS_CLK_ID_SEN_MI2S_IBIT 14
#define LPASS_CLK_ID_SEN_MI2S_EBIT 15
#define LPASS_CLK_ID_INT0_MI2S_IBIT 16
#define LPASS_CLK_ID_INT1_MI2S_IBIT 17
#define LPASS_CLK_ID_INT2_MI2S_IBIT 18
#define LPASS_CLK_ID_INT3_MI2S_IBIT 19
#define LPASS_CLK_ID_INT4_MI2S_IBIT 20
#define LPASS_CLK_ID_INT5_MI2S_IBIT 21
#define LPASS_CLK_ID_INT6_MI2S_IBIT 22
#define LPASS_CLK_ID_QUI_MI2S_OSR 23
#define LPASS_CLK_ID_PRI_PCM_IBIT 24
#define LPASS_CLK_ID_PRI_PCM_EBIT 25
#define LPASS_CLK_ID_SEC_PCM_IBIT 26
#define LPASS_CLK_ID_SEC_PCM_EBIT 27
#define LPASS_CLK_ID_TER_PCM_IBIT 28
#define LPASS_CLK_ID_TER_PCM_EBIT 29
#define LPASS_CLK_ID_QUAD_PCM_IBIT 30
#define LPASS_CLK_ID_QUAD_PCM_EBIT 31
#define LPASS_CLK_ID_QUIN_PCM_IBIT 32
#define LPASS_CLK_ID_QUIN_PCM_EBIT 33
#define LPASS_CLK_ID_QUI_PCM_OSR 34
#define LPASS_CLK_ID_PRI_TDM_IBIT 35
#define LPASS_CLK_ID_PRI_TDM_EBIT 36
#define LPASS_CLK_ID_SEC_TDM_IBIT 37
#define LPASS_CLK_ID_SEC_TDM_EBIT 38
#define LPASS_CLK_ID_TER_TDM_IBIT 39
#define LPASS_CLK_ID_TER_TDM_EBIT 40
#define LPASS_CLK_ID_QUAD_TDM_IBIT 41
#define LPASS_CLK_ID_QUAD_TDM_EBIT 42
#define LPASS_CLK_ID_QUIN_TDM_IBIT 43
#define LPASS_CLK_ID_QUIN_TDM_EBIT 44
#define LPASS_CLK_ID_QUIN_TDM_OSR 45
#define LPASS_CLK_ID_MCLK_1 46
#define LPASS_CLK_ID_MCLK_2 47
#define LPASS_CLK_ID_MCLK_3 48
#define LPASS_CLK_ID_MCLK_4 49
#define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50
#define LPASS_CLK_ID_INT_MCLK_0 51
#define LPASS_CLK_ID_INT_MCLK_1 52
#define LPASS_CLK_ID_MCLK_5 53
#define LPASS_CLK_ID_WSA_CORE_MCLK 54
#define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55
#define LPASS_CLK_ID_VA_CORE_MCLK 56
#define LPASS_CLK_ID_TX_CORE_MCLK 57
#define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58
#define LPASS_CLK_ID_RX_CORE_MCLK 59
#define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60
#define LPASS_CLK_ID_VA_CORE_2X_MCLK 61
#define LPASS_HW_AVTIMER_VOTE 101
#define LPASS_HW_MACRO_VOTE 102
#define LPASS_HW_DCODEC_VOTE 103
#define Q6AFE_MAX_CLK_ID 104
#define LPASS_CLK_ATTRIBUTE_INVALID 0x0
#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2
#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#endif /* __DT_BINDINGS_Q6_AFE_H__ */

View File

@ -0,0 +1,208 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_BINDINGS_Q6_AUDIO_PORTS_H__
#define __DT_BINDINGS_Q6_AUDIO_PORTS_H__
/* LPASS Audio virtual ports IDs */
#define HDMI_RX 1
#define SLIMBUS_0_RX 2
#define SLIMBUS_0_TX 3
#define SLIMBUS_1_RX 4
#define SLIMBUS_1_TX 5
#define SLIMBUS_2_RX 6
#define SLIMBUS_2_TX 7
#define SLIMBUS_3_RX 8
#define SLIMBUS_3_TX 9
#define SLIMBUS_4_RX 10
#define SLIMBUS_4_TX 11
#define SLIMBUS_5_RX 12
#define SLIMBUS_5_TX 13
#define SLIMBUS_6_RX 14
#define SLIMBUS_6_TX 15
#define PRIMARY_MI2S_RX 16
#define PRIMARY_MI2S_TX 17
#define SECONDARY_MI2S_RX 18
#define SECONDARY_MI2S_TX 19
#define TERTIARY_MI2S_RX 20
#define TERTIARY_MI2S_TX 21
#define QUATERNARY_MI2S_RX 22
#define QUATERNARY_MI2S_TX 23
#define PRIMARY_TDM_RX_0 24
#define PRIMARY_TDM_TX_0 25
#define PRIMARY_TDM_RX_1 26
#define PRIMARY_TDM_TX_1 27
#define PRIMARY_TDM_RX_2 28
#define PRIMARY_TDM_TX_2 29
#define PRIMARY_TDM_RX_3 30
#define PRIMARY_TDM_TX_3 31
#define PRIMARY_TDM_RX_4 32
#define PRIMARY_TDM_TX_4 33
#define PRIMARY_TDM_RX_5 34
#define PRIMARY_TDM_TX_5 35
#define PRIMARY_TDM_RX_6 36
#define PRIMARY_TDM_TX_6 37
#define PRIMARY_TDM_RX_7 38
#define PRIMARY_TDM_TX_7 39
#define SECONDARY_TDM_RX_0 40
#define SECONDARY_TDM_TX_0 41
#define SECONDARY_TDM_RX_1 42
#define SECONDARY_TDM_TX_1 43
#define SECONDARY_TDM_RX_2 44
#define SECONDARY_TDM_TX_2 45
#define SECONDARY_TDM_RX_3 46
#define SECONDARY_TDM_TX_3 47
#define SECONDARY_TDM_RX_4 48
#define SECONDARY_TDM_TX_4 49
#define SECONDARY_TDM_RX_5 50
#define SECONDARY_TDM_TX_5 51
#define SECONDARY_TDM_RX_6 52
#define SECONDARY_TDM_TX_6 53
#define SECONDARY_TDM_RX_7 54
#define SECONDARY_TDM_TX_7 55
#define TERTIARY_TDM_RX_0 56
#define TERTIARY_TDM_TX_0 57
#define TERTIARY_TDM_RX_1 58
#define TERTIARY_TDM_TX_1 59
#define TERTIARY_TDM_RX_2 60
#define TERTIARY_TDM_TX_2 61
#define TERTIARY_TDM_RX_3 62
#define TERTIARY_TDM_TX_3 63
#define TERTIARY_TDM_RX_4 64
#define TERTIARY_TDM_TX_4 65
#define TERTIARY_TDM_RX_5 66
#define TERTIARY_TDM_TX_5 67
#define TERTIARY_TDM_RX_6 68
#define TERTIARY_TDM_TX_6 69
#define TERTIARY_TDM_RX_7 70
#define TERTIARY_TDM_TX_7 71
#define QUATERNARY_TDM_RX_0 72
#define QUATERNARY_TDM_TX_0 73
#define QUATERNARY_TDM_RX_1 74
#define QUATERNARY_TDM_TX_1 75
#define QUATERNARY_TDM_RX_2 76
#define QUATERNARY_TDM_TX_2 77
#define QUATERNARY_TDM_RX_3 78
#define QUATERNARY_TDM_TX_3 79
#define QUATERNARY_TDM_RX_4 80
#define QUATERNARY_TDM_TX_4 81
#define QUATERNARY_TDM_RX_5 82
#define QUATERNARY_TDM_TX_5 83
#define QUATERNARY_TDM_RX_6 84
#define QUATERNARY_TDM_TX_6 85
#define QUATERNARY_TDM_RX_7 86
#define QUATERNARY_TDM_TX_7 87
#define QUINARY_TDM_RX_0 88
#define QUINARY_TDM_TX_0 89
#define QUINARY_TDM_RX_1 90
#define QUINARY_TDM_TX_1 91
#define QUINARY_TDM_RX_2 92
#define QUINARY_TDM_TX_2 93
#define QUINARY_TDM_RX_3 94
#define QUINARY_TDM_TX_3 95
#define QUINARY_TDM_RX_4 96
#define QUINARY_TDM_TX_4 97
#define QUINARY_TDM_RX_5 98
#define QUINARY_TDM_TX_5 99
#define QUINARY_TDM_RX_6 100
#define QUINARY_TDM_TX_6 101
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
#define DISPLAY_PORT_RX 104
#define WSA_CODEC_DMA_RX_0 105
#define WSA_CODEC_DMA_TX_0 106
#define WSA_CODEC_DMA_RX_1 107
#define WSA_CODEC_DMA_TX_1 108
#define WSA_CODEC_DMA_TX_2 109
#define VA_CODEC_DMA_TX_0 110
#define VA_CODEC_DMA_TX_1 111
#define VA_CODEC_DMA_TX_2 112
#define RX_CODEC_DMA_RX_0 113
#define TX_CODEC_DMA_TX_0 114
#define RX_CODEC_DMA_RX_1 115
#define TX_CODEC_DMA_TX_1 116
#define RX_CODEC_DMA_RX_2 117
#define TX_CODEC_DMA_TX_2 118
#define RX_CODEC_DMA_RX_3 119
#define TX_CODEC_DMA_TX_3 120
#define RX_CODEC_DMA_RX_4 121
#define TX_CODEC_DMA_TX_4 122
#define RX_CODEC_DMA_RX_5 123
#define TX_CODEC_DMA_TX_5 124
#define RX_CODEC_DMA_RX_6 125
#define RX_CODEC_DMA_RX_7 126
#define QUINARY_MI2S_RX 127
#define QUINARY_MI2S_TX 128
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
#define LPASS_CLK_ID_SEC_MI2S_IBIT 3
#define LPASS_CLK_ID_SEC_MI2S_EBIT 4
#define LPASS_CLK_ID_TER_MI2S_IBIT 5
#define LPASS_CLK_ID_TER_MI2S_EBIT 6
#define LPASS_CLK_ID_QUAD_MI2S_IBIT 7
#define LPASS_CLK_ID_QUAD_MI2S_EBIT 8
#define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9
#define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10
#define LPASS_CLK_ID_SPEAKER_I2S_OSR 11
#define LPASS_CLK_ID_QUI_MI2S_IBIT 12
#define LPASS_CLK_ID_QUI_MI2S_EBIT 13
#define LPASS_CLK_ID_SEN_MI2S_IBIT 14
#define LPASS_CLK_ID_SEN_MI2S_EBIT 15
#define LPASS_CLK_ID_INT0_MI2S_IBIT 16
#define LPASS_CLK_ID_INT1_MI2S_IBIT 17
#define LPASS_CLK_ID_INT2_MI2S_IBIT 18
#define LPASS_CLK_ID_INT3_MI2S_IBIT 19
#define LPASS_CLK_ID_INT4_MI2S_IBIT 20
#define LPASS_CLK_ID_INT5_MI2S_IBIT 21
#define LPASS_CLK_ID_INT6_MI2S_IBIT 22
#define LPASS_CLK_ID_QUI_MI2S_OSR 23
#define LPASS_CLK_ID_PRI_PCM_IBIT 24
#define LPASS_CLK_ID_PRI_PCM_EBIT 25
#define LPASS_CLK_ID_SEC_PCM_IBIT 26
#define LPASS_CLK_ID_SEC_PCM_EBIT 27
#define LPASS_CLK_ID_TER_PCM_IBIT 28
#define LPASS_CLK_ID_TER_PCM_EBIT 29
#define LPASS_CLK_ID_QUAD_PCM_IBIT 30
#define LPASS_CLK_ID_QUAD_PCM_EBIT 31
#define LPASS_CLK_ID_QUIN_PCM_IBIT 32
#define LPASS_CLK_ID_QUIN_PCM_EBIT 33
#define LPASS_CLK_ID_QUI_PCM_OSR 34
#define LPASS_CLK_ID_PRI_TDM_IBIT 35
#define LPASS_CLK_ID_PRI_TDM_EBIT 36
#define LPASS_CLK_ID_SEC_TDM_IBIT 37
#define LPASS_CLK_ID_SEC_TDM_EBIT 38
#define LPASS_CLK_ID_TER_TDM_IBIT 39
#define LPASS_CLK_ID_TER_TDM_EBIT 40
#define LPASS_CLK_ID_QUAD_TDM_IBIT 41
#define LPASS_CLK_ID_QUAD_TDM_EBIT 42
#define LPASS_CLK_ID_QUIN_TDM_IBIT 43
#define LPASS_CLK_ID_QUIN_TDM_EBIT 44
#define LPASS_CLK_ID_QUIN_TDM_OSR 45
#define LPASS_CLK_ID_MCLK_1 46
#define LPASS_CLK_ID_MCLK_2 47
#define LPASS_CLK_ID_MCLK_3 48
#define LPASS_CLK_ID_MCLK_4 49
#define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50
#define LPASS_CLK_ID_INT_MCLK_0 51
#define LPASS_CLK_ID_INT_MCLK_1 52
#define LPASS_CLK_ID_MCLK_5 53
#define LPASS_CLK_ID_WSA_CORE_MCLK 54
#define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55
#define LPASS_CLK_ID_VA_CORE_MCLK 56
#define LPASS_CLK_ID_TX_CORE_MCLK 57
#define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58
#define LPASS_CLK_ID_RX_CORE_MCLK 59
#define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60
#define LPASS_CLK_ID_VA_CORE_2X_MCLK 61
#define LPASS_HW_AVTIMER_VOTE 101
#define LPASS_HW_MACRO_VOTE 102
#define LPASS_HW_DCODEC_VOTE 103
#define Q6AFE_MAX_CLK_ID 104
#define LPASS_CLK_ATTRIBUTE_INVALID 0x0
#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2
#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3
#endif /* __DT_BINDINGS_Q6_AUDIO_PORTS_H__ */

View File

@ -0,0 +1,242 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cs_dsp.h -- Cirrus Logic DSP firmware support
*
* Based on sound/soc/codecs/wm_adsp.h
*
* Copyright 2012 Wolfson Microelectronics plc
* Copyright (C) 2015-2021 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef __CS_DSP_H
#define __CS_DSP_H
#define CS_ADSP2_REGION_0 BIT(0)
#define CS_ADSP2_REGION_1 BIT(1)
#define CS_ADSP2_REGION_2 BIT(2)
#define CS_ADSP2_REGION_3 BIT(3)
#define CS_ADSP2_REGION_4 BIT(4)
#define CS_ADSP2_REGION_5 BIT(5)
#define CS_ADSP2_REGION_6 BIT(6)
#define CS_ADSP2_REGION_7 BIT(7)
#define CS_ADSP2_REGION_8 BIT(8)
#define CS_ADSP2_REGION_9 BIT(9)
#define CS_ADSP2_REGION_1_9 (CS_ADSP2_REGION_1 | \
CS_ADSP2_REGION_2 | CS_ADSP2_REGION_3 | \
CS_ADSP2_REGION_4 | CS_ADSP2_REGION_5 | \
CS_ADSP2_REGION_6 | CS_ADSP2_REGION_7 | \
CS_ADSP2_REGION_8 | CS_ADSP2_REGION_9)
#define CS_ADSP2_REGION_ALL (CS_ADSP2_REGION_0 | CS_ADSP2_REGION_1_9)
#define CS_DSP_DATA_WORD_SIZE 3
#define CS_DSP_ACKED_CTL_TIMEOUT_MS 100
#define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10
#define CS_DSP_ACKED_CTL_MIN_VALUE 0
#define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF
/**
* struct cs_dsp_region - Describes a logical memory region in DSP address space
* @type: Memory region type
* @base: Address of region
*/
struct cs_dsp_region {
int type;
unsigned int base;
};
/**
* struct cs_dsp_alg_region - Describes a logical algorithm region in DSP address space
* @list: List node for internal use
* @alg: Algorithm id
* @type: Memory region type
* @base: Address of region
*/
struct cs_dsp_alg_region {
struct list_head list;
unsigned int alg;
int type;
unsigned int base;
};
/**
* struct cs_dsp_coeff_ctl - Describes a coefficient control
* @fw_name: Name of the firmware
* @subname: Name of the control parsed from the WMFW
* @subname_len: Length of subname
* @alg_region: Logical region associated with this control
* @dsp: DSP instance associated with this control
* @enabled: Flag indicating whether control is enabled
* @list: List node for internal use
* @cache: Cached value of the control
* @offset: Offset of control within alg_region
* @len: Length of the cached value
* @set: Flag indicating the value has been written by the user
* @flags: Bitfield of WMFW_CTL_FLAG_ control flags defined in wmfw.h
* @type: One of the WMFW_CTL_TYPE_ control types defined in wmfw.h
* @priv: For use by the client
*/
struct cs_dsp_coeff_ctl {
const char *fw_name;
/* Subname is needed to match with firmware */
const char *subname;
unsigned int subname_len;
struct cs_dsp_alg_region alg_region;
struct cs_dsp *dsp;
unsigned int enabled:1;
struct list_head list;
void *cache;
unsigned int offset;
size_t len;
unsigned int set:1;
unsigned int flags;
unsigned int type;
void *priv;
};
struct cs_dsp_ops;
struct cs_dsp_client_ops;
/**
* struct cs_dsp - Configuration and state of a Cirrus Logic DSP
* @name: The name of the DSP instance
* @rev: Revision of the DSP
* @num: DSP instance number
* @type: Type of DSP
* @dev: Driver model representation of the device
* @regmap: Register map of the device
* @ops: Function pointers for internal callbacks
* @client_ops: Function pointers for client callbacks
* @base: Address of the DSP registers
* @base_sysinfo: Address of the sysinfo register (Halo only)
* @sysclk_reg: Address of the sysclk register (ADSP1 only)
* @sysclk_mask: Mask of frequency bits within sysclk register (ADSP1 only)
* @sysclk_shift: Shift of frequency bits within sysclk register (ADSP1 only)
* @alg_regions: List of currently loaded algorithm regions
* @fw_file_name: Filename of the current firmware
* @fw_name: Name of the current firmware
* @fw_id: ID of the current firmware, obtained from the wmfw
* @fw_id_version: Version of the firmware, obtained from the wmfw
* @fw_vendor_id: Vendor of the firmware, obtained from the wmfw
* @mem: DSP memory region descriptions
* @num_mems: Number of memory regions in this DSP
* @fw_ver: Version of the wmfw file format
* @booted: Flag indicating DSP has been configured
* @running: Flag indicating DSP is executing firmware
* @ctl_list: Controls defined within the loaded DSP firmware
* @lock_regions: Enable MPU traps on specified memory regions
* @pwr_lock: Lock used to serialize accesses
* @debugfs_root: Debugfs directory for this DSP instance
* @wmfw_file_name: Filename of the currently loaded firmware
* @bin_file_name: Filename of the currently loaded coefficients
*/
struct cs_dsp {
const char *name;
int rev;
int num;
int type;
struct device *dev;
struct regmap *regmap;
const struct cs_dsp_ops *ops;
const struct cs_dsp_client_ops *client_ops;
unsigned int base;
unsigned int base_sysinfo;
unsigned int sysclk_reg;
unsigned int sysclk_mask;
unsigned int sysclk_shift;
struct list_head alg_regions;
const char *fw_name;
unsigned int fw_id;
unsigned int fw_id_version;
unsigned int fw_vendor_id;
const struct cs_dsp_region *mem;
int num_mems;
int fw_ver;
bool booted;
bool running;
struct list_head ctl_list;
struct mutex pwr_lock;
unsigned int lock_regions;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
char *wmfw_file_name;
char *bin_file_name;
#endif
};
/**
* struct cs_dsp_client_ops - client callbacks
* @control_add: Called under the pwr_lock when a control is created
* @control_remove: Called under the pwr_lock when a control is destroyed
* @post_run: Called under the pwr_lock by cs_dsp_run()
* @post_stop: Called under the pwr_lock by cs_dsp_stop()
* @watchdog_expired: Called when a watchdog expiry is detected
*
* These callbacks give the cs_dsp client an opportunity to respond to events
* or to perform actions atomically.
*/
struct cs_dsp_client_ops {
int (*control_add)(struct cs_dsp_coeff_ctl *ctl);
void (*control_remove)(struct cs_dsp_coeff_ctl *ctl);
int (*post_run)(struct cs_dsp *dsp);
void (*post_stop)(struct cs_dsp *dsp);
void (*watchdog_expired)(struct cs_dsp *dsp);
};
int cs_dsp_adsp1_init(struct cs_dsp *dsp);
int cs_dsp_adsp2_init(struct cs_dsp *dsp);
int cs_dsp_halo_init(struct cs_dsp *dsp);
int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
const struct firmware *wmfw_firmware, char *wmfw_filename,
const struct firmware *coeff_firmware, char *coeff_filename,
const char *fw_name);
void cs_dsp_adsp1_power_down(struct cs_dsp *dsp);
int cs_dsp_power_up(struct cs_dsp *dsp,
const struct firmware *wmfw_firmware, char *wmfw_filename,
const struct firmware *coeff_firmware, char *coeff_filename,
const char *fw_name);
void cs_dsp_power_down(struct cs_dsp *dsp);
int cs_dsp_run(struct cs_dsp *dsp);
void cs_dsp_stop(struct cs_dsp *dsp);
void cs_dsp_remove(struct cs_dsp *dsp);
int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq);
void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp);
void cs_dsp_halo_bus_error(struct cs_dsp *dsp);
void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp);
void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root);
void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp);
int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id);
int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, const void *buf, size_t len);
int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len);
struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type,
unsigned int alg);
int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr,
unsigned int num_words, __be32 *data);
int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data);
int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data);
void cs_dsp_remove_padding(u32 *buf, int nwords);
struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
int type, unsigned int id);
const char *cs_dsp_mem_region_name(unsigned int type);
#endif

View File

@ -23,10 +23,12 @@
#define WMFW_CTL_FLAG_WRITEABLE 0x0002
#define WMFW_CTL_FLAG_READABLE 0x0001
#define WMFW_CTL_TYPE_BYTES 0x0004 /* byte control */
/* Non-ALSA coefficient types start at 0x1000 */
#define WMFW_CTL_TYPE_ACKED ((__force snd_ctl_elem_type_t)0x1000) /* acked control */
#define WMFW_CTL_TYPE_HOSTEVENT ((__force snd_ctl_elem_type_t)0x1001) /* event control */
#define WMFW_CTL_TYPE_HOST_BUFFER ((__force snd_ctl_elem_type_t)0x1002) /* host buffer pointer */
#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */
#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */
#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
struct wmfw_header {
char magic[4];

View File

@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <dt-bindings/soc/qcom,apr.h>
#include <dt-bindings/soc/qcom,gpr.h>
extern struct bus_type aprbus;
@ -75,10 +76,65 @@ struct apr_resp_pkt {
int payload_size;
};
struct gpr_hdr {
uint32_t version:4;
uint32_t hdr_size:4;
uint32_t pkt_size:24;
uint32_t dest_domain:8;
uint32_t src_domain:8;
uint32_t reserved:16;
uint32_t src_port;
uint32_t dest_port;
uint32_t token;
uint32_t opcode;
} __packed;
struct gpr_pkt {
struct gpr_hdr hdr;
uint32_t payload[];
};
struct gpr_resp_pkt {
struct gpr_hdr hdr;
void *payload;
int payload_size;
};
#define GPR_HDR_SIZE sizeof(struct gpr_hdr)
#define GPR_PKT_VER 0x0
#define GPR_PKT_HEADER_WORD_SIZE ((sizeof(struct gpr_pkt) + 3) >> 2)
#define GPR_PKT_HEADER_BYTE_SIZE (GPR_PKT_HEADER_WORD_SIZE << 2)
#define GPR_BASIC_RSP_RESULT 0x02001005
struct gpr_ibasic_rsp_result_t {
uint32_t opcode;
uint32_t status;
};
#define GPR_BASIC_EVT_ACCEPTED 0x02001006
struct gpr_ibasic_rsp_accepted_t {
uint32_t opcode;
};
/* Bits 0 to 15 -- Minor version, Bits 16 to 31 -- Major version */
#define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF)
#define APR_SVC_MINOR_VERSION(v) (v & 0xFF)
typedef int (*gpr_port_cb) (struct gpr_resp_pkt *d, void *priv, int op);
struct packet_router;
struct pkt_router_svc {
struct device *dev;
gpr_port_cb callback;
struct packet_router *pr;
spinlock_t lock;
int id;
void *priv;
};
typedef struct pkt_router_svc gpr_port_t;
struct apr_device {
struct device dev;
uint16_t svc_id;
@ -86,21 +142,26 @@ struct apr_device {
uint32_t version;
char name[APR_NAME_SIZE];
const char *service_path;
spinlock_t lock;
struct pkt_router_svc svc;
struct list_head node;
};
typedef struct apr_device gpr_device_t;
#define to_apr_device(d) container_of(d, struct apr_device, dev)
#define svc_to_apr_device(d) container_of(d, struct apr_device, svc)
struct apr_driver {
int (*probe)(struct apr_device *sl);
int (*remove)(struct apr_device *sl);
int (*callback)(struct apr_device *a,
struct apr_resp_pkt *d);
int (*gpr_callback)(struct gpr_resp_pkt *d, void *data, int op);
struct device_driver driver;
const struct apr_device_id *id_table;
};
typedef struct apr_driver gpr_driver_t;
#define to_apr_driver(d) container_of(d, struct apr_driver, driver)
/*
@ -123,7 +184,14 @@ void apr_driver_unregister(struct apr_driver *drv);
#define module_apr_driver(__apr_driver) \
module_driver(__apr_driver, apr_driver_register, \
apr_driver_unregister)
#define module_gpr_driver(__gpr_driver) module_apr_driver(__gpr_driver)
int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt);
gpr_port_t *gpr_alloc_port(gpr_device_t *gdev, struct device *dev,
gpr_port_cb cb, void *priv);
void gpr_free_port(gpr_port_t *port);
int gpr_send_port_pkt(gpr_port_t *port, struct gpr_pkt *pkt);
int gpr_send_pkt(gpr_device_t *gdev, struct gpr_pkt *pkt);
#endif /* __QCOM_APR_H_ */

34
include/sound/cs35l41.h Normal file
View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0
*
* linux/sound/cs35l41.h -- Platform data for CS35L41
*
* Copyright (c) 2017-2021 Cirrus Logic Inc.
*
* Author: David Rhodes <david.rhodes@cirrus.com>
*/
#ifndef __CS35L41_H
#define __CS35L41_H
enum cs35l41_clk_ids {
CS35L41_CLKID_SCLK = 0,
CS35L41_CLKID_LRCLK = 1,
CS35L41_CLKID_MCLK = 4,
};
struct cs35l41_irq_cfg {
bool irq_pol_inv;
bool irq_out_en;
int irq_src_sel;
};
struct cs35l41_platform_data {
int bst_ind;
int bst_ipk;
int bst_cap;
int dout_hiz;
struct cs35l41_irq_cfg irq_config1;
struct cs35l41_irq_cfg irq_config2;
};
#endif /* __CS35L41_H */

View File

@ -9,6 +9,27 @@
#include <sound/simple_card_utils.h>
typedef int (*GRAPH2_CUSTOM)(struct asoc_simple_priv *priv,
struct device_node *lnk,
struct link_info *li);
struct graph2_custom_hooks {
int (*hook_pre)(struct asoc_simple_priv *priv);
int (*hook_post)(struct asoc_simple_priv *priv);
GRAPH2_CUSTOM custom_normal;
GRAPH2_CUSTOM custom_dpcm;
GRAPH2_CUSTOM custom_c2c;
};
int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
struct graph2_custom_hooks *hooks);
int audio_graph2_link_normal(struct asoc_simple_priv *priv,
struct device_node *lnk, struct link_info *li);
int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
struct device_node *lnk, struct link_info *li);
int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
struct device_node *lnk, struct link_info *li);
#endif /* __GRAPH_CARD_H */

View File

@ -88,6 +88,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream,
int type);
void snd_hdac_ext_stream_release(struct hdac_ext_stream *azx_dev, int type);
void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
struct hdac_ext_stream *azx_dev, bool decouple);
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
struct hdac_ext_stream *azx_dev, bool decouple);
void snd_hdac_ext_stop_streams(struct hdac_bus *bus);

View File

@ -9,16 +9,20 @@
#ifndef __SOUND_MEMALLOC_H
#define __SOUND_MEMALLOC_H
#include <linux/dma-direction.h>
#include <asm/page.h>
struct device;
struct vm_area_struct;
struct sg_table;
/*
* buffer device info
*/
struct snd_dma_device {
int type; /* SNDRV_DMA_TYPE_XXX */
enum dma_data_direction dir; /* DMA direction */
bool need_sync; /* explicit sync needed? */
struct device *dev; /* generic device */
};
@ -32,19 +36,21 @@ struct snd_dma_device {
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
#define SNDRV_DMA_TYPE_DEV_WC 5 /* continuous write-combined */
#ifdef CONFIG_SND_DMA_SGBUF
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
#define SNDRV_DMA_TYPE_DEV_WC_SG 6 /* SG write-combined */
#else
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
#define SNDRV_DMA_TYPE_DEV_WC_SG SNDRV_DMA_TYPE_DEV_WC
#endif
#ifdef CONFIG_GENERIC_ALLOCATOR
#define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */
#else
#define SNDRV_DMA_TYPE_DEV_IRAM SNDRV_DMA_TYPE_DEV
#endif
#define SNDRV_DMA_TYPE_VMALLOC 7 /* vmalloc'ed buffer */
#define SNDRV_DMA_TYPE_NONCONTIG 8 /* non-coherent SG buffer */
#define SNDRV_DMA_TYPE_NONCOHERENT 9 /* non-coherent buffer */
#ifdef CONFIG_SND_DMA_SGBUF
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_NONCONTIG
#define SNDRV_DMA_TYPE_DEV_WC_SG 6 /* SG write-combined */
#else
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
#define SNDRV_DMA_TYPE_DEV_WC_SG SNDRV_DMA_TYPE_DEV_WC
#endif
/*
* info for buffer allocation
@ -66,22 +72,52 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
}
/* allocate/release a buffer */
int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
int snd_dma_alloc_dir_pages(int type, struct device *dev,
enum dma_data_direction dir, size_t size,
struct snd_dma_buffer *dmab);
static inline int snd_dma_alloc_pages(int type, struct device *dev,
size_t size, struct snd_dma_buffer *dmab)
{
return snd_dma_alloc_dir_pages(type, dev, DMA_BIDIRECTIONAL, size, dmab);
}
int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
void snd_dma_free_pages(struct snd_dma_buffer *dmab);
int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area);
enum snd_dma_sync_mode { SNDRV_DMA_SYNC_CPU, SNDRV_DMA_SYNC_DEVICE };
#ifdef CONFIG_HAS_DMA
void snd_dma_buffer_sync(struct snd_dma_buffer *dmab,
enum snd_dma_sync_mode mode);
#else
static inline void snd_dma_buffer_sync(struct snd_dma_buffer *dmab,
enum snd_dma_sync_mode mode) {}
#endif
dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset);
struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset);
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
/* device-managed memory allocator */
struct snd_dma_buffer *snd_devm_alloc_pages(struct device *dev, int type,
size_t size);
struct snd_dma_buffer *snd_devm_alloc_dir_pages(struct device *dev, int type,
enum dma_data_direction dir,
size_t size);
static inline struct snd_dma_buffer *
snd_devm_alloc_pages(struct device *dev, int type, size_t size)
{
return snd_devm_alloc_dir_pages(dev, type, DMA_BIDIRECTIONAL, size);
}
static inline struct sg_table *
snd_dma_noncontig_sg_table(struct snd_dma_buffer *dmab)
{
return dmab->private_data;
}
#endif /* __SOUND_MEMALLOC_H */

48
include/sound/rt5682s.h Normal file
View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/sound/rt5682s.h -- Platform data for RT5682I-VS
*
* Copyright 2021 Realtek Microelectronics
*/
#ifndef __LINUX_SND_RT5682S_H
#define __LINUX_SND_RT5682S_H
enum rt5682s_dmic1_data_pin {
RT5682S_DMIC1_DATA_NULL,
RT5682S_DMIC1_DATA_GPIO2,
RT5682S_DMIC1_DATA_GPIO5,
};
enum rt5682s_dmic1_clk_pin {
RT5682S_DMIC1_CLK_NULL,
RT5682S_DMIC1_CLK_GPIO1,
RT5682S_DMIC1_CLK_GPIO3,
};
enum rt5682s_jd_src {
RT5682S_JD_NULL,
RT5682S_JD1,
};
enum rt5682s_dai_clks {
RT5682S_DAI_WCLK_IDX,
RT5682S_DAI_BCLK_IDX,
RT5682S_DAI_NUM_CLKS,
};
struct rt5682s_platform_data {
int ldo1_en; /* GPIO for LDO1_EN */
enum rt5682s_dmic1_data_pin dmic1_data_pin;
enum rt5682s_dmic1_clk_pin dmic1_clk_pin;
enum rt5682s_jd_src jd_src;
unsigned int dmic_clk_rate;
unsigned int dmic_delay;
bool dmic_clk_driving_high;
const char *dai_clk_names[RT5682S_DAI_NUM_CLKS];
};
#endif

View File

@ -42,6 +42,7 @@ struct prop_nums {
int cpus;
int codecs;
int platforms;
int c2c;
};
struct asoc_simple_priv {
@ -54,6 +55,7 @@ struct asoc_simple_priv {
struct snd_soc_dai_link_component *platforms;
struct asoc_simple_data adata;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_pcm_stream *c2c_conf;
struct prop_nums num;
unsigned int mclk_fs;
} *dai_props;
@ -64,6 +66,7 @@ struct asoc_simple_priv {
struct snd_soc_dai_link_component *dlcs;
struct snd_soc_dai_link_component dummy;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_pcm_stream *c2c_conf;
struct gpio_desc *pa_gpio;
const struct snd_soc_ops *ops;
unsigned int dpcm_selectable:1;
@ -115,7 +118,7 @@ struct asoc_simple_priv {
((codec) = simple_props_to_dai_codec(props, i)); \
(i)++)
#define SNDRV_MAX_LINKS 128
#define SNDRV_MAX_LINKS 512
struct link_info {
int link; /* number of link */
@ -180,6 +183,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
int asoc_simple_remove(struct platform_device *pdev);
int asoc_graph_card_probe(struct snd_soc_card *card);
int asoc_graph_is_ports0(struct device_node *port);
#ifdef DEBUG
static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,

View File

@ -129,6 +129,8 @@ struct snd_soc_acpi_link_adr {
* all firmware/topology related fields.
*
* @id: ACPI ID (usually the codec's) used to find a matching machine driver.
* @comp_ids: list of compatible audio codecs using the same machine driver,
* firmware and topology
* @link_mask: describes required board layout, e.g. for SoundWire.
* @links: array of link _ADR descriptors, null terminated.
* @drv_name: machine driver name
@ -146,6 +148,7 @@ struct snd_soc_acpi_link_adr {
/* Descriptor for SST ASoC machine driver */
struct snd_soc_acpi_mach {
const u8 id[ACPI_ID_LEN];
const struct snd_soc_acpi_codecs *comp_ids;
const u32 link_mask;
const struct snd_soc_acpi_link_adr *links;
const char *drv_name;

View File

@ -220,17 +220,15 @@ struct snd_soc_component {
int (*init)(struct snd_soc_component *component);
/* function mark */
struct snd_pcm_substream *mark_module;
void *mark_module;
struct snd_pcm_substream *mark_open;
struct snd_pcm_substream *mark_hw_params;
struct snd_pcm_substream *mark_trigger;
struct snd_compr_stream *mark_compr_open;
void *mark_pm;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
const char *debugfs_prefix;
#endif
};
#define for_each_component_dais(component, dai)\
@ -335,6 +333,11 @@ static inline int snd_soc_component_cache_sync(
return regcache_sync(component->regmap);
}
static inline int snd_soc_component_is_codec(struct snd_soc_component *component)
{
return component->driver->non_legacy_dai_naming;
}
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux);
int snd_soc_component_init(struct snd_soc_component *component);
@ -391,15 +394,13 @@ void snd_soc_component_exit_regmap(struct snd_soc_component *component);
#define snd_soc_component_module_get_when_open(component, substream) \
snd_soc_component_module_get(component, substream, 1)
int snd_soc_component_module_get(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
int upon_open);
void *mark, int upon_open);
#define snd_soc_component_module_put_when_remove(component) \
snd_soc_component_module_put(component, NULL, 0, 0)
#define snd_soc_component_module_put_when_close(component, substream, rollback) \
snd_soc_component_module_put(component, substream, 1, rollback)
void snd_soc_component_module_put(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
int upon_open, int rollback);
void *mark, int upon_open, int rollback);
static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c,
void *data)
@ -455,8 +456,10 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component,
int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
const struct of_phandle_args *args,
const char **dai_name);
int snd_soc_component_compr_open(struct snd_compr_stream *cstream);
void snd_soc_component_compr_free(struct snd_compr_stream *cstream,
int snd_soc_component_compr_open(struct snd_soc_component *component,
struct snd_compr_stream *cstream);
void snd_soc_component_compr_free(struct snd_soc_component *component,
struct snd_compr_stream *cstream,
int rollback);
int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd);
int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream,

View File

@ -159,6 +159,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd);
int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
int event);
bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir);
#define dpcm_be_dai_startup_rollback(fe, stream, last) \
dpcm_be_dai_stop(fe, stream, 0, last)

View File

@ -151,7 +151,7 @@ struct snd_soc_tplg_ops {
struct snd_soc_tplg_hdr *);
/* completion - called at completion of firmware loading */
void (*complete)(struct snd_soc_component *);
int (*complete)(struct snd_soc_component *comp);
/* manifest - optional to inform component of manifest */
int (*manifest)(struct snd_soc_component *, int index,
@ -188,8 +188,7 @@ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
#else
static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp,
u32 index)
static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
{
return 0;
}

View File

@ -74,11 +74,6 @@ struct sof_dev_desc {
int resindex_pcicfg_base;
int resindex_imr_base;
int irqindex_host_ipc;
int resindex_dma_base;
/* DMA only valid when resindex_dma_base != -1*/
int dma_engine;
int dma_size;
/* IPC timeouts in ms */
int ipc_timeout;

View File

@ -48,6 +48,10 @@
#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4)
/* bclk idle */
#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5)
/* mclk early start */
#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES BIT(6)
/* bclk early start */
#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES BIT(7)
/* DMIC max. four controllers for eight microphone channels */
#define SOF_DAI_INTEL_DMIC_NUM_CTRL 4

View File

@ -50,6 +50,13 @@
#define SOF_DAI_FMT_INV_MASK 0x0f00
#define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000
/* DAI_CONFIG flags */
#define SOF_DAI_CONFIG_FLAGS_MASK 0x3
#define SOF_DAI_CONFIG_FLAGS_NONE (0 << 0) /**< DAI_CONFIG sent without stage information */
#define SOF_DAI_CONFIG_FLAGS_HW_PARAMS (1 << 0) /**< DAI_CONFIG sent during hw_params stage */
#define SOF_DAI_CONFIG_FLAGS_HW_FREE (2 << 0) /**< DAI_CONFIG sent during hw_free stage */
#define SOF_DAI_CONFIG_FLAGS_RFU (3 << 0) /**< not used, reserved for future use */
/** \brief Types of DAI */
enum sof_ipc_dai_type {
SOF_DAI_INTEL_NONE = 0, /**< None */
@ -69,7 +76,8 @@ struct sof_ipc_dai_config {
/* physical protocol and clocking */
uint16_t format; /**< SOF_DAI_FMT_ */
uint16_t reserved16; /**< alignment */
uint8_t group_id; /**< group ID, 0 means no group (ABI 3.17) */
uint8_t flags; /**< SOF_DAI_CONFIG_FLAGS_ (ABI 3.19) */
/* reserved for future use */
uint32_t reserved[8];

View File

@ -1002,7 +1002,7 @@ typedef int __bitwise snd_ctl_elem_iface_t;
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
// (1 << 3) is unused.
/* (1 << 3) is unused. */
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)

View File

@ -13,6 +13,7 @@
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
#define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
#define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL 0x7473636d
#define SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE 0x4d545244
struct snd_firewire_event_common {
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@ -65,6 +66,12 @@ struct snd_firewire_event_tascam_control {
struct snd_firewire_tascam_change changes[0];
};
struct snd_firewire_event_motu_register_dsp_change {
unsigned int type;
__u32 count; /* The number of changes. */
__u32 changes[]; /* Encoded event for change of register DSP. */
};
union snd_firewire_event {
struct snd_firewire_event_common common;
struct snd_firewire_event_lock_status lock_status;
@ -73,6 +80,7 @@ union snd_firewire_event {
struct snd_firewire_event_digi00x_message digi00x_message;
struct snd_firewire_event_tascam_control tascam_control;
struct snd_firewire_event_motu_notification motu_notification;
struct snd_firewire_event_motu_register_dsp_change motu_register_dsp_change;
};
@ -80,6 +88,9 @@ union snd_firewire_event {
#define SNDRV_FIREWIRE_IOCTL_LOCK _IO('H', 0xf9)
#define SNDRV_FIREWIRE_IOCTL_UNLOCK _IO('H', 0xfa)
#define SNDRV_FIREWIRE_IOCTL_TASCAM_STATE _IOR('H', 0xfb, struct snd_firewire_tascam_state)
#define SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER _IOR('H', 0xfc, struct snd_firewire_motu_register_dsp_meter)
#define SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER _IOR('H', 0xfd, struct snd_firewire_motu_command_dsp_meter)
#define SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_PARAMETER _IOR('H', 0xfe, struct snd_firewire_motu_register_dsp_parameter)
#define SNDRV_FIREWIRE_TYPE_DICE 1
#define SNDRV_FIREWIRE_TYPE_FIREWORKS 2
@ -108,4 +119,143 @@ struct snd_firewire_tascam_state {
__be32 data[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
};
/*
* In below MOTU models, software is allowed to control their DSP by accessing to registers.
* - 828mk2
* - 896hd
* - Traveler
* - 8 pre
* - Ultralite
* - 4 pre
* - Audio Express
*
* On the other hand, the status of DSP is split into specific messages included in the sequence of
* isochronous packet. ALSA firewire-motu driver gathers the messages and allow userspace applications
* to read it via ioctl. In 828mk2, 896hd, and Traveler, hardware meter for all of physical inputs
* are put into the message, while one pair of physical outputs is selected. The selection is done by
* LSB one byte in asynchronous write quadlet transaction to 0x'ffff'f000'0b2c.
*
* I note that V3HD/V4HD uses asynchronous transaction for the purpose. The destination address is
* registered to 0x'ffff'f000'0b38 and '0b3c by asynchronous write quadlet request. The size of
* message differs between 23 and 51 quadlets. For the case, the number of mixer bus can be extended
* up to 12.
*/
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT 24
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_OUTPUT_COUNT 24
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_COUNT \
(SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT + SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_OUTPUT_COUNT)
/**
* struct snd_firewire_motu_register_dsp_meter - the container for meter information in DSP
* controlled by register access
* @data: Signal level meters. The mapping between position and input/output channel is
* model-dependent.
*
* The structure expresses the part of DSP status for hardware meter. The u8 storage includes linear
* value for audio signal level between 0x00 and 0x7f.
*/
struct snd_firewire_motu_register_dsp_meter {
__u8 data[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_COUNT];
};
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT 4
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT 20
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT 10
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT (SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT + 2)
/**
* snd_firewire_motu_register_dsp_parameter - the container for parameters of DSP controlled
* by register access.
* @mixer.source.gain: The gain of source to mixer.
* @mixer.source.pan: The L/R balance of source to mixer.
* @mixer.source.flag: The flag of source to mixer, including mute, solo.
* @mixer.source.paired_balance: The L/R balance of paired source to mixer, only for 4 pre and
* Audio Express.
* @mixer.source.paired_width: The width of paired source to mixer, only for 4 pre and
* Audio Express.
* @mixer.output.paired_volume: The volume of paired output from mixer.
* @mixer.output.paired_flag: The flag of paired output from mixer.
* @output.main_paired_volume: The volume of paired main output.
* @output.hp_paired_volume: The volume of paired hp output.
* @output.hp_paired_assignment: The source assigned to paired hp output.
* @output.reserved: Padding for 32 bit alignment for future extension.
* @line_input.boost_flag: The flags of boost for line inputs, only for 828mk2 and Traveler.
* @line_input.nominal_level_flag: The flags of nominal level for line inputs, only for 828mk2 and
* Traveler.
* @line_input.reserved: Padding for 32 bit alignment for future extension.
* @input.gain_and_invert: The value including gain and invert for input, only for Ultralite, 4 pre
* and Audio Express.
* @input.flag: The flag of input; e.g. jack detection, phantom power, and pad, only for Ultralite,
* 4 pre and Audio express.
* @reserved: Padding so that the size of structure is kept to 512 byte, but for future extension.
*
* The structure expresses the set of parameters for DSP controlled by register access.
*/
struct snd_firewire_motu_register_dsp_parameter {
struct {
struct {
__u8 gain[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT];
__u8 pan[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT];
__u8 flag[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT];
__u8 paired_balance[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT];
__u8 paired_width[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT];
} source[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT];
struct {
__u8 paired_volume[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT];
__u8 paired_flag[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT];
} output;
} mixer;
struct {
__u8 main_paired_volume;
__u8 hp_paired_volume;
__u8 hp_paired_assignment;
__u8 reserved[5];
} output;
struct {
__u8 boost_flag;
__u8 nominal_level_flag;
__u8 reserved[6];
} line_input;
struct {
__u8 gain_and_invert[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT];
__u8 flag[SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT];
} input;
__u8 reserved[64];
};
/*
* In below MOTU models, software is allowed to control their DSP by command in frame of
* asynchronous transaction to 0x'ffff'0001'0000:
*
* - 828 mk3 (FireWire only and Hybrid)
* - 896 mk3 (FireWire only and Hybrid)
* - Ultralite mk3 (FireWire only and Hybrid)
* - Traveler mk3
* - Track 16
*
* On the other hand, the states of hardware meter is split into specific messages included in the
* sequence of isochronous packet. ALSA firewire-motu driver gathers the message and allow userspace
* application to read it via ioctl.
*/
#define SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT 400
/**
* struct snd_firewire_motu_command_dsp_meter - the container for meter information in DSP
* controlled by command
* @data: Signal level meters. The mapping between position and signal channel is model-dependent.
*
* The structure expresses the part of DSP status for hardware meter. The 32 bit storage is
* estimated to include IEEE 764 32 bit single precision floating point (binary32) value. It is
* expected to be linear value (not logarithm) for audio signal level between 0.0 and +1.0.
*/
struct snd_firewire_motu_command_dsp_meter {
#ifdef __KERNEL__
__u32 data[SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT];
#else
float data[SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT];
#endif
};
#endif /* _UAPI_SOUND_FIREWIRE_H_INCLUDED */

View File

@ -0,0 +1,208 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __SND_AR_TOKENS_H__
#define __SND_AR_TOKENS_H__
#define APM_SUB_GRAPH_PERF_MODE_LOW_POWER 0x1
#define APM_SUB_GRAPH_PERF_MODE_LOW_LATENCY 0x2
#define APM_SUB_GRAPH_DIRECTION_TX 0x1
#define APM_SUB_GRAPH_DIRECTION_RX 0x2
/** Scenario ID Audio Playback */
#define APM_SUB_GRAPH_SID_AUDIO_PLAYBACK 0x1
/* Scenario ID Audio Record */
#define APM_SUB_GRAPH_SID_AUDIO_RECORD 0x2
/* Scenario ID Voice call. */
#define APM_SUB_GRAPH_SID_VOICE_CALL 0x3
/* container capability ID Pre/Post Processing (PP) */
#define APM_CONTAINER_CAP_ID_PP 0x1
/* container capability ID Compression/Decompression (CD) */
#define APM_CONTAINER_CAP_ID_CD 0x2
/* container capability ID End Point(EP) */
#define APM_CONTAINER_CAP_ID_EP 0x3
/* container capability ID Offload (OLC) */
#define APM_CONTAINER_CAP_ID_OLC 0x4
/* container graph position Stream */
#define APM_CONT_GRAPH_POS_STREAM 0x1
/* container graph position Per Stream Per Device*/
#define APM_CONT_GRAPH_POS_PER_STR_PER_DEV 0x2
/* container graph position Stream-Device */
#define APM_CONT_GRAPH_POS_STR_DEV 0x3
/* container graph position Global Device */
#define APM_CONT_GRAPH_POS_GLOBAL_DEV 0x4
#define APM_PROC_DOMAIN_ID_MDSP 0x1
#define APM_PROC_DOMAIN_ID_ADSP 0x2
#define APM_PROC_DOMAIN_ID_SDSP 0x4
#define APM_PROC_DOMAIN_ID_CDSP 0x5
#define PCM_INTERLEAVED 1
#define PCM_DEINTERLEAVED_PACKED 2
#define PCM_DEINTERLEAVED_UNPACKED 3
#define AR_I2S_WS_SRC_EXTERNAL 0
#define AR_I2S_WS_SRC_INTERNAL 1
enum ar_event_types {
AR_EVENT_NONE = 0,
AR_PGA_DAPM_EVENT
};
/*
* Kcontrol IDs
*/
#define SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX 256
#define SND_SOC_AR_TPLG_VOL_CTL 257
/**
* %AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: Sub Graph Instance Id
*
* %AR_TKN_U32_SUB_GRAPH_PERF_MODE: Performance mode of subgraph
* APM_SUB_GRAPH_PERF_MODE_LOW_POWER = 1,
* APM_SUB_GRAPH_PERF_MODE_LOW_LATENCY = 2
*
* %AR_TKN_U32_SUB_GRAPH_DIRECTION: Direction of subgraph
* APM_SUB_GRAPH_DIRECTION_TX = 1,
* APM_SUB_GRAPH_DIRECTION_RX = 2
*
* %AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: Scenario ID for subgraph
* APM_SUB_GRAPH_SID_AUDIO_PLAYBACK = 1,
* APM_SUB_GRAPH_SID_AUDIO_RECORD = 2,
* APM_SUB_GRAPH_SID_VOICE_CALL = 3
*
* %AR_TKN_U32_CONTAINER_INSTANCE_ID: Container Instance ID
*
* %AR_TKN_U32_CONTAINER_CAPABILITY_ID: Container capability ID
* APM_CONTAINER_CAP_ID_PP = 1,
* APM_CONTAINER_CAP_ID_CD = 2,
* APM_CONTAINER_CAP_ID_EP = 3,
* APM_CONTAINER_CAP_ID_OLC = 4
*
* %AR_TKN_U32_CONTAINER_STACK_SIZE: Stack size in the container.
*
* %AR_TKN_U32_CONTAINER_GRAPH_POS: Graph Position
* APM_CONT_GRAPH_POS_STREAM = 1,
* APM_CONT_GRAPH_POS_PER_STR_PER_DEV = 2,
* APM_CONT_GRAPH_POS_STR_DEV = 3,
* APM_CONT_GRAPH_POS_GLOBAL_DEV = 4
*
* %AR_TKN_U32_CONTAINER_PROC_DOMAIN: Processor domain of container
* APM_PROC_DOMAIN_ID_MDSP = 1,
* APM_PROC_DOMAIN_ID_ADSP = 2,
* APM_PROC_DOMAIN_ID_SDSP = 4,
* APM_PROC_DOMAIN_ID_CDSP = 5
*
* %AR_TKN_U32_MODULE_ID: Module ID
*
* %AR_TKN_U32_MODULE_INSTANCE_ID: Module Instance ID.
*
* %AR_TKN_U32_MODULE_MAX_IP_PORTS: Module maximum input ports
*
* %AR_TKN_U32_MODULE_MAX_OP_PORTS: Module maximum output ports.
*
* %AR_TKN_U32_MODULE_IN_PORTS: Number of in ports
*
* %AR_TKN_U32_MODULE_OUT_PORTS: Number of out ports.
*
* %AR_TKN_U32_MODULE_SRC_OP_PORT_ID: Source module output port ID
*
* %AR_TKN_U32_MODULE_DST_IN_PORT_ID: Destination module input port ID
*
* %AR_TKN_U32_MODULE_HW_IF_IDX: Interface index types for I2S/LPAIF
*
* %AR_TKN_U32_MODULE_HW_IF_TYPE: Interface type
* LPAIF = 0,
* LPAIF_RXTX = 1,
* LPAIF_WSA = 2,
* LPAIF_VA = 3,
* LPAIF_AXI = 4
*
* %AR_TKN_U32_MODULE_FMT_INTERLEAVE: PCM Interleaving
* PCM_INTERLEAVED = 1,
* PCM_DEINTERLEAVED_PACKED = 2,
* PCM_DEINTERLEAVED_UNPACKED = 3
*
* %AR_TKN_U32_MODULE_FMT_DATA: data format
* FIXED POINT = 1,
* IEC60958 PACKETIZED = 3,
* IEC60958 PACKETIZED NON LINEAR = 8,
* COMPR OVER PCM PACKETIZED = 7,
* IEC61937 PACKETIZED = 2,
* GENERIC COMPRESSED = 5
*
* %AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: sample rate
*
* %AR_TKN_U32_MODULE_FMT_BIT_DEPTH: bit depth
*
* %AR_TKN_U32_MODULE_SD_LINE_IDX: I2S serial data line idx
* I2S_SD0 = 1,
* I2S_SD1 = 2,
* I2S_SD2 = 3,
* I2S_SD3 = 4,
* I2S_QUAD01 = 5,
* I2S_QUAD23 = 6,
* I2S_6CHS = 7,
* I2S_8CHS = 8
*
* %AR_TKN_U32_MODULE_WS_SRC: Word Select Source
* AR_I2S_WS_SRC_EXTERNAL = 0,
* AR_I2S_WS_SRC_INTERNAL = 1,
*
* %AR_TKN_U32_MODULE_FRAME_SZ_FACTOR: Frame size factor
*
* %AR_TKN_U32_MODULE_LOG_CODE: Log Module Code
*
* %AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: logging tap point of this module
*
* %AR_TKN_U32_MODULE_LOG_MODE: logging mode
* LOG_WAIT = 0,
* LOG_IMMEDIATELY = 1
*
* %AR_TKN_DAI_INDEX: dai index
*
*/
/* DAI Tokens */
#define AR_TKN_DAI_INDEX 1
/* SUB GRAPH Tokens */
#define AR_TKN_U32_SUB_GRAPH_INSTANCE_ID 2
#define AR_TKN_U32_SUB_GRAPH_PERF_MODE 3
#define AR_TKN_U32_SUB_GRAPH_DIRECTION 4
#define AR_TKN_U32_SUB_GRAPH_SCENARIO_ID 5
/* Container Tokens */
#define AR_TKN_U32_CONTAINER_INSTANCE_ID 100
#define AR_TKN_U32_CONTAINER_CAPABILITY_ID 101
#define AR_TKN_U32_CONTAINER_STACK_SIZE 102
#define AR_TKN_U32_CONTAINER_GRAPH_POS 103
#define AR_TKN_U32_CONTAINER_PROC_DOMAIN 104
/* Module Tokens */
#define AR_TKN_U32_MODULE_ID 200
#define AR_TKN_U32_MODULE_INSTANCE_ID 201
#define AR_TKN_U32_MODULE_MAX_IP_PORTS 202
#define AR_TKN_U32_MODULE_MAX_OP_PORTS 203
#define AR_TKN_U32_MODULE_IN_PORTS 204
#define AR_TKN_U32_MODULE_OUT_PORTS 205
#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID 206
#define AR_TKN_U32_MODULE_DST_IN_PORT_ID 207
#define AR_TKN_U32_MODULE_SRC_INSTANCE_ID 208
#define AR_TKN_U32_MODULE_DST_INSTANCE_ID 209
#define AR_TKN_U32_MODULE_HW_IF_IDX 250
#define AR_TKN_U32_MODULE_HW_IF_TYPE 251
#define AR_TKN_U32_MODULE_FMT_INTERLEAVE 252
#define AR_TKN_U32_MODULE_FMT_DATA 253
#define AR_TKN_U32_MODULE_FMT_SAMPLE_RATE 254
#define AR_TKN_U32_MODULE_FMT_BIT_DEPTH 255
#define AR_TKN_U32_MODULE_SD_LINE_IDX 256
#define AR_TKN_U32_MODULE_WS_SRC 257
#define AR_TKN_U32_MODULE_FRAME_SZ_FACTOR 258
#define AR_TKN_U32_MODULE_LOG_CODE 259
#define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260
#define AR_TKN_U32_MODULE_LOG_MODE 261
#endif /* __SND_AR_TOKENS_H__ */

View File

@ -51,6 +51,7 @@
#define SOF_TKN_SCHED_CORE 203
#define SOF_TKN_SCHED_FRAMES 204
#define SOF_TKN_SCHED_TIME_DOMAIN 205
#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206
/* volume */
#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250

View File

@ -9,7 +9,9 @@ ifneq ($(CONFIG_SND_PROC_FS),)
snd-y += info.o
snd-$(CONFIG_SND_OSSEMUL) += info_oss.o
endif
ifneq ($(CONFIG_M68K),y)
snd-$(CONFIG_ISA_DMA_API) += isadma.o
endif
snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
snd-$(CONFIG_SND_VMASTER) += vmaster.o
snd-$(CONFIG_SND_JACK) += ctljack.o jack.o
@ -17,7 +19,6 @@ snd-$(CONFIG_SND_JACK) += ctljack.o jack.o
snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_misc.o \
pcm_memory.o memalloc.o
snd-pcm-$(CONFIG_SND_PCM_TIMER) += pcm_timer.o
snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o
snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o

View File

@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/genalloc.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
#ifdef CONFIG_X86
#include <asm/set_memory.h>
@ -39,9 +40,11 @@ static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
}
/**
* snd_dma_alloc_pages - allocate the buffer area according to the given type
* snd_dma_alloc_dir_pages - allocate the buffer area according to the given
* type and direction
* @type: the DMA buffer type
* @device: the device pointer
* @dir: DMA direction
* @size: the buffer size to allocate
* @dmab: buffer allocation record to store the allocated data
*
@ -51,8 +54,9 @@ static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
* Return: Zero if the buffer with the given size is allocated successfully,
* otherwise a negative value on error.
*/
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
int snd_dma_alloc_dir_pages(int type, struct device *device,
enum dma_data_direction dir, size_t size,
struct snd_dma_buffer *dmab)
{
if (WARN_ON(!size))
return -ENXIO;
@ -62,6 +66,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
size = PAGE_ALIGN(size);
dmab->dev.type = type;
dmab->dev.dev = device;
dmab->dev.dir = dir;
dmab->bytes = 0;
dmab->addr = 0;
dmab->private_data = NULL;
@ -71,7 +76,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->bytes = size;
return 0;
}
EXPORT_SYMBOL(snd_dma_alloc_pages);
EXPORT_SYMBOL(snd_dma_alloc_dir_pages);
/**
* snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
@ -129,9 +134,10 @@ static void __snd_release_pages(struct device *dev, void *res)
}
/**
* snd_devm_alloc_pages - allocate the buffer and manage with devres
* snd_devm_alloc_dir_pages - allocate the buffer and manage with devres
* @dev: the device pointer
* @type: the DMA buffer type
* @dir: DMA direction
* @size: the buffer size to allocate
*
* Allocate buffer pages depending on the given type and manage using devres.
@ -144,7 +150,8 @@ static void __snd_release_pages(struct device *dev, void *res)
* The function returns the snd_dma_buffer object at success, or NULL if failed.
*/
struct snd_dma_buffer *
snd_devm_alloc_pages(struct device *dev, int type, size_t size)
snd_devm_alloc_dir_pages(struct device *dev, int type,
enum dma_data_direction dir, size_t size)
{
struct snd_dma_buffer *dmab;
int err;
@ -157,7 +164,7 @@ snd_devm_alloc_pages(struct device *dev, int type, size_t size)
if (!dmab)
return NULL;
err = snd_dma_alloc_pages(type, dev, size, dmab);
err = snd_dma_alloc_dir_pages(type, dev, dir, size, dmab);
if (err < 0) {
devres_free(dmab);
return NULL;
@ -166,7 +173,7 @@ snd_devm_alloc_pages(struct device *dev, int type, size_t size)
devres_add(dev, dmab);
return dmab;
}
EXPORT_SYMBOL_GPL(snd_devm_alloc_pages);
EXPORT_SYMBOL_GPL(snd_devm_alloc_dir_pages);
/**
* snd_dma_buffer_mmap - perform mmap of the given DMA buffer
@ -185,6 +192,26 @@ int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
}
EXPORT_SYMBOL(snd_dma_buffer_mmap);
#ifdef CONFIG_HAS_DMA
/**
* snd_dma_buffer_sync - sync DMA buffer between CPU and device
* @dmab: buffer allocation information
* @mode: sync mode
*/
void snd_dma_buffer_sync(struct snd_dma_buffer *dmab,
enum snd_dma_sync_mode mode)
{
const struct snd_malloc_ops *ops;
if (!dmab || !dmab->dev.need_sync)
return;
ops = snd_dma_get_ops(dmab);
if (ops && ops->sync)
ops->sync(dmab, mode);
}
EXPORT_SYMBOL_GPL(snd_dma_buffer_sync);
#endif /* CONFIG_HAS_DMA */
/**
* snd_sgbuf_get_addr - return the physical address at the corresponding offset
* @dmab: buffer allocation information
@ -468,6 +495,161 @@ static const struct snd_malloc_ops snd_dma_wc_ops = {
.mmap = snd_dma_wc_mmap,
};
#endif /* CONFIG_X86 */
/*
* Non-contiguous pages allocator
*/
static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct sg_table *sgt;
void *p;
sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir,
DEFAULT_GFP, 0);
if (!sgt)
return NULL;
dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->dev.dir);
p = dma_vmap_noncontiguous(dmab->dev.dev, size, sgt);
if (p)
dmab->private_data = sgt;
else
dma_free_noncontiguous(dmab->dev.dev, size, sgt, dmab->dev.dir);
return p;
}
static void snd_dma_noncontig_free(struct snd_dma_buffer *dmab)
{
dma_vunmap_noncontiguous(dmab->dev.dev, dmab->area);
dma_free_noncontiguous(dmab->dev.dev, dmab->bytes, dmab->private_data,
dmab->dev.dir);
}
static int snd_dma_noncontig_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return dma_mmap_noncontiguous(dmab->dev.dev, area,
dmab->bytes, dmab->private_data);
}
static void snd_dma_noncontig_sync(struct snd_dma_buffer *dmab,
enum snd_dma_sync_mode mode)
{
if (mode == SNDRV_DMA_SYNC_CPU) {
if (dmab->dev.dir == DMA_TO_DEVICE)
return;
dma_sync_sgtable_for_cpu(dmab->dev.dev, dmab->private_data,
dmab->dev.dir);
invalidate_kernel_vmap_range(dmab->area, dmab->bytes);
} else {
if (dmab->dev.dir == DMA_FROM_DEVICE)
return;
flush_kernel_vmap_range(dmab->area, dmab->bytes);
dma_sync_sgtable_for_device(dmab->dev.dev, dmab->private_data,
dmab->dev.dir);
}
}
static const struct snd_malloc_ops snd_dma_noncontig_ops = {
.alloc = snd_dma_noncontig_alloc,
.free = snd_dma_noncontig_free,
.mmap = snd_dma_noncontig_mmap,
.sync = snd_dma_noncontig_sync,
/* re-use vmalloc helpers for get_* ops */
.get_addr = snd_dma_vmalloc_get_addr,
.get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size,
};
/* x86-specific SG-buffer with WC pages */
#ifdef CONFIG_SND_DMA_SGBUF
#define vmalloc_to_virt(v) (unsigned long)page_to_virt(vmalloc_to_page(v))
static void *snd_dma_sg_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
{
void *p = snd_dma_noncontig_alloc(dmab, size);
size_t ofs;
if (!p)
return NULL;
for (ofs = 0; ofs < size; ofs += PAGE_SIZE)
set_memory_uc(vmalloc_to_virt(p + ofs), 1);
return p;
}
static void snd_dma_sg_wc_free(struct snd_dma_buffer *dmab)
{
size_t ofs;
for (ofs = 0; ofs < dmab->bytes; ofs += PAGE_SIZE)
set_memory_wb(vmalloc_to_virt(dmab->area + ofs), 1);
snd_dma_noncontig_free(dmab);
}
static int snd_dma_sg_wc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
/* FIXME: dma_mmap_noncontiguous() works? */
return -ENOENT; /* continue with the default mmap handler */
}
const struct snd_malloc_ops snd_dma_sg_wc_ops = {
.alloc = snd_dma_sg_wc_alloc,
.free = snd_dma_sg_wc_free,
.mmap = snd_dma_sg_wc_mmap,
.sync = snd_dma_noncontig_sync,
.get_addr = snd_dma_vmalloc_get_addr,
.get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size,
};
#endif /* CONFIG_SND_DMA_SGBUF */
/*
* Non-coherent pages allocator
*/
static void *snd_dma_noncoherent_alloc(struct snd_dma_buffer *dmab, size_t size)
{
dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->dev.dir);
return dma_alloc_noncoherent(dmab->dev.dev, size, &dmab->addr,
dmab->dev.dir, DEFAULT_GFP);
}
static void snd_dma_noncoherent_free(struct snd_dma_buffer *dmab)
{
dma_free_noncoherent(dmab->dev.dev, dmab->bytes, dmab->area,
dmab->addr, dmab->dev.dir);
}
static int snd_dma_noncoherent_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = vm_get_page_prot(area->vm_flags);
return dma_mmap_pages(dmab->dev.dev, area,
area->vm_end - area->vm_start,
virt_to_page(dmab->area));
}
static void snd_dma_noncoherent_sync(struct snd_dma_buffer *dmab,
enum snd_dma_sync_mode mode)
{
if (mode == SNDRV_DMA_SYNC_CPU) {
if (dmab->dev.dir != DMA_TO_DEVICE)
dma_sync_single_for_cpu(dmab->dev.dev, dmab->addr,
dmab->bytes, dmab->dev.dir);
} else {
if (dmab->dev.dir != DMA_FROM_DEVICE)
dma_sync_single_for_device(dmab->dev.dev, dmab->addr,
dmab->bytes, dmab->dev.dir);
}
}
static const struct snd_malloc_ops snd_dma_noncoherent_ops = {
.alloc = snd_dma_noncoherent_alloc,
.free = snd_dma_noncoherent_free,
.mmap = snd_dma_noncoherent_mmap,
.sync = snd_dma_noncoherent_sync,
};
#endif /* CONFIG_HAS_DMA */
/*
@ -479,14 +661,15 @@ static const struct snd_malloc_ops *dma_ops[] = {
#ifdef CONFIG_HAS_DMA
[SNDRV_DMA_TYPE_DEV] = &snd_dma_dev_ops,
[SNDRV_DMA_TYPE_DEV_WC] = &snd_dma_wc_ops,
[SNDRV_DMA_TYPE_NONCONTIG] = &snd_dma_noncontig_ops,
[SNDRV_DMA_TYPE_NONCOHERENT] = &snd_dma_noncoherent_ops,
#ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_wc_ops,
#endif
#ifdef CONFIG_GENERIC_ALLOCATOR
[SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops,
#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
#ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops,
[SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_ops,
#endif
};
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab)

View File

@ -10,6 +10,7 @@ struct snd_malloc_ops {
unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode);
};
#ifdef CONFIG_SND_DMA_SGBUF

View File

@ -130,11 +130,13 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume || pslot->put_recsrc)
result |= 1 << chn;
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -146,11 +148,13 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume && pslot->stereo)
result |= 1 << chn;
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -161,6 +165,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
result = mixer->mask_recsrc;
} else {
@ -172,6 +177,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
result |= 1 << chn;
}
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -182,12 +188,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
int err;
unsigned int index;
err = mixer->get_recsrc(fmixer, &index);
if (err < 0)
return err;
result = mixer->get_recsrc(fmixer, &index);
if (result < 0)
goto unlock;
result = 1 << index;
} else {
struct snd_mixer_oss_slot *pslot;
@ -202,7 +208,10 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
}
}
}
return mixer->oss_recsrc = result;
mixer->oss_recsrc = result;
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
@ -215,6 +224,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
if (mixer == NULL)
return -EIO;
mutex_lock(&mixer->reg_mutex);
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
@ -240,6 +250,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
}
}
}
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -251,6 +262,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
if (mixer == NULL || slot > 30)
return -EIO;
mutex_lock(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
left = pslot->volume[0];
right = pslot->volume[1];
@ -258,15 +270,21 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
result = pslot->get_volume(fmixer, pslot, &left, &right);
if (!pslot->stereo)
right = left;
if (snd_BUG_ON(left < 0 || left > 100))
return -EIO;
if (snd_BUG_ON(right < 0 || right > 100))
return -EIO;
if (snd_BUG_ON(left < 0 || left > 100)) {
result = -EIO;
goto unlock;
}
if (snd_BUG_ON(right < 0 || right > 100)) {
result = -EIO;
goto unlock;
}
if (result >= 0) {
pslot->volume[0] = left;
pslot->volume[1] = right;
result = (left & 0xff) | ((right & 0xff) << 8);
}
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
@ -279,6 +297,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (mixer == NULL || slot > 30)
return -EIO;
mutex_lock(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
if (left > 100)
left = 100;
@ -289,10 +308,13 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (pslot->put_volume)
result = pslot->put_volume(fmixer, pslot, left, right);
if (result < 0)
return result;
goto unlock;
pslot->volume[0] = left;
pslot->volume[1] = right;
return (left & 0xff) | ((right & 0xff) << 8);
result = (left & 0xff) | ((right & 0xff) << 8);
unlock:
mutex_unlock(&mixer->reg_mutex);
return result;
}
static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)

View File

@ -453,6 +453,8 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
@ -533,6 +535,8 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
return -EFAULT;
return 0;

View File

@ -106,6 +106,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
frames -= transfer;
ofs = 0;
}
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
}
#ifdef CONFIG_SND_DEBUG
@ -2256,8 +2257,12 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
goto _end_unlock;
}
snd_pcm_stream_unlock_irq(substream);
if (!is_playback)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
err = writer(substream, appl_ofs, data, offset, frames,
transfer);
if (is_playback)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
snd_pcm_stream_lock_irq(substream);
if (err < 0)
goto _end_unlock;

View File

@ -73,4 +73,11 @@ void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);
for ((subs) = (pcm)->streams[str].substream; (subs); \
(subs) = (subs)->next)
static inline void snd_pcm_dma_buffer_sync(struct snd_pcm_substream *substream,
enum snd_dma_sync_mode mode)
{
if (substream->runtime->info & SNDRV_PCM_INFO_EXPLICIT_SYNC)
snd_dma_buffer_sync(snd_pcm_get_dma_buf(substream), mode);
}
#endif /* __SOUND_CORE_PCM_LOCAL_H */

View File

@ -32,15 +32,20 @@ module_param(max_alloc_per_card, ulong, 0644);
MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
size_t size, struct snd_dma_buffer *dmab)
int str, size_t size, struct snd_dma_buffer *dmab)
{
enum dma_data_direction dir;
int err;
if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card)
return -ENOMEM;
err = snd_dma_alloc_pages(type, dev, size, dmab);
if (str == SNDRV_PCM_STREAM_PLAYBACK)
dir = DMA_TO_DEVICE;
else
dir = DMA_FROM_DEVICE;
err = snd_dma_alloc_dir_pages(type, dev, dir, size, dmab);
if (!err) {
mutex_lock(&card->memory_mutex);
card->total_pcm_alloc_bytes += dmab->bytes;
@ -77,7 +82,7 @@ static int preallocate_pcm_pages(struct snd_pcm_substream *substream,
do {
err = do_alloc_pages(card, dmab->dev.type, dmab->dev.dev,
size, dmab);
substream->stream, size, dmab);
if (err != -ENOMEM)
return err;
if (no_fallback)
@ -177,6 +182,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
if (do_alloc_pages(card,
substream->dma_buffer.dev.type,
substream->dma_buffer.dev.dev,
substream->stream,
size, &new_dmab) < 0) {
buffer->error = -ENOMEM;
pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
@ -418,6 +424,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
if (do_alloc_pages(card,
substream->dma_buffer.dev.type,
substream->dma_buffer.dev.dev,
substream->stream,
size, dmab) < 0) {
kfree(dmab);
pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",

View File

@ -2685,6 +2685,13 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
goto error;
}
/* automatically set EXPLICIT_SYNC flag in the managed mode whenever
* the DMA buffer requires it
*/
if (substream->managed_buffer_alloc &&
substream->dma_buffer.dev.need_sync)
substream->runtime->hw.info |= SNDRV_PCM_INFO_EXPLICIT_SYNC;
*rsubstream = substream;
return 0;
@ -2912,6 +2919,8 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
ret = rewind_appl_ptr(substream, frames,
snd_pcm_hw_avail(substream));
snd_pcm_stream_unlock_irq(substream);
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
}
@ -2929,35 +2938,31 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
ret = forward_appl_ptr(substream, frames,
snd_pcm_avail(substream));
snd_pcm_stream_unlock_irq(substream);
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
}
static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
{
int err;
snd_pcm_stream_lock_irq(substream);
err = do_pcm_hwsync(substream);
snd_pcm_stream_unlock_irq(substream);
return err;
}
static int snd_pcm_delay(struct snd_pcm_substream *substream,
snd_pcm_sframes_t *delay)
{
int err;
snd_pcm_sframes_t n = 0;
snd_pcm_stream_lock_irq(substream);
err = do_pcm_hwsync(substream);
if (!err)
n = snd_pcm_calc_delay(substream);
if (delay && !err)
*delay = snd_pcm_calc_delay(substream);
snd_pcm_stream_unlock_irq(substream);
if (!err)
*delay = n;
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
return err;
}
static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream)
{
return snd_pcm_delay(substream, NULL);
}
static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr __user *_sync_ptr)
{
@ -3000,6 +3005,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
sync_ptr.s.status.suspended_state = status->suspended_state;
sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
return -EFAULT;
return 0;
@ -3096,6 +3103,8 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
sstatus.suspended_state = status->suspended_state;
sstatus.audio_tstamp = status->audio_tstamp;
snd_pcm_stream_unlock_irq(substream);
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (put_user(sstatus.state, &src->s.status.state) ||
put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
@ -3218,6 +3227,9 @@ static int snd_pcm_common_ioctl(struct file *file,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
res = snd_power_wait(substream->pcm->card);
if (res < 0)
return res;
@ -3272,7 +3284,7 @@ static int snd_pcm_common_ioctl(struct file *file,
return snd_pcm_hwsync(substream);
case SNDRV_PCM_IOCTL_DELAY:
{
snd_pcm_sframes_t delay;
snd_pcm_sframes_t delay = 0;
snd_pcm_sframes_t __user *res = arg;
int err;
@ -3344,6 +3356,9 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
snd_pcm_uframes_t *frames = arg;
snd_pcm_sframes_t result;
if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
switch (cmd) {
case SNDRV_PCM_IOCTL_FORWARD:
{
@ -3386,7 +3401,8 @@ 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->status->state == SNDRV_PCM_STATE_OPEN)
if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (!frame_aligned(runtime, count))
return -EINVAL;
@ -3410,7 +3426,8 @@ 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->status->state == SNDRV_PCM_STATE_OPEN)
if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (!frame_aligned(runtime, count))
return -EINVAL;
@ -3436,7 +3453,8 @@ 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->status->state == SNDRV_PCM_STATE_OPEN)
if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (!iter_is_iovec(to))
return -EINVAL;
@ -3472,7 +3490,8 @@ 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->status->state == SNDRV_PCM_STATE_OPEN)
if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
if (!iter_is_iovec(from))
return -EINVAL;
@ -3511,6 +3530,9 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
return ok | EPOLLERR;
runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return ok | EPOLLERR;
poll_wait(file, &runtime->sleep, wait);
mask = 0;
@ -3820,6 +3842,8 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
substream = pcm_file->substream;
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
if (substream->runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) {
@ -3856,6 +3880,8 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
return fasync_helper(fd, file, on, &runtime->fasync);
}

View File

@ -1,201 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Scatter-Gather buffer
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*/
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <sound/memalloc.h>
#include "memalloc_local.h"
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct device *dev;
};
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
static void snd_dma_sg_free(struct snd_dma_buffer *dmab)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
struct snd_dma_buffer tmpb;
int i;
if (!sgbuf)
return;
vunmap(dmab->area);
dmab->area = NULL;
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
tmpb.dev.type = SNDRV_DMA_TYPE_DEV_WC;
tmpb.dev.dev = sgbuf->dev;
for (i = 0; i < sgbuf->pages; i++) {
if (!(sgbuf->table[i].addr & ~PAGE_MASK))
continue; /* continuous pages */
tmpb.area = sgbuf->table[i].buf;
tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
snd_dma_free_pages(&tmpb);
}
kfree(sgbuf->table);
kfree(sgbuf->page_table);
kfree(sgbuf);
dmab->private_data = NULL;
}
#define MAX_ALLOC_PAGES 32
static void *snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct snd_sg_buf *sgbuf;
unsigned int i, pages, chunk, maxpages;
struct snd_dma_buffer tmpb;
struct snd_sg_page *table;
struct page **pgtable;
int type = SNDRV_DMA_TYPE_DEV;
pgprot_t prot = PAGE_KERNEL;
void *area;
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (!sgbuf)
return NULL;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG) {
type = SNDRV_DMA_TYPE_DEV_WC;
#ifdef pgprot_noncached
prot = pgprot_noncached(PAGE_KERNEL);
#endif
}
sgbuf->dev = dmab->dev.dev;
pages = snd_sgbuf_aligned_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
if (!table)
goto _failed;
sgbuf->table = table;
pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
if (!pgtable)
goto _failed;
sgbuf->page_table = pgtable;
/* allocate pages */
maxpages = MAX_ALLOC_PAGES;
while (pages > 0) {
chunk = pages;
/* don't be too eager to take a huge chunk */
if (chunk > maxpages)
chunk = maxpages;
chunk <<= PAGE_SHIFT;
if (snd_dma_alloc_pages_fallback(type, dmab->dev.dev,
chunk, &tmpb) < 0) {
if (!sgbuf->pages)
goto _failed;
size = sgbuf->pages * PAGE_SIZE;
break;
}
chunk = tmpb.bytes >> PAGE_SHIFT;
for (i = 0; i < chunk; i++) {
table->buf = tmpb.area;
table->addr = tmpb.addr;
if (!i)
table->addr |= chunk; /* mark head */
table++;
*pgtable++ = virt_to_page(tmpb.area);
tmpb.area += PAGE_SIZE;
tmpb.addr += PAGE_SIZE;
}
sgbuf->pages += chunk;
pages -= chunk;
if (chunk < maxpages)
maxpages = chunk;
}
sgbuf->size = size;
area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
if (!area)
goto _failed;
return area;
_failed:
snd_dma_sg_free(dmab); /* free the table */
return NULL;
}
static dma_addr_t snd_dma_sg_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
dma_addr_t addr;
addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= ~((dma_addr_t)PAGE_SIZE - 1);
return addr + offset % PAGE_SIZE;
}
static struct page *snd_dma_sg_get_page(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
static unsigned int snd_dma_sg_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs,
unsigned int size)
{
struct snd_sg_buf *sg = dmab->private_data;
unsigned int start, end, pg;
start = ofs >> PAGE_SHIFT;
end = (ofs + size - 1) >> PAGE_SHIFT;
/* check page continuity */
pg = sg->table[start].addr >> PAGE_SHIFT;
for (;;) {
start++;
if (start > end)
break;
pg++;
if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
return (start << PAGE_SHIFT) - ofs;
}
/* ok, all on continuous pages */
return size;
}
static int snd_dma_sg_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return -ENOENT; /* continue with the default mmap handler */
}
const struct snd_malloc_ops snd_dma_sg_ops = {
.alloc = snd_dma_sg_alloc,
.free = snd_dma_sg_free,
.get_addr = snd_dma_sg_get_addr,
.get_page = snd_dma_sg_get_page,
.get_chunk_size = snd_dma_sg_get_chunk_size,
.mmap = snd_dma_sg_mmap,
};

View File

@ -4,5 +4,6 @@ CFLAGS_amdtp-motu.o := -I$(src)
snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
motu-protocol-v2.o motu-protocol-v3.o \
motu-protocol-v1.o
motu-protocol-v1.o motu-register-dsp-message-parser.o \
motu-command-dsp-message-parser.o
obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o

View File

@ -333,6 +333,7 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
unsigned int packets,
struct snd_pcm_substream *pcm)
{
struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
struct amdtp_motu *p = s->protocol;
unsigned int pcm_frames = 0;
int i;
@ -357,6 +358,14 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
read_midi_messages(s, buf, data_blocks);
}
if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
snd_motu_register_dsp_message_parser_parse(motu, descs, packets,
s->data_block_quadlets);
} else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) {
snd_motu_command_dsp_message_parser_parse(motu, descs, packets,
s->data_block_quadlets);
}
// For tracepoints.
if (trace_data_block_sph_enabled() ||
trace_data_block_message_enabled())
@ -415,8 +424,6 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
if (p->midi_ports)
write_midi_messages(s, buf, data_blocks);
// TODO: how to interact control messages between userspace?
write_sph(p->cache, buf, data_blocks, s->data_block_quadlets);
}

View File

@ -0,0 +1,181 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series
//
// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
// Below models allow software to configure their DSP function by command transferred in
// asynchronous transaction:
// * 828 mk3 (FireWire only and Hybrid)
// * 896 mk3 (FireWire only and Hybrid)
// * Ultralite mk3 (FireWire only and Hybrid)
// * Traveler mk3
// * Track 16
//
// Isochronous packets from the above models includes messages to report state of hardware meter.
#include "motu.h"
enum msg_parser_state {
INITIALIZED,
FRAGMENT_DETECTED,
AVAILABLE,
};
struct msg_parser {
spinlock_t lock;
enum msg_parser_state state;
unsigned int interval;
unsigned int message_count;
unsigned int fragment_pos;
unsigned int value_index;
u64 value;
struct snd_firewire_motu_command_dsp_meter meter;
};
int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
{
struct msg_parser *parser;
parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
if (!parser)
return -ENOMEM;
spin_lock_init(&parser->lock);
motu->message_parser = parser;
return 0;
}
int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
{
struct msg_parser *parser = motu->message_parser;
parser->state = INITIALIZED;
// All of data blocks don't have messages with meaningful information.
switch (sfc) {
case CIP_SFC_176400:
case CIP_SFC_192000:
parser->interval = 4;
break;
case CIP_SFC_88200:
case CIP_SFC_96000:
parser->interval = 2;
break;
case CIP_SFC_32000:
case CIP_SFC_44100:
case CIP_SFC_48000:
default:
parser->interval = 1;
break;
}
return 0;
}
#define FRAGMENT_POS 6
#define MIDI_BYTE_POS 7
#define MIDI_FLAG_POS 8
// One value of hardware meter consists of 4 messages.
#define FRAGMENTS_PER_VALUE 4
#define VALUES_AT_IMAGE_END 0xffffffffffffffff
void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
unsigned int desc_count, unsigned int data_block_quadlets)
{
struct msg_parser *parser = motu->message_parser;
unsigned int interval = parser->interval;
unsigned long flags;
int i;
spin_lock_irqsave(&parser->lock, flags);
for (i = 0; i < desc_count; ++i) {
const struct pkt_desc *desc = descs + i;
__be32 *buffer = desc->ctx_payload;
unsigned int data_blocks = desc->data_blocks;
int j;
for (j = 0; j < data_blocks; ++j) {
u8 *b = (u8 *)buffer;
buffer += data_block_quadlets;
switch (parser->state) {
case INITIALIZED:
{
u8 fragment = b[FRAGMENT_POS];
if (fragment > 0) {
parser->value = fragment;
parser->message_count = 1;
parser->state = FRAGMENT_DETECTED;
}
break;
}
case FRAGMENT_DETECTED:
{
if (parser->message_count % interval == 0) {
u8 fragment = b[FRAGMENT_POS];
parser->value >>= 8;
parser->value |= (u64)fragment << 56;
if (parser->value == VALUES_AT_IMAGE_END) {
parser->state = AVAILABLE;
parser->fragment_pos = 0;
parser->value_index = 0;
parser->message_count = 0;
}
}
++parser->message_count;
break;
}
case AVAILABLE:
default:
{
if (parser->message_count % interval == 0) {
u8 fragment = b[FRAGMENT_POS];
parser->value >>= 8;
parser->value |= (u64)fragment << 56;
++parser->fragment_pos;
if (parser->fragment_pos == 4) {
// Skip the last two quadlets since they could be
// invalid value (0xffffffff) as floating point
// number.
if (parser->value_index <
SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
u32 val = (u32)(parser->value >> 32);
parser->meter.data[parser->value_index] = val;
}
++parser->value_index;
parser->fragment_pos = 0;
}
if (parser->value == VALUES_AT_IMAGE_END) {
parser->value_index = 0;
parser->fragment_pos = 0;
parser->message_count = 0;
}
}
++parser->message_count;
break;
}
}
}
}
spin_unlock_irqrestore(&parser->lock, flags);
}
void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
struct snd_firewire_motu_command_dsp_meter *meter)
{
struct msg_parser *parser = motu->message_parser;
unsigned long flags;
spin_lock_irqsave(&parser->lock, flags);
memcpy(meter, &parser->meter, sizeof(*meter));
spin_unlock_irqrestore(&parser->lock, flags);
}

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