Merge: ALSA - update drivers for 9.7 - upstream 6.13
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6587 JIRA: https://issues.redhat.com/browse/RHEL-80681 This upstream patchset updates the ALSA driver code: - ALSA core - ALSA HDA - ALSA USB - ALSA PCI - ALSA SoC (mainly SOF including SoundWire drivers) - Soundwire bus The other components are touched to get things in sync with the current upstream: Some touched drivers are for hardware platforms which are not used in RHEL. The purpose to merge those upstream commits is to keep the future code sync more easy. Omitted-fix: 704dbe97a681 # not supported platform Omitted-fix: efa527f984a1 # code is not used Omitted-fix: ec15e5043d0b # not supported platform Omitted-fix: 3f0b8d367db5 # not supported platform Omitted-fix: e9d2a2f49244 # not supported platform Omitted-fix: be8cd366beb8 # in MR !6787 Omitted-fix: 38e94cefbf45 # in MR !6787 Signed-off-by: Jaroslav Kysela <jkysela@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: Eric Chanudet <echanude@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
This commit is contained in:
commit
f8561e9b91
|
@ -0,0 +1,111 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/adi,adau1373.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices ADAU1373 CODEC
|
||||
|
||||
maintainers:
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices ADAU1373 Low power codec with speaker and headphone amplifiers.
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1373.pdf
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adau1373
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
powerdown-gpios:
|
||||
description: GPIO used for hardware power-down.
|
||||
maxItems: 1
|
||||
|
||||
adi,micbias1-microvolt:
|
||||
description:
|
||||
This property sets the microphone bias voltage for the first microphone.
|
||||
enum: [1800000, 2200000, 2600000, 2900000]
|
||||
default: 2900000
|
||||
|
||||
adi,micbias2-microvolt:
|
||||
description:
|
||||
This property sets the microphone bias voltage for the second microphone.
|
||||
enum: [1800000, 2200000, 2600000, 2900000]
|
||||
default: 2900000
|
||||
|
||||
adi,input1-differential:
|
||||
description: This property sets the first analog input as differential.
|
||||
type: boolean
|
||||
|
||||
adi,input2-differential:
|
||||
description: This property sets the second analog input as differential.
|
||||
type: boolean
|
||||
|
||||
adi,input3-differential:
|
||||
description: This property sets the third analog input as differential.
|
||||
type: boolean
|
||||
|
||||
adi,input4-differential:
|
||||
description: This property sets the fourth analog input as differential.
|
||||
type: boolean
|
||||
|
||||
adi,lineout-differential:
|
||||
description: This property sets the line output as differential.
|
||||
type: boolean
|
||||
|
||||
adi,lineout-gnd-sense:
|
||||
description: This property enables the line output ground sense control.
|
||||
type: boolean
|
||||
|
||||
adi,drc-settings:
|
||||
description:
|
||||
This setting is used to control the dynamic range of the signal. The
|
||||
device provides a maximum of three full band DRCs with 13 entries each.
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
oneOf:
|
||||
- minItems: 13
|
||||
maxItems: 13
|
||||
- minItems: 26
|
||||
maxItems: 26
|
||||
- minItems: 39
|
||||
maxItems: 39
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
audio-codec@1a {
|
||||
compatible = "adi,adau1373";
|
||||
reg = <0x1a>;
|
||||
#sound-dai-cells = <0>;
|
||||
powerdown-gpios = <&gpio 100 GPIO_ACTIVE_LOW>;
|
||||
adi,input2-differential;
|
||||
adi,input1-differential;
|
||||
adi,lineout-differential;
|
||||
adi,micbias2-microvolt = <1800000>;
|
||||
adi,drc-settings = /bits/ 8 <
|
||||
0xff 0xff 0x1 0x2 0xa 0xa 0xd 0x1 0xff 0xff 0x5 0xd 0xff
|
||||
>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -17,8 +17,9 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- awinic,aw88395
|
||||
- awinic,aw88081
|
||||
- awinic,aw88261
|
||||
- awinic,aw88395
|
||||
- awinic,aw88399
|
||||
|
||||
reg:
|
||||
|
@ -56,6 +57,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- awinic,aw88081
|
||||
- awinic,aw88261
|
||||
then:
|
||||
properties:
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/irondevice,sma1307.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Iron Device SMA1307 Audio Amplifier
|
||||
|
||||
maintainers:
|
||||
- Kiseok Jo <kiseok.jo@irondevice.com>
|
||||
|
||||
description:
|
||||
SMA1307 boosted digital speaker amplifier with feedback-loop.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- irondevice,sma1307a
|
||||
- irondevice,sma1307aq
|
||||
description:
|
||||
If a 'q' is added, it indicated the product is AEC-Q100
|
||||
qualified for automotive applications. SMA1307A supports
|
||||
both WLCSP and QFN packages. However, SMA1307AQ only
|
||||
supports the QFN package.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#sound-dai-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
amplifier@1e {
|
||||
compatible = "irondevice,sma1307a";
|
||||
reg = <0x1e>;
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/neofidelity,ntp8835.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NeoFidelity NTP8835/NTP8835C Amplifiers
|
||||
|
||||
maintainers:
|
||||
- Igor Prusov <ivprusov@salutedevices.com>
|
||||
|
||||
description: |
|
||||
The NTP8835 is a single chip full digital audio amplifier
|
||||
including power stages for stereo amplifier systems.
|
||||
NTP8835 is integrated with versatile digital audio signal
|
||||
processing functions, high-performance, high-fidelity fully
|
||||
digital PWM modulator and two high-power full-bridge MOSFET
|
||||
power stages. NTP8835C has identical programming interface,
|
||||
but has different output signal characteristics.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- neofidelity,ntp8835
|
||||
- neofidelity,ntp8835c
|
||||
|
||||
reg:
|
||||
enum:
|
||||
- 0x2a
|
||||
- 0x2b
|
||||
- 0x2c
|
||||
- 0x2d
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: wck
|
||||
- const: bck
|
||||
- const: scl
|
||||
- const: mclk
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
audio-codec@2b {
|
||||
compatible = "neofidelity,ntp8835";
|
||||
#sound-dai-cells = <0>;
|
||||
reg = <0x2b>;
|
||||
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&clkc 551>, <&clkc 552>, <&clkc 553>, <&clkc 554>;
|
||||
clock-names = "wck", "bck", "scl", "mclk";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/neofidelity,ntp8918.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NeoFidelity NTP8918 Amplifier
|
||||
|
||||
maintainers:
|
||||
- Igor Prusov <ivprusov@salutedevices.com>
|
||||
|
||||
description:
|
||||
The NTP8918 is a single chip full digital audio amplifier
|
||||
including power stage for stereo amplifier system.
|
||||
The NTP8918 is integrated with versatile digital audio signal
|
||||
processing functions, high-performance, high-fidelity fully
|
||||
digital PWM modulator and two high-power full-bridge MOSFET
|
||||
power stages.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- neofidelity,ntp8918
|
||||
|
||||
reg:
|
||||
enum:
|
||||
- 0x2a
|
||||
- 0x2b
|
||||
- 0x2c
|
||||
- 0x2d
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: wck
|
||||
- const: scl
|
||||
- const: bck
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
audio-codec@2a {
|
||||
compatible = "neofidelity,ntp8918";
|
||||
#sound-dai-cells = <0>;
|
||||
reg = <0x2a>;
|
||||
clocks = <&clkc 150>, <&clkc 151>, <&clkc 152>;
|
||||
clock-names = "wck", "scl", "bck";
|
||||
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
|
@ -25,6 +25,7 @@ properties:
|
|||
- enum:
|
||||
- qcom,sm8550-sndcard
|
||||
- qcom,sm8650-sndcard
|
||||
- qcom,sm8750-sndcard
|
||||
- const: qcom,sm8450-sndcard
|
||||
- enum:
|
||||
- qcom,apq8016-sbc-sndcard
|
||||
|
|
|
@ -29,6 +29,10 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/string-array
|
||||
maxItems: 2
|
||||
|
||||
idle-state:
|
||||
description: If present specifies the state when the mux is powered down
|
||||
$ref: /schemas/mux/mux-controller.yaml#/properties/idle-state
|
||||
|
||||
sound-name-prefix: true
|
||||
|
||||
required:
|
||||
|
@ -43,4 +47,5 @@ examples:
|
|||
compatible = "simple-audio-mux";
|
||||
mux-gpios = <&gpio 3 0>;
|
||||
state-labels = "Label_A", "Label_B";
|
||||
idle-state = <0>;
|
||||
};
|
||||
|
|
|
@ -776,6 +776,8 @@ patternProperties:
|
|||
description: National Semiconductor
|
||||
"^nec,.*":
|
||||
description: NEC LCD Technologies, Ltd.
|
||||
"^neofidelity,.*":
|
||||
description: Neofidelity Inc.
|
||||
"^neonode,.*":
|
||||
description: Neonode Inc.
|
||||
"^netgear,.*":
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
=====================================================================
|
||||
Audio drivers for Cirrus Logic CS35L54/56/57 Boosted Smart Amplifiers
|
||||
=====================================================================
|
||||
:Copyright: 2025 Cirrus Logic, Inc. and
|
||||
Cirrus Logic International Semiconductor Ltd.
|
||||
|
||||
Contact: patches@opensource.cirrus.com
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
The high-level summary of this document is:
|
||||
|
||||
**If you have a laptop that uses CS35L54/56/57 amplifiers but audio is not
|
||||
working, DO NOT ATTEMPT TO USE FIRMWARE AND SETTINGS FROM ANOTHER LAPTOP,
|
||||
EVEN IF THAT LAPTOP SEEMS SIMILAR.**
|
||||
|
||||
The CS35L54/56/57 amplifiers must be correctly configured for the power
|
||||
supply voltage, speaker impedance, maximum speaker voltage/current, and
|
||||
other external hardware connections.
|
||||
|
||||
The amplifiers feature advanced boost technology that increases the voltage
|
||||
used to drive the speakers, while proprietary speaker protection algorithms
|
||||
allow these boosted amplifiers to push the limits of the speakers without
|
||||
causing damage. These **must** be configured correctly.
|
||||
|
||||
Supported Cirrus Logic amplifiers
|
||||
---------------------------------
|
||||
|
||||
The cs35l56 drivers support:
|
||||
|
||||
* CS35L54
|
||||
* CS35L56
|
||||
* CS35L57
|
||||
|
||||
There are two drivers in the kernel
|
||||
|
||||
*For systems using SoundWire*: sound/soc/codecs/cs35l56.c and associated files
|
||||
|
||||
*For systems using HDA*: sound/pci/hda/cs35l56_hda.c
|
||||
|
||||
Firmware
|
||||
========
|
||||
|
||||
The amplifier is controlled and managed by firmware running on the internal
|
||||
DSP. Firmware files are essential to enable the full capabilities of the
|
||||
amplifier.
|
||||
|
||||
Firmware is distributed in the linux-firmware repository:
|
||||
https://gitlab.com/kernel-firmware/linux-firmware.git
|
||||
|
||||
On most SoundWire systems the amplifier has a default minimum capability to
|
||||
produce audio. However this will be
|
||||
|
||||
* at low volume, to protect the speakers, since the speaker specifications
|
||||
and power supply voltages are unknown.
|
||||
* a mono mix of left and right channels.
|
||||
|
||||
On some SoundWire systems that have both CS42L43 and CS35L56/57 the CS35L56/57
|
||||
receive their audio from the CS42L43 instead of directly from the host
|
||||
SoundWire interface. These systems can be identified by the CS42L43 showing
|
||||
in dmesg as a SoundWire device, but the CS35L56/57 as SPI. On these systems
|
||||
the firmware is *mandatory* to enable receiving the audio from the CS42L43.
|
||||
|
||||
On HDA systems the firmware is *mandatory* to enable HDA bridge mode. There
|
||||
will not be any audio from the amplifiers without firmware.
|
||||
|
||||
Cirrus Logic firmware files
|
||||
---------------------------
|
||||
|
||||
Each amplifier requires two firmware files. One file has a .wmfw suffix, the
|
||||
other has a .bin suffix.
|
||||
|
||||
The firmware is customized by the OEM to match the hardware of each laptop,
|
||||
and the firmware is specific to that laptop. Because of this, there are many
|
||||
firmware files in linux-firmware for these amplifiers. Firmware files are
|
||||
**not interchangeable between laptops**.
|
||||
|
||||
Cirrus Logic submits files for known laptops to the upstream linux-firmware
|
||||
repository. Providing Cirrus Logic is aware of a particular laptop and has
|
||||
permission from the manufacturer to publish the firmware, it will be pushed
|
||||
to linux-firmware. You may need to upgrade to a newer release of
|
||||
linux-firmware to obtain the firmware for your laptop.
|
||||
|
||||
**Important:** the Makefile for linux-firmware creates symlinks that are listed
|
||||
in the WHENCE file. These symlinks are required for the CS35L56 driver to be
|
||||
able to load the firmware.
|
||||
|
||||
How do I know which firmware file I should have?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
All firmware file names are qualified with a unique "system ID". On normal
|
||||
x86 PCs with PCI audio this is the Vendor Subsystem ID (SSID) of the host
|
||||
PCI audio interface.
|
||||
|
||||
The SSID can be viewed using the lspci tool::
|
||||
|
||||
lspci -v -nn | grep -A2 -i audio
|
||||
0000:00:1f.3 Audio device [0403]: Intel Corporation Meteor Lake-P HD Audio Controller [8086:7e28]
|
||||
Subsystem: Dell Meteor Lake-P HD Audio Controller [1028:0c63]
|
||||
|
||||
In this example the SSID is 10280c63.
|
||||
|
||||
The format of the firmware file names is:
|
||||
|
||||
cs35lxx-b0-dsp1-misc-SSID[-spkidX]-ampN
|
||||
|
||||
Where:
|
||||
|
||||
* cs35lxx-b0 is the amplifier model and silicon revision. This information
|
||||
is logged by the driver during initialization.
|
||||
* SSID is the 8-digit hexadecimal SSID value.
|
||||
* ampN is the amplifier number (for example amp1). This is the same as
|
||||
the prefix on the ALSA control names except that it is always lower-case
|
||||
in the file name.
|
||||
* spkidX is an optional part, used for laptops that have firmware
|
||||
configurations for different makes and models of internal speakers.
|
||||
|
||||
Sound Open Firmware and ALSA topology files
|
||||
-------------------------------------------
|
||||
|
||||
All SoundWire systems will require a Sound Open Firmware (SOF) for the
|
||||
host CPU audio DSP, together with an ALSA topology file (.tplg).
|
||||
|
||||
The SOF firmware will usually be provided by the manufacturer of the host
|
||||
CPU (i.e. Intel or AMD). The .tplg file is normally part of the SOF firmware
|
||||
release.
|
||||
|
||||
SOF binary builds are available from: https://github.com/thesofproject/sof-bin/releases
|
||||
|
||||
The main SOF source is here: https://github.com/thesofproject
|
||||
|
||||
ALSA-ucm configurations
|
||||
-----------------------
|
||||
Typically an appropriate ALSA-ucm configuration file is needed for
|
||||
use-case managers and audio servers such as PipeWire.
|
||||
|
||||
Configuration files are available from the alsa-ucm-conf repository:
|
||||
https://git.alsa-project.org/?p=alsa-ucm-conf.git
|
||||
|
||||
Kernel log messages
|
||||
===================
|
||||
|
||||
SoundWire
|
||||
---------
|
||||
A successful initialization will look like this (this will be repeated for
|
||||
each amplifier)::
|
||||
|
||||
[ 7.568374] cs35l56 sdw:0:0:01fa:3556:01:0: supply VDD_P not found, using dummy regulator
|
||||
[ 7.605208] cs35l56 sdw:0:0:01fa:3556:01:0: supply VDD_IO not found, using dummy regulator
|
||||
[ 7.605313] cs35l56 sdw:0:0:01fa:3556:01:0: supply VDD_A not found, using dummy regulator
|
||||
[ 7.939279] cs35l56 sdw:0:0:01fa:3556:01:0: Cirrus Logic CS35L56 Rev B0 OTP3 fw:3.4.4 (patched=0)
|
||||
[ 7.947844] cs35l56 sdw:0:0:01fa:3556:01:0: Slave 4 state check1: UNATTACHED, status was 1
|
||||
[ 8.740280] cs35l56 sdw:0:0:01fa:3556:01:0: supply VDD_B not found, using dummy regulator
|
||||
[ 8.740552] cs35l56 sdw:0:0:01fa:3556:01:0: supply VDD_AMP not found, using dummy regulator
|
||||
[ 9.242164] cs35l56 sdw:0:0:01fa:3556:01:0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx.wmfw: format 3 timestamp 0x66b2b872
|
||||
[ 9.242173] cs35l56 sdw:0:0:01fa:3556:01:0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx.wmfw: Tue 05 Dec 2023 21:37:21 GMT Standard Time
|
||||
[ 9.991709] cs35l56 sdw:0:0:01fa:3556:01:0: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.23, 41 algorithms
|
||||
[10.039098] cs35l56 sdw:0:0:01fa:3556:01:0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx-amp1.bin: v3.11.23
|
||||
[10.879235] cs35l56 sdw:0:0:01fa:3556:01:0: Slave 4 state check1: UNATTACHED, status was 1
|
||||
[11.401536] cs35l56 sdw:0:0:01fa:3556:01:0: Calibration applied
|
||||
|
||||
HDA
|
||||
---
|
||||
A successful initialization will look like this (this will be repeated for
|
||||
each amplifier)::
|
||||
|
||||
[ 6.306475] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: Cirrus Logic CS35L56 Rev B0 OTP3 fw:3.4.4 (patched=0)
|
||||
[ 6.613892] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: DSP system name: 'xxxxxxxx', amp name: 'AMP1'
|
||||
[ 8.266660] snd_hda_codec_cs8409 ehdaudio0D0: bound i2c-CSC3556:00-cs35l56-hda.0 (ops cs35l56_hda_comp_ops [snd_hda_scodec_cs35l56])
|
||||
[ 8.287525] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx.wmfw: format 3 timestamp 0x66b2b872
|
||||
[ 8.287528] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx.wmfw: Tue 05 Dec 2023 21:37:21 GMT Standard Time
|
||||
[ 9.984335] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: DSP1: Firmware: 1a00d6 vendor: 0x2 v3.11.23, 41 algorithms
|
||||
[10.085797] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx-amp1.bin: v3.11.23
|
||||
[10.655237] cs35l56-hda i2c-CSC3556:00-cs35l56-hda.0: Calibration applied
|
||||
|
||||
Important messages
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Cirrus Logic CS35L56 Rev B0 OTP3 fw:3.4.4 (patched=0)
|
||||
Shows that the driver has been able to read device ID registers from the
|
||||
amplifier.
|
||||
|
||||
* The actual amplifier type and silicon revision (CS35L56 B0 in this
|
||||
example) is shown, as read from the amplifier identification registers.
|
||||
* (patched=0) is normal, and indicates that the amplifier has been hard
|
||||
reset and is running default ROM firmware.
|
||||
* (patched=1) means that something has previously downloaded firmware
|
||||
to the amplifier and the driver does not have control of the RESET
|
||||
signal to be able to replace this preloaded firmware. This is normal
|
||||
for systems where the BIOS downloads firmware to the amplifiers
|
||||
before OS boot.
|
||||
This status can also be seen if the cs35l56 kernel module is unloaded
|
||||
and reloaded on a system where the driver does not have control of
|
||||
RESET. SoundWire systems typically do not give the driver control of
|
||||
RESET and only a BIOS (re)boot can reset the amplifiers.
|
||||
|
||||
DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx.wmfw
|
||||
Shows that a .wmfw firmware file was found and downloaded.
|
||||
|
||||
DSP1: cirrus/cs35l56-b0-dsp1-misc-xxxxxxxx-amp1.bin
|
||||
Shows that a .bin firmware file was found and downloaded.
|
||||
|
||||
Calibration applied
|
||||
Factory calibration data in EFI was written to the amplifier.
|
||||
|
||||
Error messages
|
||||
==============
|
||||
This section explains some of the error messages that the driver can log.
|
||||
|
||||
Algorithm coefficient version %d.%d.%d but expected %d.%d.%d
|
||||
The version of the .bin file content does not match the loaded firmware.
|
||||
Caused by mismatched .wmfw and .bin file, or .bin file was found but
|
||||
.wmfw was not.
|
||||
|
||||
No %s for algorithm %x
|
||||
The version of the .bin file content does not match the loaded firmware.
|
||||
Caused by mismatched .wmfw and .bin file, or .bin file was found but
|
||||
.wmfw was not.
|
||||
|
||||
.bin file required but not found
|
||||
HDA driver did not find a .bin file that matches this hardware.
|
||||
|
||||
Calibration disabled due to missing firmware controls
|
||||
Driver was not able to write EFI calibration data to firmware registers.
|
||||
This typically means that either:
|
||||
|
||||
* The driver did not find a suitable wmfw for this hardware, or
|
||||
* The amplifier has already been patched with firmware by something
|
||||
previously, and the driver does not have control of a hard RESET line
|
||||
to be able to reset the amplifier and download the firmware files it
|
||||
found. This situation is indicated by the device identification
|
||||
string in the kernel log shows "(patched=1)"
|
||||
|
||||
Failed to write calibration
|
||||
Same meaning and cause as "Calibration disabled due to missing firmware
|
||||
controls"
|
||||
|
||||
Failed to read calibration data from EFI
|
||||
Factory calibration data in EFI is missing, empty or corrupt.
|
||||
This is most likely to be cause by accidentally deleting the file from
|
||||
the EFI filesystem.
|
||||
|
||||
No calibration for silicon ID
|
||||
The factory calibration data in EFI does not match this hardware.
|
||||
The most likely cause is that an amplifier has been replaced on the
|
||||
motherboard without going through manufacturer calibration process to
|
||||
generate calibration data for the new amplifier.
|
||||
|
||||
Did not find any buses for CSCxxxx
|
||||
Only on HDA systems. The HDA codec driver found an ACPI entry for
|
||||
Cirrus Logic companion amps, but could not enumerate the ACPI entries for
|
||||
the I2C/SPI buses. The most likely cause of this is that:
|
||||
|
||||
* The relevant bus driver (I2C or SPI) is not part of the kernel.
|
||||
* The HDA codec driver was built-in to the kernel but the I2C/SPI
|
||||
bus driver is a module and so the HDA codec driver cannot call the
|
||||
bus driver functions.
|
||||
|
||||
init_completion timed out
|
||||
The SoundWire bus controller (host end) did not enumerate the amplifier.
|
||||
In other words, the ACPI says there is an amplifier but for some reason
|
||||
it was not detected on the bus.
|
||||
|
||||
No AF01 node
|
||||
Indicates an error in ACPI. A SoundWire system should have a Device()
|
||||
node named "AF01" but it was not found.
|
||||
|
||||
Failed to get spk-id-gpios
|
||||
ACPI says that the driver should request a GPIO but the driver was not
|
||||
able to get that GPIO. The most likely cause is that the kernel does not
|
||||
include the correct GPIO or PINCTRL driver for this system.
|
||||
|
||||
Failed to read spk-id
|
||||
ACPI says that the driver should request a GPIO but the driver was not
|
||||
able to read that GPIO.
|
||||
|
||||
Unexpected spk-id element count
|
||||
AF01 contains more speaker ID GPIO entries than the driver supports
|
||||
|
||||
Overtemp error
|
||||
Amplifier overheat protection was triggered and the amplifier shut down
|
||||
to protect itself.
|
||||
|
||||
Amp short error
|
||||
Amplifier detected a short-circuit on the speaker output pins and shut
|
||||
down for protection. This would normally indicate a damaged speaker.
|
||||
|
||||
Hibernate wake failed
|
||||
The driver tried to wake the amplifier from its power-saving state but
|
||||
did not see the expected responses from the amplifier. This can be caused
|
||||
by using firmware that does not match the hardware.
|
|
@ -0,0 +1,9 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Codec-Specific Information
|
||||
==========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
cs35l56
|
|
@ -0,0 +1,134 @@
|
|||
==================================
|
||||
ALSA Co-processor Acceleration API
|
||||
==================================
|
||||
|
||||
Jaroslav Kysela <perex@perex.cz>
|
||||
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
There is a requirement to expose the audio hardware that accelerates various
|
||||
tasks for user space such as sample rate converters, compressed
|
||||
stream decoders, etc.
|
||||
|
||||
This is description for the API extension for the compress ALSA API which
|
||||
is able to handle "tasks" that are not bound to real-time operations
|
||||
and allows for the serialization of operations.
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
The main requirements are:
|
||||
|
||||
- serialization of multiple tasks for user space to allow multiple
|
||||
operations without user space intervention
|
||||
|
||||
- separate buffers (input + output) for each operation
|
||||
|
||||
- expose buffers using mmap to user space
|
||||
|
||||
- signal user space when the task is finished (standard poll mechanism)
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
A new direction SND_COMPRESS_ACCEL is introduced to identify
|
||||
the passthrough API.
|
||||
|
||||
The API extension shares device enumeration and parameters handling from
|
||||
the main compressed API. All other realtime streaming ioctls are deactivated
|
||||
and a new set of task related ioctls are introduced. The standard
|
||||
read/write/mmap I/O operations are not supported in the passthrough device.
|
||||
|
||||
Device ("stream") state handling is reduced to OPEN/SETUP. All other
|
||||
states are not available for the passthrough mode.
|
||||
|
||||
Data I/O mechanism is using standard dma-buf interface with all advantages
|
||||
like mmap, standard I/O, buffer sharing etc. One buffer is used for the
|
||||
input data and second (separate) buffer is used for the output data. Each task
|
||||
have separate I/O buffers.
|
||||
|
||||
For the buffering parameters, the fragments means a limit of allocated tasks
|
||||
for given device. The fragment_size limits the input buffer size for the given
|
||||
device. The output buffer size is determined by the driver (may be different
|
||||
from the input buffer size).
|
||||
|
||||
State Machine
|
||||
=============
|
||||
|
||||
The passthrough audio stream state machine is described below::
|
||||
|
||||
+----------+
|
||||
| |
|
||||
| OPEN |
|
||||
| |
|
||||
+----------+
|
||||
|
|
||||
|
|
||||
| compr_set_params()
|
||||
|
|
||||
v
|
||||
all passthrough task ops +----------+
|
||||
+------------------------------------| |
|
||||
| | SETUP |
|
||||
| |
|
||||
| +----------+
|
||||
| |
|
||||
+------------------------------------------+
|
||||
|
||||
|
||||
Passthrough operations (ioctls)
|
||||
===============================
|
||||
|
||||
All operations are protected using stream->device->lock (mutex).
|
||||
|
||||
CREATE
|
||||
------
|
||||
Creates a set of input/output buffers. The input buffer size is
|
||||
fragment_size. Allocates unique seqno.
|
||||
|
||||
The hardware drivers allocate internal 'struct dma_buf' for both input and
|
||||
output buffers (using 'dma_buf_export()' function). The anonymous
|
||||
file descriptors for those buffers are passed to user space.
|
||||
|
||||
FREE
|
||||
----
|
||||
Free a set of input/output buffers. If a task is active, the stop
|
||||
operation is executed before. If seqno is zero, operation is executed for all
|
||||
tasks.
|
||||
|
||||
START
|
||||
-----
|
||||
Starts (queues) a task. There are two cases of the task start - right after
|
||||
the task is created. In this case, origin_seqno must be zero.
|
||||
The second case is for reusing of already finished task. The origin_seqno
|
||||
must identify the task to be reused. In both cases, a new seqno value
|
||||
is allocated and returned to user space.
|
||||
|
||||
The prerequisite is that application filled input dma buffer with
|
||||
new source data and set input_size to pass the real data size to the driver.
|
||||
|
||||
The order of data processing is preserved (first started job must be
|
||||
finished at first).
|
||||
|
||||
If the multiple tasks require a state handling (e.g. resampling operation),
|
||||
the user space may set SND_COMPRESS_TFLG_NEW_STREAM flag to mark the
|
||||
start of the new stream data. It is useful to keep the allocated buffers
|
||||
for the new operation rather using open/close mechanism.
|
||||
|
||||
STOP
|
||||
----
|
||||
Stop (dequeues) a task. If seqno is zero, operation is executed for all
|
||||
tasks.
|
||||
|
||||
STATUS
|
||||
------
|
||||
Obtain the task status (active, finished). Also, the driver will set
|
||||
the real output data size (valid area in the output buffer).
|
||||
|
||||
Credits
|
||||
=======
|
||||
- Shengjiu Wang <shengjiu.wang@gmail.com>
|
||||
- Takashi Iwai <tiwai@suse.de>
|
||||
- Vinod Koul <vkoul@kernel.org>
|
|
@ -6,6 +6,7 @@ Designs and Implementations
|
|||
|
||||
control-names
|
||||
channel-mapping-api
|
||||
compress-accel
|
||||
compress-offload
|
||||
timestamping
|
||||
jack-controls
|
||||
|
|
|
@ -42,7 +42,7 @@ If you are interested in the deep debugging of HD-audio, read the
|
|||
HD-audio specification at first. The specification is found on
|
||||
Intel's web page, for example:
|
||||
|
||||
* https://www.intel.com/standards/hdaudio/
|
||||
* https://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html
|
||||
|
||||
|
||||
HD-Audio Controller
|
||||
|
|
|
@ -13,6 +13,7 @@ Sound Subsystem Documentation
|
|||
alsa-configuration
|
||||
hd-audio/index
|
||||
cards/index
|
||||
codecs/index
|
||||
utimers
|
||||
|
||||
.. only:: subproject and html
|
||||
|
|
|
@ -42,5 +42,17 @@ rate, number of channels and word size) to save on power.
|
|||
It is also desirable to use the codec (if possible) to drive (or master) the
|
||||
audio clocks as it usually gives more accurate sample rates than the CPU.
|
||||
|
||||
ASoC provided clock APIs
|
||||
------------------------
|
||||
|
||||
.. kernel-doc:: sound/soc/soc-dai.c
|
||||
:identifiers: snd_soc_dai_set_sysclk
|
||||
|
||||
.. kernel-doc:: sound/soc/soc-dai.c
|
||||
:identifiers: snd_soc_dai_set_clkdiv
|
||||
|
||||
.. kernel-doc:: sound/soc/soc-dai.c
|
||||
:identifiers: snd_soc_dai_set_pll
|
||||
|
||||
.. kernel-doc:: sound/soc/soc-dai.c
|
||||
:identifiers: snd_soc_dai_set_bclk_ratio
|
||||
|
|
|
@ -35,6 +35,9 @@ The graph for the STM32MP1-DK1 sound card is shown in picture:
|
|||
:alt: Example DAPM graph
|
||||
:align: center
|
||||
|
||||
You can also generate compatible graph for your sound card using
|
||||
`tools/sound/dapm-graph` utility.
|
||||
|
||||
DAPM power domains
|
||||
==================
|
||||
|
||||
|
|
|
@ -157,15 +157,13 @@ FE DAI links are defined as follows :-
|
|||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.dynamic = 1,
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
},
|
||||
.....< other FE and BE DAI links here >
|
||||
};
|
||||
|
||||
This FE DAI link is pretty similar to a regular DAI link except that we also
|
||||
set the DAI link to a DPCM FE with the ``dynamic = 1``. The supported FE stream
|
||||
directions should also be set with the ``dpcm_playback`` and ``dpcm_capture``
|
||||
flags. There is also an option to specify the ordering of the trigger call for
|
||||
set the DAI link to a DPCM FE with the ``dynamic = 1``.
|
||||
There is also an option to specify the ordering of the trigger call for
|
||||
each FE. This allows the ASoC core to trigger the DSP before or after the other
|
||||
components (as some DSPs have strong requirements for the ordering DAI/DSP
|
||||
start and stop sequences).
|
||||
|
@ -189,15 +187,12 @@ The BE DAIs are configured as follows :-
|
|||
.ignore_pmdown_time = 1,
|
||||
.be_hw_params_fixup = hswult_ssp0_fixup,
|
||||
.ops = &haswell_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
.....< other BE DAI links here >
|
||||
};
|
||||
|
||||
This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets
|
||||
the ``no_pcm`` flag to mark it has a BE and sets flags for supported stream
|
||||
directions using ``dpcm_playback`` and ``dpcm_capture`` above.
|
||||
the ``no_pcm`` flag to mark it has a BE.
|
||||
|
||||
The BE has also flags set for ignoring suspend and PM down time. This allows
|
||||
the BE to work in a hostless mode where the host CPU is not transferring data
|
||||
|
|
|
@ -71,6 +71,18 @@ struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
|
|||
.ops = &corgi_ops,
|
||||
};
|
||||
|
||||
In the above struct, dai’s are registered using names but you can pass
|
||||
either dai name or device tree node but not both. Also, names used here
|
||||
for cpu/codec/platform dais should be globally unique.
|
||||
|
||||
Additionaly below example macro can be used to register cpu, codec and
|
||||
platform dai::
|
||||
|
||||
SND_SOC_DAILINK_DEFS(wm2200_cpu_dsp,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")),
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")),
|
||||
DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
|
||||
|
||||
struct snd_soc_card then sets up the machine with its DAIs. e.g.
|
||||
::
|
||||
|
||||
|
@ -81,6 +93,10 @@ struct snd_soc_card then sets up the machine with its DAIs. e.g.
|
|||
.num_links = 1,
|
||||
};
|
||||
|
||||
Following this, ``devm_snd_soc_register_card`` can be used to register
|
||||
the sound card. During the registration, the individual components
|
||||
such as the codec, CPU, and platform are probed. If all these components
|
||||
are successfully probed, the sound card gets registered.
|
||||
|
||||
Machine Power Map
|
||||
-----------------
|
||||
|
@ -95,3 +111,13 @@ Machine Controls
|
|||
----------------
|
||||
|
||||
Machine specific audio mixer controls can be added in the DAI init function.
|
||||
|
||||
|
||||
Clocking Controls
|
||||
-----------------
|
||||
|
||||
As previously noted, clock configuration is handled within the machine driver.
|
||||
For details on the clock APIs that the machine driver can utilize for
|
||||
setup, please refer to Documentation/sound/soc/clocking.rst. However, the
|
||||
callback needs to be registered by the CPU/Codec/Platform drivers to configure
|
||||
the clocks that is needed for the corresponding device operation.
|
||||
|
|
|
@ -1242,6 +1242,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
|||
S: Supported
|
||||
W: http://wiki.analog.com/
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
F: Documentation/devicetree/bindings/sound/adi,*
|
||||
F: sound/soc/codecs/ad1*
|
||||
F: sound/soc/codecs/ad7*
|
||||
F: sound/soc/codecs/adau*
|
||||
|
@ -1807,6 +1808,7 @@ F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
|
|||
F: Documentation/devicetree/bindings/sound/apple,*
|
||||
F: sound/soc/apple/*
|
||||
F: sound/soc/codecs/cs42l83-i2c.c
|
||||
F: sound/soc/codecs/cs42l84.*
|
||||
F: sound/soc/codecs/ssm3515.c
|
||||
|
||||
ARM/ARTPEC MACHINE SUPPORT
|
||||
|
@ -4572,6 +4574,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
|||
L: patches@opensource.cirrus.com
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/cirrus,cs*
|
||||
F: Documentation/sound/codecs/cs*
|
||||
F: drivers/mfd/cs42l43*
|
||||
F: drivers/pinctrl/cirrus/pinctrl-cs42l43*
|
||||
F: include/dt-bindings/sound/cs*
|
||||
|
|
|
@ -967,7 +967,6 @@ static void cs42l43_boot_work(struct work_struct *work)
|
|||
|
||||
err:
|
||||
pm_runtime_put_sync(cs42l43->dev);
|
||||
cs42l43_dev_remove(cs42l43);
|
||||
}
|
||||
|
||||
static int cs42l43_power_up(struct cs42l43 *cs42l43)
|
||||
|
@ -1101,6 +1100,8 @@ EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43);
|
|||
|
||||
void cs42l43_dev_remove(struct cs42l43 *cs42l43)
|
||||
{
|
||||
cancel_work_sync(&cs42l43->boot_work);
|
||||
|
||||
cs42l43_power_down(cs42l43);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43);
|
||||
|
@ -1108,16 +1109,39 @@ EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43);
|
|||
static int cs42l43_suspend(struct device *dev)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
|
||||
static const struct reg_sequence mask_all[] = {
|
||||
{ CS42L43_DECIM_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_EQ_MIX_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_ASP_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_PLL_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_SOFT_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_SWIRE_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_MSM_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_ACC_DET_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_I2C_TGT_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_SPI_MSTR_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_SW_TO_SPI_BRIDGE_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_OTP_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_CLASS_D_AMP_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_GPIO_INT_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_ASRC_MASK, 0xFFFFFFFF, },
|
||||
{ CS42L43_HPOUT_MASK, 0xFFFFFFFF, },
|
||||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Don't care about being resumed here, but the driver does want
|
||||
* force_resume to always trigger an actual resume, so that register
|
||||
* state for the MCU/GPIOs is returned as soon as possible after system
|
||||
* resume. force_resume will resume if the reference count is resumed on
|
||||
* suspend hence the get_noresume.
|
||||
*/
|
||||
pm_runtime_get_noresume(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret) {
|
||||
dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The IRQs will be re-enabled on resume by the cache sync */
|
||||
ret = regmap_multi_reg_write_bypassed(cs42l43->regmap,
|
||||
mask_all, ARRAY_SIZE(mask_all));
|
||||
if (ret) {
|
||||
dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret) {
|
||||
|
@ -1132,6 +1156,26 @@ static int cs42l43_suspend(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
disable_irq(cs42l43->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
|
||||
|
||||
enable_irq(cs42l43->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
|
||||
|
||||
disable_irq(cs42l43->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1144,6 +1188,8 @@ static int cs42l43_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
enable_irq(cs42l43->irq);
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret) {
|
||||
dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret);
|
||||
|
@ -1211,6 +1257,7 @@ err:
|
|||
|
||||
EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = {
|
||||
SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume)
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend_noirq, cs42l43_resume_noirq)
|
||||
RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
menuconfig SOUNDWIRE
|
||||
tristate "SoundWire support"
|
||||
depends on ACPI || OF
|
||||
depends on SND_SOC_SDCA_OPTIONAL
|
||||
help
|
||||
SoundWire is a 2-Pin interface with data and clock line ratified
|
||||
by the MIPI Alliance. SoundWire is used for transporting data
|
||||
|
|
|
@ -121,6 +121,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
|
|||
|
||||
sdw_pdata[index].instance = index;
|
||||
sdw_pdata[index].acp_sdw_lock = res->acp_lock;
|
||||
sdw_pdata[index].acp_rev = res->acp_rev;
|
||||
pdevinfo[index].name = "amd_sdw_manager";
|
||||
pdevinfo[index].id = index;
|
||||
pdevinfo[index].parent = res->parent;
|
||||
|
@ -177,7 +178,7 @@ EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
|
|||
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
|
||||
{
|
||||
sdw_amd_cleanup(ctx);
|
||||
kfree(ctx->ids);
|
||||
kfree(ctx->peripherals);
|
||||
kfree(ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
|
||||
|
@ -204,10 +205,11 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
|||
num_slaves++;
|
||||
}
|
||||
|
||||
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
|
||||
if (!ctx->ids)
|
||||
ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->peripherals)
|
||||
return -ENOMEM;
|
||||
ctx->num_slaves = num_slaves;
|
||||
ctx->peripherals->num_peripherals = num_slaves;
|
||||
for (index = 0; index < ctx->count; index++) {
|
||||
if (!(ctx->link_mask & BIT(index)))
|
||||
continue;
|
||||
|
@ -215,8 +217,7 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
|||
if (amd_manager) {
|
||||
bus = &amd_manager->bus;
|
||||
list_for_each_entry(slave, &bus->slaves, node) {
|
||||
ctx->ids[i].id = slave->id;
|
||||
ctx->ids[i].link_id = bus->link_id;
|
||||
ctx->peripherals->array[i] = slave;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -433,12 +433,18 @@ static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_pa
|
|||
u32 frame_fmt_reg, dpn_frame_fmt;
|
||||
|
||||
dev_dbg(amd_manager->dev, "p_params->num:0x%x\n", p_params->num);
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
frame_fmt_reg = sdw0_manager_dp_reg[p_params->num].frame_fmt_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
frame_fmt_reg = sdw1_manager_dp_reg[p_params->num].frame_fmt_reg;
|
||||
switch (amd_manager->acp_rev) {
|
||||
case ACP63_PCI_REV_ID:
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
frame_fmt_reg = acp63_sdw0_dp_reg[p_params->num].frame_fmt_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
frame_fmt_reg = acp63_sdw1_dp_reg[p_params->num].frame_fmt_reg;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -465,20 +471,28 @@ static int amd_sdw_transport_params(struct sdw_bus *bus,
|
|||
u32 frame_fmt_reg, sample_int_reg, hctrl_dp0_reg;
|
||||
u32 offset_reg, lane_ctrl_ch_en_reg;
|
||||
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
frame_fmt_reg = sdw0_manager_dp_reg[params->port_num].frame_fmt_reg;
|
||||
sample_int_reg = sdw0_manager_dp_reg[params->port_num].sample_int_reg;
|
||||
hctrl_dp0_reg = sdw0_manager_dp_reg[params->port_num].hctrl_dp0_reg;
|
||||
offset_reg = sdw0_manager_dp_reg[params->port_num].offset_reg;
|
||||
lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
frame_fmt_reg = sdw1_manager_dp_reg[params->port_num].frame_fmt_reg;
|
||||
sample_int_reg = sdw1_manager_dp_reg[params->port_num].sample_int_reg;
|
||||
hctrl_dp0_reg = sdw1_manager_dp_reg[params->port_num].hctrl_dp0_reg;
|
||||
offset_reg = sdw1_manager_dp_reg[params->port_num].offset_reg;
|
||||
lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
|
||||
switch (amd_manager->acp_rev) {
|
||||
case ACP63_PCI_REV_ID:
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
frame_fmt_reg = acp63_sdw0_dp_reg[params->port_num].frame_fmt_reg;
|
||||
sample_int_reg = acp63_sdw0_dp_reg[params->port_num].sample_int_reg;
|
||||
hctrl_dp0_reg = acp63_sdw0_dp_reg[params->port_num].hctrl_dp0_reg;
|
||||
offset_reg = acp63_sdw0_dp_reg[params->port_num].offset_reg;
|
||||
lane_ctrl_ch_en_reg =
|
||||
acp63_sdw0_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
frame_fmt_reg = acp63_sdw1_dp_reg[params->port_num].frame_fmt_reg;
|
||||
sample_int_reg = acp63_sdw1_dp_reg[params->port_num].sample_int_reg;
|
||||
hctrl_dp0_reg = acp63_sdw1_dp_reg[params->port_num].hctrl_dp0_reg;
|
||||
offset_reg = acp63_sdw1_dp_reg[params->port_num].offset_reg;
|
||||
lane_ctrl_ch_en_reg =
|
||||
acp63_sdw1_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -520,12 +534,20 @@ static int amd_sdw_port_enable(struct sdw_bus *bus,
|
|||
u32 dpn_ch_enable;
|
||||
u32 lane_ctrl_ch_en_reg;
|
||||
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
|
||||
switch (amd_manager->acp_rev) {
|
||||
case ACP63_PCI_REV_ID:
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
lane_ctrl_ch_en_reg =
|
||||
acp63_sdw0_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
lane_ctrl_ch_en_reg =
|
||||
acp63_sdw1_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -910,6 +932,7 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
|||
amd_manager->mmio = amd_manager->acp_mmio +
|
||||
(amd_manager->instance * SDW_MANAGER_REG_OFFSET);
|
||||
amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
|
||||
amd_manager->acp_rev = pdata->acp_rev;
|
||||
amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
|
||||
amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
|
||||
amd_manager->dev = dev;
|
||||
|
@ -926,15 +949,21 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
|||
* information.
|
||||
*/
|
||||
amd_manager->bus.controller_id = 0;
|
||||
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
amd_manager->num_dout_ports = AMD_SDW0_MAX_TX_PORTS;
|
||||
amd_manager->num_din_ports = AMD_SDW0_MAX_RX_PORTS;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
amd_manager->num_dout_ports = AMD_SDW1_MAX_TX_PORTS;
|
||||
amd_manager->num_din_ports = AMD_SDW1_MAX_RX_PORTS;
|
||||
dev_dbg(dev, "acp_rev:0x%x\n", amd_manager->acp_rev);
|
||||
switch (amd_manager->acp_rev) {
|
||||
case ACP63_PCI_REV_ID:
|
||||
switch (amd_manager->instance) {
|
||||
case ACP_SDW0:
|
||||
amd_manager->num_dout_ports = AMD_ACP63_SDW0_MAX_TX_PORTS;
|
||||
amd_manager->num_din_ports = AMD_ACP63_SDW0_MAX_RX_PORTS;
|
||||
break;
|
||||
case ACP_SDW1:
|
||||
amd_manager->num_dout_ports = AMD_ACP63_SDW1_MAX_TX_PORTS;
|
||||
amd_manager->num_din_ports = AMD_ACP63_SDW1_MAX_RX_PORTS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
|
@ -155,12 +155,12 @@
|
|||
#define AMD_SDW_IRQ_MASK_8TO11 0x000c7777
|
||||
#define AMD_SDW_IRQ_ERROR_MASK 0xff
|
||||
#define AMD_SDW_MAX_FREQ_NUM 1
|
||||
#define AMD_SDW0_MAX_TX_PORTS 3
|
||||
#define AMD_SDW0_MAX_RX_PORTS 3
|
||||
#define AMD_SDW1_MAX_TX_PORTS 1
|
||||
#define AMD_SDW1_MAX_RX_PORTS 1
|
||||
#define AMD_SDW0_MAX_DAI 6
|
||||
#define AMD_SDW1_MAX_DAI 2
|
||||
#define AMD_ACP63_SDW0_MAX_TX_PORTS 3
|
||||
#define AMD_ACP63_SDW0_MAX_RX_PORTS 3
|
||||
#define AMD_ACP63_SDW1_MAX_TX_PORTS 1
|
||||
#define AMD_ACP63_SDW1_MAX_RX_PORTS 1
|
||||
#define AMD_ACP63_SDW0_MAX_DAI 6
|
||||
#define AMD_ACP63_SDW1_MAX_DAI 2
|
||||
#define AMD_SDW_SLAVE_0_ATTACHED 5
|
||||
#define AMD_SDW_SSP_COUNTER_VAL 3
|
||||
|
||||
|
@ -222,7 +222,7 @@ struct sdw_manager_dp_reg {
|
|||
* in SoundWire DMA driver.
|
||||
*/
|
||||
|
||||
static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = {
|
||||
static struct sdw_manager_dp_reg acp63_sdw0_dp_reg[AMD_ACP63_SDW0_MAX_DAI] = {
|
||||
{ACP_SW_AUDIO0_TX_FRAME_FORMAT, ACP_SW_AUDIO0_TX_SAMPLEINTERVAL, ACP_SW_AUDIO0_TX_HCTRL_DP0,
|
||||
ACP_SW_AUDIO0_TX_OFFSET_DP0, ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0},
|
||||
{ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
|
||||
|
@ -237,7 +237,7 @@ static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = {
|
|||
ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0},
|
||||
};
|
||||
|
||||
static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = {
|
||||
static struct sdw_manager_dp_reg acp63_sdw1_dp_reg[AMD_ACP63_SDW1_MAX_DAI] = {
|
||||
{ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
|
||||
ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0},
|
||||
{ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL,
|
||||
|
|
|
@ -112,7 +112,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
|||
/* Set higher order bits */
|
||||
*bus->assigned = ~GENMASK(SDW_BROADCAST_DEV_NUM, SDW_ENUM_DEV_NUM);
|
||||
|
||||
/* Set enumuration device number and broadcast device number */
|
||||
/* Set enumeration device number and broadcast device number */
|
||||
set_bit(SDW_ENUM_DEV_NUM, bus->assigned);
|
||||
set_bit(SDW_BROADCAST_DEV_NUM, bus->assigned);
|
||||
|
||||
|
|
|
@ -1377,6 +1377,31 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
|
|||
cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_cdns_soft_reset() - Cadence soft-reset
|
||||
* @cdns: Cadence instance
|
||||
*/
|
||||
int sdw_cdns_soft_reset(struct sdw_cdns *cdns)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST,
|
||||
CDNS_MCP_CONTROL_SOFT_RST);
|
||||
|
||||
ret = cdns_config_update(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(cdns->dev, "%s: config update failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cdns_set_wait(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST, 0);
|
||||
if (ret < 0)
|
||||
dev_err(cdns->dev, "%s: Soft Reset timed out\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_cdns_soft_reset);
|
||||
|
||||
/**
|
||||
* sdw_cdns_init() - Cadence initialization
|
||||
* @cdns: Cadence instance
|
||||
|
@ -1400,6 +1425,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
|
|||
cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
|
||||
CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
|
||||
|
||||
/* disable wakeup */
|
||||
cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
|
||||
CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP,
|
||||
0);
|
||||
|
||||
/* Configure mcp config */
|
||||
val = cdns_readl(cdns, CDNS_MCP_CONFIG);
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns);
|
|||
irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
|
||||
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
|
||||
|
||||
int sdw_cdns_soft_reset(struct sdw_cdns *cdns);
|
||||
int sdw_cdns_init(struct sdw_cdns *cdns);
|
||||
int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
|
||||
struct sdw_cdns_stream_config config);
|
||||
|
|
|
@ -175,6 +175,9 @@ static int intel_link_power_up(struct sdw_intel *sdw)
|
|||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true,
|
||||
AZX_REG_ML_LEPTR_ID_SDW, true);
|
||||
}
|
||||
|
||||
*shim_mask |= BIT(link_id);
|
||||
|
@ -201,6 +204,10 @@ static int intel_link_power_down(struct sdw_intel *sdw)
|
|||
|
||||
*shim_mask &= ~BIT(link_id);
|
||||
|
||||
if (!*shim_mask)
|
||||
hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true,
|
||||
AZX_REG_ML_LEPTR_ID_SDW, false);
|
||||
|
||||
ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
|
||||
if (ret < 0) {
|
||||
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
|
||||
|
|
|
@ -16,6 +16,12 @@ int intel_start_bus(struct sdw_intel *sdw)
|
|||
struct sdw_bus *bus = &cdns->bus;
|
||||
int ret;
|
||||
|
||||
ret = sdw_cdns_soft_reset(cdns);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to soft-reset Cadence IP: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* follow recommended programming flows to avoid timeouts when
|
||||
* gsync is enabled
|
||||
|
|
|
@ -252,17 +252,16 @@ static struct sdw_intel_ctx
|
|||
num_slaves++;
|
||||
}
|
||||
|
||||
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
|
||||
if (!ctx->ids)
|
||||
ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->peripherals)
|
||||
goto err;
|
||||
|
||||
ctx->num_slaves = num_slaves;
|
||||
ctx->peripherals->num_peripherals = num_slaves;
|
||||
i = 0;
|
||||
list_for_each_entry(link, &ctx->link_list, list) {
|
||||
bus = &link->cdns->bus;
|
||||
list_for_each_entry(slave, &bus->slaves, node) {
|
||||
ctx->ids[i].id = slave->id;
|
||||
ctx->ids[i].link_id = bus->link_id;
|
||||
ctx->peripherals->array[i] = slave;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +370,7 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx)
|
|||
}
|
||||
|
||||
sdw_intel_cleanup(ctx);
|
||||
kfree(ctx->ids);
|
||||
kfree(ctx->peripherals);
|
||||
kfree(ctx->ldev);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,26 @@
|
|||
#include <linux/soundwire/sdw.h>
|
||||
#include "bus.h"
|
||||
|
||||
static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode,
|
||||
const char *propname)
|
||||
{
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
if (!fwnode_property_present(fwnode, propname))
|
||||
return false;
|
||||
ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
return !!val;
|
||||
}
|
||||
|
||||
static bool mipi_device_property_read_bool(const struct device *dev,
|
||||
const char *propname)
|
||||
{
|
||||
return mipi_fwnode_property_read_bool(dev_fwnode(dev), propname);
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_master_read_prop() - Read Master properties
|
||||
* @bus: SDW bus instance
|
||||
|
@ -31,8 +51,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
{
|
||||
struct sdw_master_prop *prop = &bus->prop;
|
||||
struct fwnode_handle *link;
|
||||
const char *scales_prop;
|
||||
char name[32];
|
||||
int nval, i;
|
||||
int nval;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
device_property_read_u32(bus->dev,
|
||||
"mipi-sdw-sw-interface-revision",
|
||||
|
@ -48,11 +71,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (fwnode_property_read_bool(link,
|
||||
if (mipi_fwnode_property_read_bool(link,
|
||||
"mipi-sdw-clock-stop-mode0-supported"))
|
||||
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0);
|
||||
|
||||
if (fwnode_property_read_bool(link,
|
||||
if (mipi_fwnode_property_read_bool(link,
|
||||
"mipi-sdw-clock-stop-mode1-supported"))
|
||||
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1);
|
||||
|
||||
|
@ -71,9 +94,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32_array(link,
|
||||
ret = fwnode_property_read_u32_array(link,
|
||||
"mipi-sdw-clock-frequencies-supported",
|
||||
prop->clk_freq, prop->num_clk_freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,7 +113,12 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
}
|
||||
}
|
||||
|
||||
nval = fwnode_property_count_u32(link, "mipi-sdw-supported-clock-gears");
|
||||
scales_prop = "mipi-sdw-supported-clock-scales";
|
||||
nval = fwnode_property_count_u32(link, scales_prop);
|
||||
if (nval == 0) {
|
||||
scales_prop = "mipi-sdw-supported-clock-gears";
|
||||
nval = fwnode_property_count_u32(link, scales_prop);
|
||||
}
|
||||
if (nval > 0) {
|
||||
prop->num_clk_gears = nval;
|
||||
prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears,
|
||||
|
@ -99,10 +129,12 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32_array(link,
|
||||
"mipi-sdw-supported-clock-gears",
|
||||
ret = fwnode_property_read_u32_array(link,
|
||||
scales_prop,
|
||||
prop->clk_gears,
|
||||
prop->num_clk_gears);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate",
|
||||
|
@ -114,7 +146,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size",
|
||||
&prop->default_col);
|
||||
|
||||
prop->dynamic_frame = fwnode_property_read_bool(link,
|
||||
prop->dynamic_frame = mipi_fwnode_property_read_bool(link,
|
||||
"mipi-sdw-dynamic-frame-shape");
|
||||
|
||||
fwnode_property_read_u32(link, "mipi-sdw-command-error-threshold",
|
||||
|
@ -131,6 +163,7 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
|
|||
struct sdw_dp0_prop *dp0)
|
||||
{
|
||||
int nval;
|
||||
int ret;
|
||||
|
||||
fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength",
|
||||
&dp0->max_word);
|
||||
|
@ -148,20 +181,38 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
|
|||
if (!dp0->words)
|
||||
return -ENOMEM;
|
||||
|
||||
fwnode_property_read_u32_array(port,
|
||||
ret = fwnode_property_read_u32_array(port,
|
||||
"mipi-sdw-port-wordlength-configs",
|
||||
dp0->words, dp0->num_words);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dp0->BRA_flow_controlled = fwnode_property_read_bool(port,
|
||||
dp0->BRA_flow_controlled = mipi_fwnode_property_read_bool(port,
|
||||
"mipi-sdw-bra-flow-controlled");
|
||||
|
||||
dp0->simple_ch_prep_sm = fwnode_property_read_bool(port,
|
||||
dp0->simple_ch_prep_sm = mipi_fwnode_property_read_bool(port,
|
||||
"mipi-sdw-simplified-channel-prepare-sm");
|
||||
|
||||
dp0->imp_def_interrupts = fwnode_property_read_bool(port,
|
||||
dp0->imp_def_interrupts = mipi_fwnode_property_read_bool(port,
|
||||
"mipi-sdw-imp-def-dp0-interrupts-supported");
|
||||
|
||||
nval = fwnode_property_count_u32(port, "mipi-sdw-lane-list");
|
||||
if (nval > 0) {
|
||||
dp0->num_lanes = nval;
|
||||
dp0->lane_list = devm_kcalloc(&slave->dev,
|
||||
dp0->num_lanes, sizeof(*dp0->lane_list),
|
||||
GFP_KERNEL);
|
||||
if (!dp0->lane_list)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fwnode_property_read_u32_array(port,
|
||||
"mipi-sdw-lane-list",
|
||||
dp0->lane_list, dp0->num_lanes);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -171,9 +222,10 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
{
|
||||
struct fwnode_handle *node;
|
||||
u32 bit, i = 0;
|
||||
int nval;
|
||||
unsigned long addr;
|
||||
char name[40];
|
||||
int nval;
|
||||
int ret;
|
||||
|
||||
addr = ports;
|
||||
/* valid ports are 1 to 14 so apply mask */
|
||||
|
@ -208,9 +260,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32_array(node,
|
||||
ret = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-port-wordlength-configs",
|
||||
dpn[i].words, dpn[i].num_words);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32(node, "mipi-sdw-data-port-type",
|
||||
|
@ -220,7 +274,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
"mipi-sdw-max-grouping-supported",
|
||||
&dpn[i].max_grouping);
|
||||
|
||||
dpn[i].simple_ch_prep_sm = fwnode_property_read_bool(node,
|
||||
dpn[i].simple_ch_prep_sm = mipi_fwnode_property_read_bool(node,
|
||||
"mipi-sdw-simplified-channelprepare-sm");
|
||||
|
||||
fwnode_property_read_u32(node,
|
||||
|
@ -249,9 +303,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32_array(node,
|
||||
ret = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-channel-number-list",
|
||||
dpn[i].channels, dpn[i].num_channels);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list");
|
||||
|
@ -266,10 +322,12 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32_array(node,
|
||||
ret = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-channel-combination-list",
|
||||
dpn[i].ch_combinations,
|
||||
dpn[i].num_ch_combinations);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32(node,
|
||||
|
@ -278,13 +336,27 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
fwnode_property_read_u32(node, "mipi-sdw-max-async-buffer",
|
||||
&dpn[i].max_async_buffer);
|
||||
|
||||
dpn[i].block_pack_mode = fwnode_property_read_bool(node,
|
||||
dpn[i].block_pack_mode = mipi_fwnode_property_read_bool(node,
|
||||
"mipi-sdw-block-packing-mode");
|
||||
|
||||
fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type",
|
||||
&dpn[i].port_encoding);
|
||||
|
||||
/* TODO: Read audio mode */
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-lane-list");
|
||||
if (nval > 0) {
|
||||
dpn[i].num_lanes = nval;
|
||||
dpn[i].lane_list = devm_kcalloc(&slave->dev,
|
||||
dpn[i].num_lanes, sizeof(*dpn[i].lane_list),
|
||||
GFP_KERNEL);
|
||||
if (!dpn[i].lane_list)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-lane-list",
|
||||
dpn[i].lane_list, dpn[i].num_lanes);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fwnode_handle_put(node);
|
||||
|
||||
|
@ -304,42 +376,46 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
|
|||
struct device *dev = &slave->dev;
|
||||
struct fwnode_handle *port;
|
||||
int nval;
|
||||
int ret;
|
||||
|
||||
device_property_read_u32(dev, "mipi-sdw-sw-interface-revision",
|
||||
&prop->mipi_revision);
|
||||
|
||||
prop->wake_capable = device_property_read_bool(dev,
|
||||
prop->wake_capable = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-wake-up-unavailable");
|
||||
prop->wake_capable = !prop->wake_capable;
|
||||
|
||||
prop->test_mode_capable = device_property_read_bool(dev,
|
||||
prop->test_mode_capable = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-test-mode-supported");
|
||||
|
||||
prop->clk_stop_mode1 = false;
|
||||
if (device_property_read_bool(dev,
|
||||
if (mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-clock-stop-mode1-supported"))
|
||||
prop->clk_stop_mode1 = true;
|
||||
|
||||
prop->simple_clk_stop_capable = device_property_read_bool(dev,
|
||||
prop->simple_clk_stop_capable = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-simplified-clockstopprepare-sm-supported");
|
||||
|
||||
device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout",
|
||||
&prop->clk_stop_timeout);
|
||||
|
||||
device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout",
|
||||
&prop->ch_prep_timeout);
|
||||
ret = device_property_read_u32(dev, "mipi-sdw-peripheral-channelprepare-timeout",
|
||||
&prop->ch_prep_timeout);
|
||||
if (ret < 0)
|
||||
device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout",
|
||||
&prop->ch_prep_timeout);
|
||||
|
||||
device_property_read_u32(dev,
|
||||
"mipi-sdw-clockstopprepare-hard-reset-behavior",
|
||||
&prop->reset_behave);
|
||||
|
||||
prop->high_PHY_capable = device_property_read_bool(dev,
|
||||
prop->high_PHY_capable = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-highPHY-capable");
|
||||
|
||||
prop->paging_support = device_property_read_bool(dev,
|
||||
prop->paging_support = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-paging-support");
|
||||
|
||||
prop->bank_delay_support = device_property_read_bool(dev,
|
||||
prop->bank_delay_support = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-bank-delay-support");
|
||||
|
||||
device_property_read_u32(dev,
|
||||
|
@ -354,7 +430,17 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
|
|||
device_property_read_u32(dev, "mipi-sdw-sink-port-list",
|
||||
&prop->sink_ports);
|
||||
|
||||
/* Read dp0 properties */
|
||||
device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list",
|
||||
&prop->sdca_interrupt_register_list);
|
||||
|
||||
prop->commit_register_supported = mipi_device_property_read_bool(dev,
|
||||
"mipi-sdw-commit-register-supported");
|
||||
|
||||
/*
|
||||
* Read dp0 properties - we don't rely on the 'mipi-sdw-dp-0-supported'
|
||||
* property since the 'mipi-sdw-dp0-subproperties' property is logically
|
||||
* equivalent.
|
||||
*/
|
||||
port = device_get_named_child_node(dev, "mipi-sdw-dp-0-subproperties");
|
||||
if (!port) {
|
||||
dev_dbg(dev, "DP0 node not found!!\n");
|
||||
|
|
|
@ -1173,7 +1173,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
|
|||
else
|
||||
sconfig.direction = SDW_DATA_DIR_RX;
|
||||
|
||||
/* hw parameters wil be ignored as we only support PDM */
|
||||
/* hw parameters will be ignored as we only support PDM */
|
||||
sconfig.ch_count = 1;
|
||||
sconfig.frame_rate = params_rate(params);
|
||||
sconfig.type = stream->type;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/sdca.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
|
@ -70,6 +71,17 @@ int sdw_slave_add(struct sdw_bus *bus,
|
|||
list_add_tail(&slave->node, &bus->slaves);
|
||||
mutex_unlock(&bus->bus_lock);
|
||||
|
||||
/*
|
||||
* The Soundwire driver probe may optionally register SDCA
|
||||
* sub-devices, one per Function. This means the information
|
||||
* on the SDCA revision and the number/type of Functions need
|
||||
* to be extracted from platform firmware before the SoundWire
|
||||
* driver probe, and as a consequence before the SoundWire
|
||||
* device_register() below.
|
||||
*/
|
||||
sdca_lookup_interface_revision(slave);
|
||||
sdca_lookup_functions(slave);
|
||||
|
||||
ret = device_register(&slave->dev);
|
||||
if (ret) {
|
||||
dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
|
||||
|
@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SDCA);
|
||||
|
|
|
@ -224,7 +224,7 @@ int sdw_slave_sysfs_init(struct sdw_slave *slave)
|
|||
|
||||
/*
|
||||
* the status is shown in capital letters for UNATTACHED and RESERVED
|
||||
* on purpose, to highligh users to the fact that these status values
|
||||
* on purpose, to highlight users to the fact that these status values
|
||||
* are not expected.
|
||||
*/
|
||||
static const char *const slave_status[] = {
|
||||
|
|
|
@ -4,12 +4,21 @@
|
|||
#ifndef __SOUNDWIRE_H
|
||||
#define __SOUNDWIRE_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/lockdep_types.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/lockdep_types.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <sound/sdca.h>
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct dentry;
|
||||
struct fwnode_handle;
|
||||
|
||||
struct sdw_bus;
|
||||
struct sdw_slave;
|
||||
|
@ -226,64 +235,36 @@ enum sdw_clk_stop_mode {
|
|||
|
||||
/**
|
||||
* struct sdw_dp0_prop - DP0 properties
|
||||
* @words: wordlengths supported
|
||||
* @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64
|
||||
* (inclusive)
|
||||
* @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64
|
||||
* (inclusive)
|
||||
* @num_words: number of wordlengths supported
|
||||
* @words: wordlengths supported
|
||||
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
||||
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady
|
||||
* response
|
||||
* @simple_ch_prep_sm: If channel prepare sequence is required
|
||||
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
||||
* @imp_def_interrupts: If set, each bit corresponds to support for
|
||||
* implementation-defined interrupts
|
||||
* @num_lanes: array size of @lane_list
|
||||
* @lane_list: indicates which Lanes can be used by DP0
|
||||
*
|
||||
* The wordlengths are specified by Spec as max, min AND number of
|
||||
* discrete values, implementation can define based on the wordlengths they
|
||||
* support
|
||||
*/
|
||||
struct sdw_dp0_prop {
|
||||
u32 *words;
|
||||
u32 max_word;
|
||||
u32 min_word;
|
||||
u32 num_words;
|
||||
u32 *words;
|
||||
u32 ch_prep_timeout;
|
||||
bool BRA_flow_controlled;
|
||||
bool simple_ch_prep_sm;
|
||||
u32 ch_prep_timeout;
|
||||
bool imp_def_interrupts;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdw_dpn_audio_mode - Audio mode properties for DPn
|
||||
* @bus_min_freq: Minimum bus frequency, in Hz
|
||||
* @bus_max_freq: Maximum bus frequency, in Hz
|
||||
* @bus_num_freq: Number of discrete frequencies supported
|
||||
* @bus_freq: Discrete bus frequencies, in Hz
|
||||
* @min_freq: Minimum sampling frequency, in Hz
|
||||
* @max_freq: Maximum sampling bus frequency, in Hz
|
||||
* @num_freq: Number of discrete sampling frequency supported
|
||||
* @freq: Discrete sampling frequencies, in Hz
|
||||
* @prep_ch_behave: Specifies the dependencies between Channel Prepare
|
||||
* sequence and bus clock configuration
|
||||
* If 0, Channel Prepare can happen at any Bus clock rate
|
||||
* If 1, Channel Prepare sequence shall happen only after Bus clock is
|
||||
* changed to a frequency supported by this mode or compatible modes
|
||||
* described by the next field
|
||||
* @glitchless: Bitmap describing possible glitchless transitions from this
|
||||
* Audio Mode to other Audio Modes
|
||||
*/
|
||||
struct sdw_dpn_audio_mode {
|
||||
u32 bus_min_freq;
|
||||
u32 bus_max_freq;
|
||||
u32 bus_num_freq;
|
||||
u32 *bus_freq;
|
||||
u32 max_freq;
|
||||
u32 min_freq;
|
||||
u32 num_freq;
|
||||
u32 *freq;
|
||||
u32 prep_ch_behave;
|
||||
u32 glitchless;
|
||||
int num_lanes;
|
||||
u32 *lane_list;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -298,24 +279,25 @@ struct sdw_dpn_audio_mode {
|
|||
* @type: Data port type. Full, Simplified or Reduced
|
||||
* @max_grouping: Maximum number of samples that can be grouped together for
|
||||
* a full data port
|
||||
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
|
||||
* machine
|
||||
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
||||
* @imp_def_interrupts: If set, each bit corresponds to support for
|
||||
* implementation-defined interrupts
|
||||
* @max_ch: Maximum channels supported
|
||||
* @min_ch: Minimum channels supported
|
||||
* @num_channels: Number of discrete channels supported
|
||||
* @channels: Discrete channels supported
|
||||
* @num_ch_combinations: Number of channel combinations supported
|
||||
* @channels: Discrete channels supported
|
||||
* @ch_combinations: Channel combinations supported
|
||||
* @lane_list: indicates which Lanes can be used by DPn
|
||||
* @num_lanes: array size of @lane_list
|
||||
* @modes: SDW mode supported
|
||||
* @max_async_buffer: Number of samples that this port can buffer in
|
||||
* asynchronous modes
|
||||
* @port_encoding: Payload Channel Sample encoding schemes supported
|
||||
* @block_pack_mode: Type of block port mode supported
|
||||
* @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register
|
||||
* @port_encoding: Payload Channel Sample encoding schemes supported
|
||||
* @audio_modes: Audio modes supported
|
||||
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
|
||||
* machine
|
||||
*/
|
||||
struct sdw_dpn_prop {
|
||||
u32 num;
|
||||
|
@ -325,25 +307,29 @@ struct sdw_dpn_prop {
|
|||
u32 *words;
|
||||
enum sdw_dpn_type type;
|
||||
u32 max_grouping;
|
||||
bool simple_ch_prep_sm;
|
||||
u32 ch_prep_timeout;
|
||||
u32 imp_def_interrupts;
|
||||
u32 max_ch;
|
||||
u32 min_ch;
|
||||
u32 num_channels;
|
||||
u32 *channels;
|
||||
u32 num_ch_combinations;
|
||||
u32 *channels;
|
||||
u32 *ch_combinations;
|
||||
u32 *lane_list;
|
||||
int num_lanes;
|
||||
u32 modes;
|
||||
u32 max_async_buffer;
|
||||
u32 port_encoding;
|
||||
bool block_pack_mode;
|
||||
bool read_only_wordlength;
|
||||
u32 port_encoding;
|
||||
struct sdw_dpn_audio_mode *audio_modes;
|
||||
bool simple_ch_prep_sm;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdw_slave_prop - SoundWire Slave properties
|
||||
* @dp0_prop: Data Port 0 properties
|
||||
* @src_dpn_prop: Source Data Port N properties
|
||||
* @sink_dpn_prop: Sink Data Port N properties
|
||||
* @mipi_revision: Spec version of the implementation
|
||||
* @wake_capable: Wake-up events are supported
|
||||
* @test_mode_capable: If test mode is supported
|
||||
|
@ -360,23 +346,26 @@ struct sdw_dpn_prop {
|
|||
* SCP_AddrPage2
|
||||
* @bank_delay_support: Slave implements bank delay/bridge support registers
|
||||
* SCP_BankDelay and SCP_NextFrame
|
||||
* @lane_control_support: Slave supports lane control
|
||||
* @p15_behave: Slave behavior when the Master attempts a read to the Port15
|
||||
* alias
|
||||
* @lane_control_support: Slave supports lane control
|
||||
* @master_count: Number of Masters present on this Slave
|
||||
* @source_ports: Bitmap identifying source ports
|
||||
* @sink_ports: Bitmap identifying sink ports
|
||||
* @dp0_prop: Data Port 0 properties
|
||||
* @src_dpn_prop: Source Data Port N properties
|
||||
* @sink_dpn_prop: Sink Data Port N properties
|
||||
* @scp_int1_mask: SCP_INT1_MASK desired settings
|
||||
* @quirks: bitmask identifying deltas from the MIPI specification
|
||||
* @sdca_interrupt_register_list: indicates which sets of SDCA interrupt status
|
||||
* and masks are supported
|
||||
* @commit_register_supported: is PCP_Commit register supported
|
||||
* @scp_int1_mask: SCP_INT1_MASK desired settings
|
||||
* @clock_reg_supported: the Peripheral implements the clock base and scale
|
||||
* registers introduced with the SoundWire 1.2 specification. SDCA devices
|
||||
* do not need to set this boolean property as the registers are required.
|
||||
* @use_domain_irq: call actual IRQ handler on slave, as well as callback
|
||||
*/
|
||||
struct sdw_slave_prop {
|
||||
struct sdw_dp0_prop *dp0_prop;
|
||||
struct sdw_dpn_prop *src_dpn_prop;
|
||||
struct sdw_dpn_prop *sink_dpn_prop;
|
||||
u32 mipi_revision;
|
||||
bool wake_capable;
|
||||
bool test_mode_capable;
|
||||
|
@ -388,16 +377,15 @@ struct sdw_slave_prop {
|
|||
bool high_PHY_capable;
|
||||
bool paging_support;
|
||||
bool bank_delay_support;
|
||||
enum sdw_p15_behave p15_behave;
|
||||
bool lane_control_support;
|
||||
enum sdw_p15_behave p15_behave;
|
||||
u32 master_count;
|
||||
u32 source_ports;
|
||||
u32 sink_ports;
|
||||
struct sdw_dp0_prop *dp0_prop;
|
||||
struct sdw_dpn_prop *src_dpn_prop;
|
||||
struct sdw_dpn_prop *sink_dpn_prop;
|
||||
u8 scp_int1_mask;
|
||||
u32 quirks;
|
||||
u32 sdca_interrupt_register_list;
|
||||
u8 commit_register_supported;
|
||||
u8 scp_int1_mask;
|
||||
bool clock_reg_supported;
|
||||
bool use_domain_irq;
|
||||
};
|
||||
|
@ -406,13 +394,14 @@ struct sdw_slave_prop {
|
|||
|
||||
/**
|
||||
* struct sdw_master_prop - Master properties
|
||||
* @clk_gears: Clock gears supported
|
||||
* @clk_freq: Clock frequencies supported, in Hz
|
||||
* @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
|
||||
* @revision: MIPI spec version of the implementation
|
||||
* @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
|
||||
* @max_clk_freq: Maximum Bus clock frequency, in Hz
|
||||
* @num_clk_gears: Number of clock gears supported
|
||||
* @clk_gears: Clock gears supported
|
||||
* @num_clk_freq: Number of clock frequencies supported, in Hz
|
||||
* @clk_freq: Clock frequencies supported, in Hz
|
||||
* @default_frame_rate: Controller default Frame rate, in Hz
|
||||
* @default_row: Number of rows
|
||||
* @default_col: Number of columns
|
||||
|
@ -421,24 +410,23 @@ struct sdw_slave_prop {
|
|||
* command
|
||||
* @mclk_freq: clock reference passed to SoundWire Master, in Hz.
|
||||
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux
|
||||
* @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
|
||||
*/
|
||||
struct sdw_master_prop {
|
||||
u32 *clk_gears;
|
||||
u32 *clk_freq;
|
||||
u64 quirks;
|
||||
u32 revision;
|
||||
u32 clk_stop_modes;
|
||||
u32 max_clk_freq;
|
||||
u32 num_clk_gears;
|
||||
u32 *clk_gears;
|
||||
u32 num_clk_freq;
|
||||
u32 *clk_freq;
|
||||
u32 default_frame_rate;
|
||||
u32 default_row;
|
||||
u32 default_col;
|
||||
bool dynamic_frame;
|
||||
u32 err_threshold;
|
||||
u32 mclk_freq;
|
||||
bool dynamic_frame;
|
||||
bool hw_disabled;
|
||||
u64 quirks;
|
||||
};
|
||||
|
||||
/* Definitions for Master quirks */
|
||||
|
@ -488,9 +476,9 @@ struct sdw_slave_id {
|
|||
__u8 sdw_version:4;
|
||||
};
|
||||
|
||||
struct sdw_extended_slave_id {
|
||||
int link_id;
|
||||
struct sdw_slave_id id;
|
||||
struct sdw_peripherals {
|
||||
int num_peripherals;
|
||||
struct sdw_slave *array[];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -630,7 +618,6 @@ struct sdw_slave_ops {
|
|||
int (*clk_stop)(struct sdw_slave *slave,
|
||||
enum sdw_clk_stop_mode mode,
|
||||
enum sdw_clk_stop_type type);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -663,6 +650,7 @@ struct sdw_slave_ops {
|
|||
* @is_mockup_device: status flag used to squelch errors in the command/control
|
||||
* protocol for SoundWire mockup devices
|
||||
* @sdw_dev_lock: mutex used to protect callbacks/remove races
|
||||
* @sdca_data: structure containing all device data for SDCA helpers
|
||||
*/
|
||||
struct sdw_slave {
|
||||
struct sdw_slave_id id;
|
||||
|
@ -686,6 +674,7 @@ struct sdw_slave {
|
|||
bool first_interrupt_done;
|
||||
bool is_mockup_device;
|
||||
struct mutex sdw_dev_lock; /* protect callbacks/remove races */
|
||||
struct sdca_device_data sdca_data;
|
||||
};
|
||||
|
||||
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
|
||||
|
@ -704,8 +693,7 @@ struct sdw_master_device {
|
|||
container_of(d, struct sdw_master_device, dev)
|
||||
|
||||
struct sdw_driver {
|
||||
int (*probe)(struct sdw_slave *sdw,
|
||||
const struct sdw_device_id *id);
|
||||
int (*probe)(struct sdw_slave *sdw, const struct sdw_device_id *id);
|
||||
int (*remove)(struct sdw_slave *sdw);
|
||||
void (*shutdown)(struct sdw_slave *sdw);
|
||||
|
||||
|
@ -724,7 +712,7 @@ struct sdw_driver {
|
|||
SDW_SLAVE_ENTRY_EXT((_mfg_id), (_part_id), 0, 0, (_drv_data))
|
||||
|
||||
int sdw_handle_slave_status(struct sdw_bus *bus,
|
||||
enum sdw_slave_status status[]);
|
||||
enum sdw_slave_status status[]);
|
||||
|
||||
/*
|
||||
* SDW master structures and APIs
|
||||
|
@ -806,29 +794,28 @@ struct sdw_enable_ch {
|
|||
*/
|
||||
struct sdw_master_port_ops {
|
||||
int (*dpn_set_port_params)(struct sdw_bus *bus,
|
||||
struct sdw_port_params *port_params,
|
||||
unsigned int bank);
|
||||
struct sdw_port_params *port_params,
|
||||
unsigned int bank);
|
||||
int (*dpn_set_port_transport_params)(struct sdw_bus *bus,
|
||||
struct sdw_transport_params *transport_params,
|
||||
enum sdw_reg_bank bank);
|
||||
int (*dpn_port_prep)(struct sdw_bus *bus,
|
||||
struct sdw_prepare_ch *prepare_ch);
|
||||
struct sdw_transport_params *transport_params,
|
||||
enum sdw_reg_bank bank);
|
||||
int (*dpn_port_prep)(struct sdw_bus *bus, struct sdw_prepare_ch *prepare_ch);
|
||||
int (*dpn_port_enable_ch)(struct sdw_bus *bus,
|
||||
struct sdw_enable_ch *enable_ch, unsigned int bank);
|
||||
struct sdw_enable_ch *enable_ch, unsigned int bank);
|
||||
};
|
||||
|
||||
struct sdw_msg;
|
||||
|
||||
/**
|
||||
* struct sdw_defer - SDW deffered message
|
||||
* @length: message length
|
||||
* struct sdw_defer - SDW deferred message
|
||||
* @complete: message completion
|
||||
* @msg: SDW message
|
||||
* @length: message length
|
||||
*/
|
||||
struct sdw_defer {
|
||||
struct sdw_msg *msg;
|
||||
int length;
|
||||
struct completion complete;
|
||||
struct sdw_msg *msg;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -849,14 +836,11 @@ struct sdw_defer {
|
|||
*/
|
||||
struct sdw_master_ops {
|
||||
int (*read_prop)(struct sdw_bus *bus);
|
||||
u64 (*override_adr)
|
||||
(struct sdw_bus *bus, u64 addr);
|
||||
enum sdw_command_response (*xfer_msg)
|
||||
(struct sdw_bus *bus, struct sdw_msg *msg);
|
||||
enum sdw_command_response (*xfer_msg_defer)
|
||||
(struct sdw_bus *bus);
|
||||
u64 (*override_adr)(struct sdw_bus *bus, u64 addr);
|
||||
enum sdw_command_response (*xfer_msg)(struct sdw_bus *bus, struct sdw_msg *msg);
|
||||
enum sdw_command_response (*xfer_msg_defer)(struct sdw_bus *bus);
|
||||
int (*set_bus_conf)(struct sdw_bus *bus,
|
||||
struct sdw_bus_params *params);
|
||||
struct sdw_bus_params *params);
|
||||
int (*pre_bank_switch)(struct sdw_bus *bus);
|
||||
int (*post_bank_switch)(struct sdw_bus *bus);
|
||||
u32 (*read_ping_status)(struct sdw_bus *bus);
|
||||
|
@ -871,68 +855,71 @@ struct sdw_master_ops {
|
|||
* struct sdw_bus - SoundWire bus
|
||||
* @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
|
||||
* @md: Master device
|
||||
* @controller_id: system-unique controller ID. If set to -1, the bus @id will be used.
|
||||
* @link_id: Link id number, can be 0 to N, unique for each Controller
|
||||
* @id: bus system-wide unique id
|
||||
* @slaves: list of Slaves on this bus
|
||||
* @assigned: Bitmap for Slave device numbers.
|
||||
* Bit set implies used number, bit clear implies unused number.
|
||||
* @bus_lock_key: bus lock key associated to @bus_lock
|
||||
* @bus_lock: bus lock
|
||||
* @slaves: list of Slaves on this bus
|
||||
* @msg_lock_key: message lock key associated to @msg_lock
|
||||
* @msg_lock: message lock
|
||||
* @compute_params: points to Bus resource management implementation
|
||||
* @ops: Master callback ops
|
||||
* @port_ops: Master port callback ops
|
||||
* @params: Current bus parameters
|
||||
* @prop: Master properties
|
||||
* @vendor_specific_prop: pointer to non-standard properties
|
||||
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This
|
||||
* is used to compute and program bus bandwidth, clock, frame shape,
|
||||
* transport and port parameters
|
||||
* @debugfs: Bus debugfs
|
||||
* @domain: IRQ domain
|
||||
* @defer_msg: Defer message
|
||||
* @clk_stop_timeout: Clock stop timeout computed
|
||||
* @bank_switch_timeout: Bank switch timeout computed
|
||||
* @multi_link: Store bus property that indicates if multi links
|
||||
* are supported. This flag is populated by drivers after reading
|
||||
* appropriate firmware (ACPI/DT).
|
||||
* @params: Current bus parameters
|
||||
* @stream_refcount: number of streams currently using this bus
|
||||
* @ops: Master callback ops
|
||||
* @port_ops: Master port callback ops
|
||||
* @prop: Master properties
|
||||
* @vendor_specific_prop: pointer to non-standard properties
|
||||
* @hw_sync_min_links: Number of links used by a stream above which
|
||||
* hardware-based synchronization is required. This value is only
|
||||
* meaningful if multi_link is set. If set to 1, hardware-based
|
||||
* synchronization will be used even if a stream only uses a single
|
||||
* SoundWire segment.
|
||||
* @stream_refcount: number of streams currently using this bus
|
||||
* @controller_id: system-unique controller ID. If set to -1, the bus @id will be used.
|
||||
* @link_id: Link id number, can be 0 to N, unique for each Controller
|
||||
* @id: bus system-wide unique id
|
||||
* @compute_params: points to Bus resource management implementation
|
||||
* @assigned: Bitmap for Slave device numbers.
|
||||
* Bit set implies used number, bit clear implies unused number.
|
||||
* @clk_stop_timeout: Clock stop timeout computed
|
||||
* @bank_switch_timeout: Bank switch timeout computed
|
||||
* @domain: IRQ domain
|
||||
* @irq_chip: IRQ chip
|
||||
* @debugfs: Bus debugfs (optional)
|
||||
* @multi_link: Store bus property that indicates if multi links
|
||||
* are supported. This flag is populated by drivers after reading
|
||||
* appropriate firmware (ACPI/DT).
|
||||
*/
|
||||
struct sdw_bus {
|
||||
struct device *dev;
|
||||
struct sdw_master_device *md;
|
||||
struct lock_class_key bus_lock_key;
|
||||
struct mutex bus_lock;
|
||||
struct list_head slaves;
|
||||
struct lock_class_key msg_lock_key;
|
||||
struct mutex msg_lock;
|
||||
struct list_head m_rt_list;
|
||||
struct sdw_defer defer_msg;
|
||||
struct sdw_bus_params params;
|
||||
int stream_refcount;
|
||||
const struct sdw_master_ops *ops;
|
||||
const struct sdw_master_port_ops *port_ops;
|
||||
struct sdw_master_prop prop;
|
||||
void *vendor_specific_prop;
|
||||
int hw_sync_min_links;
|
||||
int controller_id;
|
||||
unsigned int link_id;
|
||||
int id;
|
||||
struct list_head slaves;
|
||||
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
|
||||
struct mutex bus_lock;
|
||||
struct lock_class_key bus_lock_key;
|
||||
struct mutex msg_lock;
|
||||
struct lock_class_key msg_lock_key;
|
||||
int (*compute_params)(struct sdw_bus *bus);
|
||||
const struct sdw_master_ops *ops;
|
||||
const struct sdw_master_port_ops *port_ops;
|
||||
struct sdw_bus_params params;
|
||||
struct sdw_master_prop prop;
|
||||
void *vendor_specific_prop;
|
||||
struct list_head m_rt_list;
|
||||
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
|
||||
unsigned int clk_stop_timeout;
|
||||
u32 bank_switch_timeout;
|
||||
struct irq_chip irq_chip;
|
||||
struct irq_domain *domain;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
#endif
|
||||
struct irq_chip irq_chip;
|
||||
struct irq_domain *domain;
|
||||
struct sdw_defer defer_msg;
|
||||
unsigned int clk_stop_timeout;
|
||||
u32 bank_switch_timeout;
|
||||
bool multi_link;
|
||||
int hw_sync_min_links;
|
||||
int stream_refcount;
|
||||
};
|
||||
|
||||
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
||||
|
@ -1010,18 +997,18 @@ struct sdw_stream_params {
|
|||
* @params: Stream parameters
|
||||
* @state: Current state of the stream
|
||||
* @type: Stream type PCM or PDM
|
||||
* @m_rt_count: Count of Master runtime(s) in this stream
|
||||
* @master_list: List of Master runtime(s) in this stream.
|
||||
* master_list can contain only one m_rt per Master instance
|
||||
* for a stream
|
||||
* @m_rt_count: Count of Master runtime(s) in this stream
|
||||
*/
|
||||
struct sdw_stream_runtime {
|
||||
const char *name;
|
||||
struct sdw_stream_params params;
|
||||
enum sdw_stream_state state;
|
||||
enum sdw_stream_type type;
|
||||
struct list_head master_list;
|
||||
int m_rt_count;
|
||||
struct list_head master_list;
|
||||
};
|
||||
|
||||
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
|
||||
|
@ -1030,12 +1017,12 @@ void sdw_release_stream(struct sdw_stream_runtime *stream);
|
|||
int sdw_compute_params(struct sdw_bus *bus);
|
||||
|
||||
int sdw_stream_add_master(struct sdw_bus *bus,
|
||||
struct sdw_stream_config *stream_config,
|
||||
const struct sdw_port_config *port_config,
|
||||
unsigned int num_ports,
|
||||
struct sdw_stream_runtime *stream);
|
||||
struct sdw_stream_config *stream_config,
|
||||
const struct sdw_port_config *port_config,
|
||||
unsigned int num_ports,
|
||||
struct sdw_stream_runtime *stream);
|
||||
int sdw_stream_remove_master(struct sdw_bus *bus,
|
||||
struct sdw_stream_runtime *stream);
|
||||
struct sdw_stream_runtime *stream);
|
||||
int sdw_startup_stream(void *sdw_substream);
|
||||
int sdw_prepare_stream(struct sdw_stream_runtime *stream);
|
||||
int sdw_enable_stream(struct sdw_stream_runtime *stream);
|
||||
|
|
|
@ -27,9 +27,11 @@
|
|||
#define ACP_SDW0 0
|
||||
#define ACP_SDW1 1
|
||||
#define AMD_SDW_MAX_MANAGER_COUNT 2
|
||||
#define ACP63_PCI_REV_ID 0x63
|
||||
|
||||
struct acp_sdw_pdata {
|
||||
u16 instance;
|
||||
u32 acp_rev;
|
||||
/* mutex to protect acp common register access */
|
||||
struct mutex *acp_sdw_lock;
|
||||
};
|
||||
|
@ -66,6 +68,7 @@ struct sdw_amd_dai_runtime {
|
|||
* @instance: SoundWire manager instance
|
||||
* @quirks: SoundWire manager quirks
|
||||
* @wake_en_mask: wake enable mask per SoundWire manager
|
||||
* @acp_rev: acp pci device revision id
|
||||
* @clk_stopped: flag set to true when clock is stopped
|
||||
* @power_mode_mask: flag interprets amd SoundWire manager power mode
|
||||
* @dai_runtime_array: dai runtime array
|
||||
|
@ -94,6 +97,7 @@ struct amd_sdw_manager {
|
|||
u32 quirks;
|
||||
u32 wake_en_mask;
|
||||
u32 power_mode_mask;
|
||||
u32 acp_rev;
|
||||
bool clk_stopped;
|
||||
|
||||
struct sdw_amd_dai_runtime **dai_runtime_array;
|
||||
|
@ -115,25 +119,23 @@ struct sdw_amd_acpi_info {
|
|||
* struct sdw_amd_ctx - context allocated by the controller driver probe
|
||||
*
|
||||
* @count: link count
|
||||
* @num_slaves: total number of devices exposed across all enabled links
|
||||
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||
* Controller
|
||||
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||
* links
|
||||
* @pdev: platform device structure
|
||||
* @peripherals: array representing Peripherals exposed across all enabled links
|
||||
*/
|
||||
struct sdw_amd_ctx {
|
||||
int count;
|
||||
int num_slaves;
|
||||
u32 link_mask;
|
||||
struct sdw_extended_slave_id *ids;
|
||||
struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
|
||||
struct sdw_peripherals *peripherals;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdw_amd_res - Soundwire AMD global resource structure,
|
||||
* typically populated by the DSP driver/Legacy driver
|
||||
*
|
||||
* @acp_rev: acp pci device revision id
|
||||
* @addr: acp pci device resource start address
|
||||
* @reg_range: ACP register range
|
||||
* @link_mask: bit-wise mask listing links selected by the DSP driver/
|
||||
|
@ -146,6 +148,7 @@ struct sdw_amd_ctx {
|
|||
* @acp_lock: mutex protecting acp common registers access
|
||||
*/
|
||||
struct sdw_amd_res {
|
||||
u32 acp_rev;
|
||||
u32 addr;
|
||||
u32 reg_range;
|
||||
u32 link_mask;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#ifndef __SDW_INTEL_H
|
||||
#define __SDW_INTEL_H
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
||||
|
@ -286,31 +287,28 @@ struct hdac_bus;
|
|||
* hardware capabilities after all power dependencies are settled.
|
||||
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||
* Controller
|
||||
* @num_slaves: total number of devices exposed across all enabled links
|
||||
* @handle: ACPI parent handle
|
||||
* @ldev: information for each link (controller-specific and kept
|
||||
* opaque here)
|
||||
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||
* links
|
||||
* @link_list: list to handle interrupts across all links
|
||||
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
|
||||
* @shim_mask: flags to track initialization of SHIM shared registers
|
||||
* @shim_base: sdw shim base.
|
||||
* @alh_base: sdw alh base.
|
||||
* @peripherals: array representing Peripherals exposed across all enabled links
|
||||
*/
|
||||
struct sdw_intel_ctx {
|
||||
int count;
|
||||
void __iomem *mmio_base;
|
||||
u32 link_mask;
|
||||
int num_slaves;
|
||||
acpi_handle handle;
|
||||
struct sdw_intel_link_dev **ldev;
|
||||
struct sdw_extended_slave_id *ids;
|
||||
struct list_head link_list;
|
||||
struct mutex shim_lock; /* lock for access to shared SHIM registers */
|
||||
u32 shim_mask;
|
||||
u32 shim_base;
|
||||
u32 alh_base;
|
||||
struct sdw_peripherals *peripherals;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Analog Devices ADAU1373 Audio Codec drive
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_ADAU1373_H__
|
||||
#define __SOUND_ADAU1373_H__
|
||||
|
||||
enum adau1373_micbias_voltage {
|
||||
ADAU1373_MICBIAS_2_9V = 0,
|
||||
ADAU1373_MICBIAS_2_2V = 1,
|
||||
ADAU1373_MICBIAS_2_6V = 2,
|
||||
ADAU1373_MICBIAS_1_8V = 3,
|
||||
};
|
||||
|
||||
#define ADAU1373_DRC_SIZE 13
|
||||
|
||||
struct adau1373_platform_data {
|
||||
bool input_differential[4];
|
||||
bool lineout_differential;
|
||||
bool lineout_ground_sense;
|
||||
|
||||
unsigned int num_drc;
|
||||
uint8_t drc_setting[3][ADAU1373_DRC_SIZE];
|
||||
|
||||
enum adau1373_micbias_voltage micbias1;
|
||||
enum adau1373_micbias_voltage micbias2;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,6 +19,30 @@
|
|||
|
||||
struct snd_compr_ops;
|
||||
|
||||
/**
|
||||
* struct snd_compr_task_runtime: task runtime description
|
||||
* @list: list of all managed tasks
|
||||
* @input: input DMA buffer
|
||||
* @output: output DMA buffer
|
||||
* @seqno: sequence number
|
||||
* @input_size: really used data in the input buffer
|
||||
* @output_size: really used data in the output buffer
|
||||
* @flags: see SND_COMPRESS_TFLG_*
|
||||
* @state: actual task state
|
||||
* @private_value: used by the lowlevel driver (opaque)
|
||||
*/
|
||||
struct snd_compr_task_runtime {
|
||||
struct list_head list;
|
||||
struct dma_buf *input;
|
||||
struct dma_buf *output;
|
||||
u64 seqno;
|
||||
u64 input_size;
|
||||
u64 output_size;
|
||||
u32 flags;
|
||||
u8 state;
|
||||
void *private_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct snd_compr_runtime: runtime stream description
|
||||
* @state: stream state
|
||||
|
@ -37,6 +61,10 @@ struct snd_compr_ops;
|
|||
* @dma_addr: physical buffer address (not accessible from main CPU)
|
||||
* @dma_bytes: size of DMA area
|
||||
* @dma_buffer_p: runtime dma buffer pointer
|
||||
* @active_tasks: count of active tasks
|
||||
* @total_tasks: count of all tasks
|
||||
* @task_seqno: last task sequence number (!= 0)
|
||||
* @tasks: list of all tasks
|
||||
*/
|
||||
struct snd_compr_runtime {
|
||||
snd_pcm_state_t state;
|
||||
|
@ -54,6 +82,13 @@ struct snd_compr_runtime {
|
|||
dma_addr_t dma_addr;
|
||||
size_t dma_bytes;
|
||||
struct snd_dma_buffer *dma_buffer_p;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
u32 active_tasks;
|
||||
u32 total_tasks;
|
||||
u64 task_seqno;
|
||||
struct list_head tasks;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -108,6 +143,10 @@ struct snd_compr_stream {
|
|||
* Not valid if copy is implemented
|
||||
* @get_caps: Retrieve DSP capabilities, mandatory
|
||||
* @get_codec_caps: Retrieve capabilities for a specific codec, mandatory
|
||||
* @task_create: Create a set of input/output buffers for accel operations
|
||||
* @task_start: Start (queue) a task for accel operations
|
||||
* @task_stop: Stop (dequeue) a task for accel operations
|
||||
* @task_free: Free a set of input/output buffers for accel operations
|
||||
*/
|
||||
struct snd_compr_ops {
|
||||
int (*open)(struct snd_compr_stream *stream);
|
||||
|
@ -132,6 +171,12 @@ struct snd_compr_ops {
|
|||
struct snd_compr_caps *caps);
|
||||
int (*get_codec_caps) (struct snd_compr_stream *stream,
|
||||
struct snd_compr_codec_caps *codec);
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
int (*task_create) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task);
|
||||
int (*task_start) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task);
|
||||
int (*task_stop) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task);
|
||||
int (*task_free) (struct snd_compr_stream *stream, struct snd_compr_task_runtime *task);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -242,4 +287,9 @@ int snd_compr_free_pages(struct snd_compr_stream *stream);
|
|||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
void snd_compr_task_finished(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_runtime *task);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@ int hda_bus_ml_init(struct hdac_bus *bus);
|
|||
void hda_bus_ml_free(struct hdac_bus *bus);
|
||||
|
||||
int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid);
|
||||
void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable);
|
||||
void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable);
|
||||
bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid);
|
||||
|
||||
|
@ -71,6 +72,9 @@ static inline void hda_bus_ml_free(struct hdac_bus *bus) { }
|
|||
static inline int
|
||||
hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid) { return 0; }
|
||||
|
||||
static inline void
|
||||
hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable) { }
|
||||
|
||||
static inline void
|
||||
hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable) { }
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
|||
#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
|
||||
|
||||
/* INTCTL and INTSTS */
|
||||
#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */
|
||||
#define AZX_INT_ALL_STREAM 0x3fffffff /* all stream interrupts */
|
||||
#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
|
||||
#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
|
||||
|
||||
|
|
|
@ -97,11 +97,11 @@ struct snd_pcm_ops {
|
|||
|
||||
#define SNDRV_PCM_TRIGGER_STOP 0
|
||||
#define SNDRV_PCM_TRIGGER_START 1
|
||||
#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 3
|
||||
#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4
|
||||
#define SNDRV_PCM_TRIGGER_SUSPEND 5
|
||||
#define SNDRV_PCM_TRIGGER_RESUME 6
|
||||
#define SNDRV_PCM_TRIGGER_DRAIN 7
|
||||
#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 2
|
||||
#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 3
|
||||
#define SNDRV_PCM_TRIGGER_SUSPEND 4
|
||||
#define SNDRV_PCM_TRIGGER_RESUME 5
|
||||
#define SNDRV_PCM_TRIGGER_DRAIN 6
|
||||
|
||||
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
|
||||
|
||||
|
@ -1393,30 +1393,6 @@ snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
|
|||
return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_pcm_mmap_data_open - increase the mmap counter
|
||||
* @area: VMA
|
||||
*
|
||||
* PCM mmap callback should handle this counter properly
|
||||
*/
|
||||
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
|
||||
{
|
||||
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
|
||||
atomic_inc(&substream->mmap_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_pcm_mmap_data_close - decrease the mmap counter
|
||||
* @area: VMA
|
||||
*
|
||||
* PCM mmap callback should handle this counter properly
|
||||
*/
|
||||
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
|
||||
{
|
||||
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
|
||||
atomic_dec(&substream->mmap_count);
|
||||
}
|
||||
|
||||
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area);
|
||||
/* mmap for io-memory area */
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*
|
||||
* Copyright(c) 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SDCA_H__
|
||||
#define __SDCA_H__
|
||||
|
||||
struct sdw_slave;
|
||||
|
||||
#define SDCA_MAX_FUNCTION_COUNT 8
|
||||
|
||||
/**
|
||||
* sdca_device_desc - short descriptor for an SDCA Function
|
||||
* @adr: ACPI address (used for SDCA register access)
|
||||
* @type: Function topology type
|
||||
* @name: human-readable string
|
||||
*/
|
||||
struct sdca_function_desc {
|
||||
u64 adr;
|
||||
u32 type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* sdca_device_data - structure containing all SDCA related information
|
||||
* @sdca_interface_revision: value read from _DSD property, mainly to check
|
||||
* for changes between silicon versions
|
||||
* @num_functions: total number of supported SDCA functions. Invalid/unsupported
|
||||
* functions will be skipped.
|
||||
* @sdca_func: array of function descriptors
|
||||
*/
|
||||
struct sdca_device_data {
|
||||
u32 interface_revision;
|
||||
int num_functions;
|
||||
struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT];
|
||||
};
|
||||
|
||||
enum sdca_quirk {
|
||||
SDCA_QUIRKS_RT712_VB,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
|
||||
|
||||
void sdca_lookup_functions(struct sdw_slave *slave);
|
||||
void sdca_lookup_interface_revision(struct sdw_slave *slave);
|
||||
bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk);
|
||||
|
||||
#else
|
||||
|
||||
static inline void sdca_lookup_functions(struct sdw_slave *slave) {}
|
||||
static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {}
|
||||
static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*
|
||||
* Copyright(c) 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SDCA_FUNCTION_H__
|
||||
#define __SDCA_FUNCTION_H__
|
||||
|
||||
/*
|
||||
* SDCA Function Types from SDCA specification v1.0a Section 5.1.2
|
||||
* all Function types not described are reserved
|
||||
* Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types
|
||||
* are NOT defined in SDCA 1.0a, but they were defined in earlier
|
||||
* drafts and are planned for 1.1.
|
||||
*/
|
||||
|
||||
enum sdca_function_type {
|
||||
SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */
|
||||
SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */
|
||||
SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */
|
||||
SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */
|
||||
SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */
|
||||
SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */
|
||||
SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */
|
||||
};
|
||||
|
||||
/* Human-readable names used for kernel logs and Function device registration/bind */
|
||||
#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp"
|
||||
#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic"
|
||||
#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic"
|
||||
#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ"
|
||||
#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
|
||||
#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
|
||||
|
||||
enum sdca_entity0_controls {
|
||||
SDCA_CONTROL_ENTITY_0_COMMIT_GROUP_MASK = 0x01,
|
||||
SDCA_CONTROL_ENTITY_0_INTSTAT_CLEAR = 0x02,
|
||||
SDCA_CONTROL_ENTITY_0_INT_ENABLE = 0x03,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY = 0x05,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_MANUFACTURER_ID = 0x06,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_ID = 0x07,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_VERSION = 0x08
|
||||
};
|
||||
|
||||
#endif
|
|
@ -89,6 +89,13 @@ struct simple_util_priv {
|
|||
#define simple_props_to_dai_codec(props, i) ((props)->codec_dai + i)
|
||||
#define simple_props_to_codec_conf(props, i) ((props)->codec_conf + i)
|
||||
|
||||
/* has the same effect as simple_priv_to_props(). Preferred over
|
||||
* simple_priv_to_props() when dealing with PCM runtime data as
|
||||
* the ID stored in rtd->id may not be a valid array index.
|
||||
*/
|
||||
#define runtime_simple_priv_to_props(priv, rtd) \
|
||||
((priv)->dai_props + ((rtd)->dai_link - (priv)->dai_link))
|
||||
|
||||
#define for_each_prop_dlc_cpus(props, i, cpu) \
|
||||
for ((i) = 0; \
|
||||
((i) < (props)->num.cpus) && \
|
||||
|
|
|
@ -187,6 +187,10 @@ struct snd_soc_acpi_link_adr {
|
|||
* ACPI ID alone is not sufficient, wrong or misleading
|
||||
* @quirk_data: data used to uniquely identify a machine, usually a list of
|
||||
* audio codecs whose presence if checked with ACPI
|
||||
* @machine_check: pointer to quirk function. The functionality is similar to
|
||||
* the use of @machine_quirk, except that the return value is a boolean: the intent
|
||||
* is to skip a machine if the additional hardware/firmware verification invalidates
|
||||
* the initial selection in the snd_soc_acpi_mach table.
|
||||
* @pdata: intended for platform data or machine specific-ops. This structure
|
||||
* is not constant since this field may be updated at run-time
|
||||
* @sof_tplg_filename: Sound Open Firmware topology file name, if enabled
|
||||
|
@ -205,6 +209,7 @@ struct snd_soc_acpi_mach {
|
|||
const char *board;
|
||||
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
|
||||
const void *quirk_data;
|
||||
bool (*machine_check)(void *arg);
|
||||
void *pdata;
|
||||
struct snd_soc_acpi_mach_params mach_params;
|
||||
const char *sof_tplg_filename;
|
||||
|
@ -235,7 +240,6 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev)
|
|||
|
||||
bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct sdw_extended_slave_id *ids,
|
||||
int num_slaves);
|
||||
struct sdw_peripherals *peripherals);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -216,8 +216,7 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
|||
struct snd_pcm_substream *substream, int rollback);
|
||||
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
|
||||
void snd_soc_dai_resume(struct snd_soc_dai *dai);
|
||||
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
||||
struct snd_soc_pcm_runtime *rtd, int num);
|
||||
int snd_soc_dai_compress_new(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd);
|
||||
bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream);
|
||||
void snd_soc_dai_action(struct snd_soc_dai *dai,
|
||||
int stream, int action);
|
||||
|
@ -275,7 +274,7 @@ struct snd_soc_dai_ops {
|
|||
int (*probe)(struct snd_soc_dai *dai);
|
||||
int (*remove)(struct snd_soc_dai *dai);
|
||||
/* compress dai */
|
||||
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
|
||||
int (*compress_new)(struct snd_soc_pcm_runtime *rtd);
|
||||
/* Optional Callback used at pcm creation*/
|
||||
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *dai);
|
||||
|
|
|
@ -476,11 +476,11 @@ struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev,
|
|||
struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
|
||||
const char *driver_name);
|
||||
|
||||
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
|
||||
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd);
|
||||
#ifdef CONFIG_SND_SOC_COMPRESS
|
||||
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
|
||||
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd);
|
||||
#else
|
||||
static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
|
||||
static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -531,8 +531,13 @@ int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params,
|
|||
int tdm_width, int tdm_slots, int slot_multiple);
|
||||
|
||||
/* set runtime hw params */
|
||||
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
||||
const struct snd_pcm_hardware *hw);
|
||||
static inline int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
|
||||
const struct snd_pcm_hardware *hw)
|
||||
{
|
||||
substream->runtime->hw = *hw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
|
||||
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
|
||||
|
@ -805,11 +810,6 @@ struct snd_soc_dai_link {
|
|||
/* This DAI link can route to other DAI links at runtime (Frontend)*/
|
||||
unsigned int dynamic:1;
|
||||
|
||||
/* REMOVE ME */
|
||||
/* DPCM capture and Playback support */
|
||||
unsigned int dpcm_capture:1;
|
||||
unsigned int dpcm_playback:1;
|
||||
|
||||
/* DPCM used FE & BE merged format */
|
||||
unsigned int dpcm_merged_format:1;
|
||||
/* DPCM used FE & BE merged channel */
|
||||
|
@ -1185,7 +1185,7 @@ struct snd_soc_pcm_runtime {
|
|||
struct dentry *debugfs_dpcm_root;
|
||||
#endif
|
||||
|
||||
unsigned int num; /* 0-based and monotonic increasing */
|
||||
unsigned int id; /* 0-based and monotonic increasing */
|
||||
struct list_head list; /* rtd list of the soc card */
|
||||
|
||||
/* function mark */
|
||||
|
@ -1428,10 +1428,6 @@ struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_a
|
|||
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
|
||||
struct snd_soc_dai_driver *dai_drv,
|
||||
bool legacy_dai_naming);
|
||||
struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev,
|
||||
struct snd_soc_component *component,
|
||||
struct snd_soc_dai_driver *dai_drv,
|
||||
bool legacy_dai_naming);
|
||||
void snd_soc_unregister_dai(struct snd_soc_dai *dai);
|
||||
|
||||
struct snd_soc_dai *snd_soc_find_dai(
|
||||
|
|
|
@ -152,14 +152,15 @@ void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_lin
|
|||
struct snd_soc_dai_link_component *cpus, int cpus_num,
|
||||
struct snd_soc_dai_link_component *platform_component,
|
||||
int num_platforms, struct snd_soc_dai_link_component *codecs,
|
||||
int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd),
|
||||
int codecs_num, int no_pcm,
|
||||
int (*init)(struct snd_soc_pcm_runtime *rtd),
|
||||
const struct snd_soc_ops *ops);
|
||||
|
||||
int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
|
||||
int *be_id, char *name, int playback, int capture,
|
||||
const char *cpu_dai_name, const char *platform_comp_name,
|
||||
int num_platforms, const char *codec_name,
|
||||
const char *codec_dai_name,
|
||||
const char *codec_dai_name, int no_pcm,
|
||||
int (*init)(struct snd_soc_pcm_runtime *rtd),
|
||||
const struct snd_soc_ops *ops);
|
||||
|
||||
|
@ -236,8 +237,7 @@ int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s
|
|||
int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt_mf_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
|
|
|
@ -60,6 +60,7 @@ enum sof_ext_man_elem_type {
|
|||
SOF_EXT_MAN_ELEM_FW_VERSION = 0,
|
||||
SOF_EXT_MAN_ELEM_WINDOW = 1,
|
||||
SOF_EXT_MAN_ELEM_CC_VERSION = 2,
|
||||
SOF_EXT_MAN_ELEM_PROBE_INFO = 3,
|
||||
SOF_EXT_MAN_ELEM_DBG_ABI = 4,
|
||||
SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */
|
||||
SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA = 6,
|
||||
|
|
|
@ -156,6 +156,7 @@ struct tasdevice_priv {
|
|||
struct tasdevice_rca rcabin;
|
||||
struct calidata cali_data;
|
||||
struct tasdevice_fw *fmw;
|
||||
struct gpio_desc *speaker_id;
|
||||
struct gpio_desc *reset;
|
||||
struct mutex codec_lock;
|
||||
struct regmap *regmap;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <sound/compress_params.h>
|
||||
|
||||
|
||||
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 2, 0)
|
||||
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 0)
|
||||
/**
|
||||
* struct snd_compressed_buffer - compressed buffer
|
||||
* @fragment_size: size of buffer fragment in bytes
|
||||
|
@ -68,7 +68,8 @@ struct snd_compr_avail {
|
|||
|
||||
enum snd_compr_direction {
|
||||
SND_COMPRESS_PLAYBACK = 0,
|
||||
SND_COMPRESS_CAPTURE
|
||||
SND_COMPRESS_CAPTURE,
|
||||
SND_COMPRESS_ACCEL
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -127,6 +128,59 @@ struct snd_compr_metadata {
|
|||
__u32 value[8];
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
/* flags for struct snd_compr_task */
|
||||
#define SND_COMPRESS_TFLG_NEW_STREAM (1<<0) /* mark for the new stream data */
|
||||
|
||||
/**
|
||||
* struct snd_compr_task - task primitive for non-realtime operation
|
||||
* @seqno: sequence number (task identifier)
|
||||
* @origin_seqno: previous sequence number (task identifier) - for reuse
|
||||
* @input_fd: data input file descriptor (dma-buf)
|
||||
* @output_fd: data output file descriptor (dma-buf)
|
||||
* @input_size: filled data in bytes (from caller, must not exceed fragment size)
|
||||
* @flags: see SND_COMPRESS_TFLG_* defines
|
||||
* @reserved: reserved for future extension
|
||||
*/
|
||||
struct snd_compr_task {
|
||||
__u64 seqno;
|
||||
__u64 origin_seqno;
|
||||
int input_fd;
|
||||
int output_fd;
|
||||
__u64 input_size;
|
||||
__u32 flags;
|
||||
__u8 reserved[16];
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
/**
|
||||
* enum snd_compr_state - task state
|
||||
* @SND_COMPRESS_TASK_STATE_IDLE: task is not queued
|
||||
* @SND_COMPRESS_TASK_STATE_ACTIVE: task is in the queue
|
||||
* @SND_COMPRESS_TASK_STATE_FINISHED: task was processed, output is available
|
||||
*/
|
||||
enum snd_compr_state {
|
||||
SND_COMPRESS_TASK_STATE_IDLE = 0,
|
||||
SND_COMPRESS_TASK_STATE_ACTIVE,
|
||||
SND_COMPRESS_TASK_STATE_FINISHED
|
||||
};
|
||||
|
||||
/**
|
||||
* struct snd_compr_task_status - task status
|
||||
* @seqno: sequence number (task identifier)
|
||||
* @input_size: filled data in bytes (from user space)
|
||||
* @output_size: filled data in bytes (from driver)
|
||||
* @output_flags: reserved for future (all zeros - from driver)
|
||||
* @state: actual task state (SND_COMPRESS_TASK_STATE_*)
|
||||
* @reserved: reserved for future extension
|
||||
*/
|
||||
struct snd_compr_task_status {
|
||||
__u64 seqno;
|
||||
__u64 input_size;
|
||||
__u64 output_size;
|
||||
__u32 output_flags;
|
||||
__u8 state;
|
||||
__u8 reserved[15];
|
||||
} __attribute__((packed, aligned(4)));
|
||||
|
||||
/*
|
||||
* compress path ioctl definitions
|
||||
* SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
|
||||
|
@ -164,6 +218,14 @@ struct snd_compr_metadata {
|
|||
#define SNDRV_COMPRESS_DRAIN _IO('C', 0x34)
|
||||
#define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35)
|
||||
#define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36)
|
||||
|
||||
|
||||
#define SNDRV_COMPRESS_TASK_CREATE _IOWR('C', 0x60, struct snd_compr_task)
|
||||
#define SNDRV_COMPRESS_TASK_FREE _IOW('C', 0x61, __u64)
|
||||
#define SNDRV_COMPRESS_TASK_START _IOWR('C', 0x62, struct snd_compr_task)
|
||||
#define SNDRV_COMPRESS_TASK_STOP _IOW('C', 0x63, __u64)
|
||||
#define SNDRV_COMPRESS_TASK_STATUS _IOWR('C', 0x68, struct snd_compr_task_status)
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* 1. add mmap support
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_ADAU1373 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_AW88081 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_CS42L84 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_ES8323 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_NTP8835 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_NTP8918 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_SMA1307 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_UDA1342 is not set
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH is not set
|
|
@ -0,0 +1 @@
|
|||
CONFIG_SND_SOC_RT721_SDCA_SDW=m
|
|
@ -180,7 +180,7 @@ static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)
|
|||
|
||||
/**
|
||||
* snd_ac97_codec_driver_register - register an AC97 codec driver
|
||||
* @dev: AC97 driver codec to register
|
||||
* @drv: AC97 driver codec to register
|
||||
*
|
||||
* Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital
|
||||
* controller.
|
||||
|
@ -196,7 +196,7 @@ EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register);
|
|||
|
||||
/**
|
||||
* snd_ac97_codec_driver_unregister - unregister an AC97 codec driver
|
||||
* @dev: AC97 codec driver to unregister
|
||||
* @drv: AC97 codec driver to unregister
|
||||
*
|
||||
* Unregister a previously registered ac97 codec driver.
|
||||
*/
|
||||
|
@ -338,6 +338,7 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
|
|||
* @dev: the device providing the ac97 DC function
|
||||
* @slots_available: mask of the ac97 codecs that can be scanned and probed
|
||||
* bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3
|
||||
* @codecs_pdata: codec platform data
|
||||
*
|
||||
* Register a digital controller which can control up to 4 ac97 codecs. This is
|
||||
* the controller side of the AC97 AC-link, while the slave side are the codecs.
|
||||
|
|
|
@ -59,6 +59,9 @@ config SND_CORE_TEST
|
|||
config SND_COMPRESS_OFFLOAD
|
||||
tristate
|
||||
|
||||
config SND_COMPRESS_ACCEL
|
||||
bool
|
||||
|
||||
config SND_JACK
|
||||
bool
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compat.h>
|
||||
#include <sound/core.h>
|
||||
|
@ -54,6 +55,12 @@ struct snd_compr_file {
|
|||
|
||||
static void error_delayed_work(struct work_struct *work);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
static void snd_compr_task_free_all(struct snd_compr_stream *stream);
|
||||
#else
|
||||
static inline void snd_compr_task_free_all(struct snd_compr_stream *stream) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* a note on stream states used:
|
||||
* we use following states in the compressed core
|
||||
|
@ -85,6 +92,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
|||
dirn = SND_COMPRESS_PLAYBACK;
|
||||
else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
|
||||
dirn = SND_COMPRESS_CAPTURE;
|
||||
else if ((f->f_flags & O_ACCMODE) == O_RDWR)
|
||||
dirn = SND_COMPRESS_ACCEL;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -125,6 +134,9 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
|||
}
|
||||
runtime->state = SNDRV_PCM_STATE_OPEN;
|
||||
init_waitqueue_head(&runtime->sleep);
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
INIT_LIST_HEAD(&runtime->tasks);
|
||||
#endif
|
||||
data->stream.runtime = runtime;
|
||||
f->private_data = (void *)data;
|
||||
scoped_guard(mutex, &compr->lock)
|
||||
|
@ -154,6 +166,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
|
|||
break;
|
||||
}
|
||||
|
||||
snd_compr_task_free_all(&data->stream);
|
||||
|
||||
data->stream.ops->free(&data->stream);
|
||||
if (!data->stream.runtime->dma_buffer_p)
|
||||
kfree(data->stream.runtime->buffer);
|
||||
|
@ -226,6 +240,9 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
|
|||
struct snd_compr_avail ioctl_avail;
|
||||
size_t avail;
|
||||
|
||||
if (stream->direction == SND_COMPRESS_ACCEL)
|
||||
return -EBADFD;
|
||||
|
||||
avail = snd_compr_calc_avail(stream, &ioctl_avail);
|
||||
ioctl_avail.avail = avail;
|
||||
|
||||
|
@ -287,6 +304,8 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
|
|||
return -EFAULT;
|
||||
|
||||
stream = &data->stream;
|
||||
if (stream->direction == SND_COMPRESS_ACCEL)
|
||||
return -EBADFD;
|
||||
guard(mutex)(&stream->device->lock);
|
||||
/* write is allowed when stream is running or has been setup */
|
||||
switch (stream->runtime->state) {
|
||||
|
@ -336,6 +355,8 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
|
|||
return -EFAULT;
|
||||
|
||||
stream = &data->stream;
|
||||
if (stream->direction == SND_COMPRESS_ACCEL)
|
||||
return -EBADFD;
|
||||
guard(mutex)(&stream->device->lock);
|
||||
|
||||
/* read is allowed when stream is running, paused, draining and setup
|
||||
|
@ -385,6 +406,7 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
|
|||
{
|
||||
struct snd_compr_file *data = f->private_data;
|
||||
struct snd_compr_stream *stream;
|
||||
struct snd_compr_runtime *runtime;
|
||||
size_t avail;
|
||||
__poll_t retval = 0;
|
||||
|
||||
|
@ -392,10 +414,11 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
|
|||
return EPOLLERR;
|
||||
|
||||
stream = &data->stream;
|
||||
runtime = stream->runtime;
|
||||
|
||||
guard(mutex)(&stream->device->lock);
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
return snd_compr_get_poll(stream) | EPOLLERR;
|
||||
|
@ -403,23 +426,37 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
|
|||
break;
|
||||
}
|
||||
|
||||
poll_wait(f, &stream->runtime->sleep, wait);
|
||||
poll_wait(f, &runtime->sleep, wait);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
if (stream->direction == SND_COMPRESS_ACCEL) {
|
||||
struct snd_compr_task_runtime *task;
|
||||
if (runtime->fragments > runtime->active_tasks)
|
||||
retval |= EPOLLOUT | EPOLLWRNORM;
|
||||
task = list_first_entry_or_null(&runtime->tasks,
|
||||
struct snd_compr_task_runtime,
|
||||
list);
|
||||
if (task && task->state == SND_COMPRESS_TASK_STATE_FINISHED)
|
||||
retval |= EPOLLIN | EPOLLRDNORM;
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
avail = snd_compr_get_avail(stream);
|
||||
pr_debug("avail is %ld\n", (unsigned long)avail);
|
||||
/* check if we have at least one fragment to fill */
|
||||
switch (stream->runtime->state) {
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
/* stream has been woken up after drain is complete
|
||||
* draining done so set stream state to stopped
|
||||
*/
|
||||
retval = snd_compr_get_poll(stream);
|
||||
stream->runtime->state = SNDRV_PCM_STATE_SETUP;
|
||||
runtime->state = SNDRV_PCM_STATE_SETUP;
|
||||
break;
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_PREPARED:
|
||||
case SNDRV_PCM_STATE_PAUSED:
|
||||
if (avail >= stream->runtime->fragment_size)
|
||||
if (avail >= runtime->fragment_size)
|
||||
retval = snd_compr_get_poll(stream);
|
||||
break;
|
||||
default:
|
||||
|
@ -521,6 +558,9 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
|
|||
unsigned int buffer_size;
|
||||
void *buffer = NULL;
|
||||
|
||||
if (stream->direction == SND_COMPRESS_ACCEL)
|
||||
goto params;
|
||||
|
||||
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
|
||||
if (stream->ops->copy) {
|
||||
buffer = NULL;
|
||||
|
@ -543,18 +583,30 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
|
|||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
}
|
||||
stream->runtime->fragment_size = params->buffer.fragment_size;
|
||||
stream->runtime->fragments = params->buffer.fragments;
|
||||
|
||||
stream->runtime->buffer = buffer;
|
||||
stream->runtime->buffer_size = buffer_size;
|
||||
params:
|
||||
stream->runtime->fragment_size = params->buffer.fragment_size;
|
||||
stream->runtime->fragments = params->buffer.fragments;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_compress_check_input(struct snd_compr_params *params)
|
||||
static int
|
||||
snd_compress_check_input(struct snd_compr_stream *stream, struct snd_compr_params *params)
|
||||
{
|
||||
u32 max_fragments;
|
||||
|
||||
/* first let's check the buffer parameter's */
|
||||
if (params->buffer.fragment_size == 0 ||
|
||||
params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
|
||||
if (params->buffer.fragment_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (stream->direction == SND_COMPRESS_ACCEL)
|
||||
max_fragments = 64; /* safe value */
|
||||
else
|
||||
max_fragments = U32_MAX / params->buffer.fragment_size;
|
||||
|
||||
if (params->buffer.fragments > max_fragments ||
|
||||
params->buffer.fragments == 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -583,7 +635,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
|
|||
if (IS_ERR(params))
|
||||
return PTR_ERR(params);
|
||||
|
||||
retval = snd_compress_check_input(params);
|
||||
retval = snd_compress_check_input(stream, params);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -939,6 +991,273 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
|
|||
return snd_compress_wait_for_drain(stream);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
|
||||
static struct snd_compr_task_runtime *
|
||||
snd_compr_find_task(struct snd_compr_stream *stream, __u64 seqno)
|
||||
{
|
||||
struct snd_compr_task_runtime *task;
|
||||
|
||||
list_for_each_entry(task, &stream->runtime->tasks, list) {
|
||||
if (task->seqno == seqno)
|
||||
return task;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void snd_compr_task_free(struct snd_compr_task_runtime *task)
|
||||
{
|
||||
if (task->output)
|
||||
dma_buf_put(task->output);
|
||||
if (task->input)
|
||||
dma_buf_put(task->input);
|
||||
kfree(task);
|
||||
}
|
||||
|
||||
static u64 snd_compr_seqno_next(struct snd_compr_stream *stream)
|
||||
{
|
||||
u64 seqno = ++stream->runtime->task_seqno;
|
||||
if (seqno == 0)
|
||||
seqno = ++stream->runtime->task_seqno;
|
||||
return seqno;
|
||||
}
|
||||
|
||||
static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_task *utask)
|
||||
{
|
||||
struct snd_compr_task_runtime *task;
|
||||
int retval, fd_i, fd_o;
|
||||
|
||||
if (stream->runtime->total_tasks >= stream->runtime->fragments)
|
||||
return -EBUSY;
|
||||
if (utask->origin_seqno != 0 || utask->input_size != 0)
|
||||
return -EINVAL;
|
||||
task = kzalloc(sizeof(*task), GFP_KERNEL);
|
||||
if (task == NULL)
|
||||
return -ENOMEM;
|
||||
task->seqno = utask->seqno = snd_compr_seqno_next(stream);
|
||||
task->input_size = utask->input_size;
|
||||
retval = stream->ops->task_create(stream, task);
|
||||
if (retval < 0)
|
||||
goto cleanup;
|
||||
/* similar functionality as in dma_buf_fd(), but ensure that both
|
||||
file descriptors are allocated before fd_install() */
|
||||
if (!task->input || !task->input->file || !task->output || !task->output->file) {
|
||||
retval = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
|
||||
if (fd_i < 0)
|
||||
goto cleanup;
|
||||
fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
|
||||
if (fd_o < 0) {
|
||||
put_unused_fd(fd_i);
|
||||
goto cleanup;
|
||||
}
|
||||
/* keep dmabuf reference until freed with task free ioctl */
|
||||
get_dma_buf(task->input);
|
||||
get_dma_buf(task->output);
|
||||
fd_install(fd_i, task->input->file);
|
||||
fd_install(fd_o, task->output->file);
|
||||
utask->input_fd = fd_i;
|
||||
utask->output_fd = fd_o;
|
||||
list_add_tail(&task->list, &stream->runtime->tasks);
|
||||
stream->runtime->total_tasks++;
|
||||
return 0;
|
||||
cleanup:
|
||||
snd_compr_task_free(task);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int snd_compr_task_create(struct snd_compr_stream *stream, unsigned long arg)
|
||||
{
|
||||
struct snd_compr_task *task __free(kfree) = NULL;
|
||||
int retval;
|
||||
|
||||
if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
|
||||
return -EPERM;
|
||||
task = memdup_user((void __user *)arg, sizeof(*task));
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
retval = snd_compr_task_new(stream, task);
|
||||
if (retval >= 0)
|
||||
if (copy_to_user((void __user *)arg, task, sizeof(*task)))
|
||||
retval = -EFAULT;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int snd_compr_task_start_prepare(struct snd_compr_task_runtime *task,
|
||||
struct snd_compr_task *utask)
|
||||
{
|
||||
if (task == NULL)
|
||||
return -EINVAL;
|
||||
if (task->state >= SND_COMPRESS_TASK_STATE_FINISHED)
|
||||
return -EBUSY;
|
||||
if (utask->input_size > task->input->size)
|
||||
return -EINVAL;
|
||||
task->flags = utask->flags;
|
||||
task->input_size = utask->input_size;
|
||||
task->state = SND_COMPRESS_TASK_STATE_IDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_compr_task_start(struct snd_compr_stream *stream, struct snd_compr_task *utask)
|
||||
{
|
||||
struct snd_compr_task_runtime *task;
|
||||
int retval;
|
||||
|
||||
if (utask->origin_seqno > 0) {
|
||||
task = snd_compr_find_task(stream, utask->origin_seqno);
|
||||
retval = snd_compr_task_start_prepare(task, utask);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
task->seqno = utask->seqno = snd_compr_seqno_next(stream);
|
||||
utask->origin_seqno = 0;
|
||||
list_move_tail(&task->list, &stream->runtime->tasks);
|
||||
} else {
|
||||
task = snd_compr_find_task(stream, utask->seqno);
|
||||
if (task && task->state != SND_COMPRESS_TASK_STATE_IDLE)
|
||||
return -EBUSY;
|
||||
retval = snd_compr_task_start_prepare(task, utask);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
retval = stream->ops->task_start(stream, task);
|
||||
if (retval >= 0) {
|
||||
task->state = SND_COMPRESS_TASK_STATE_ACTIVE;
|
||||
stream->runtime->active_tasks++;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int snd_compr_task_start_ioctl(struct snd_compr_stream *stream, unsigned long arg)
|
||||
{
|
||||
struct snd_compr_task *task __free(kfree) = NULL;
|
||||
int retval;
|
||||
|
||||
if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
|
||||
return -EPERM;
|
||||
task = memdup_user((void __user *)arg, sizeof(*task));
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
retval = snd_compr_task_start(stream, task);
|
||||
if (retval >= 0)
|
||||
if (copy_to_user((void __user *)arg, task, sizeof(*task)))
|
||||
retval = -EFAULT;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void snd_compr_task_stop_one(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_runtime *task)
|
||||
{
|
||||
if (task->state != SND_COMPRESS_TASK_STATE_ACTIVE)
|
||||
return;
|
||||
stream->ops->task_stop(stream, task);
|
||||
if (!snd_BUG_ON(stream->runtime->active_tasks == 0))
|
||||
stream->runtime->active_tasks--;
|
||||
list_move_tail(&task->list, &stream->runtime->tasks);
|
||||
task->state = SND_COMPRESS_TASK_STATE_IDLE;
|
||||
}
|
||||
|
||||
static void snd_compr_task_free_one(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_runtime *task)
|
||||
{
|
||||
snd_compr_task_stop_one(stream, task);
|
||||
stream->ops->task_free(stream, task);
|
||||
list_del(&task->list);
|
||||
snd_compr_task_free(task);
|
||||
stream->runtime->total_tasks--;
|
||||
}
|
||||
|
||||
static void snd_compr_task_free_all(struct snd_compr_stream *stream)
|
||||
{
|
||||
struct snd_compr_task_runtime *task, *temp;
|
||||
|
||||
list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list)
|
||||
snd_compr_task_free_one(stream, task);
|
||||
}
|
||||
|
||||
typedef void (*snd_compr_seq_func_t)(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_runtime *task);
|
||||
|
||||
static int snd_compr_task_seq(struct snd_compr_stream *stream, unsigned long arg,
|
||||
snd_compr_seq_func_t fcn)
|
||||
{
|
||||
struct snd_compr_task_runtime *task, *temp;
|
||||
__u64 seqno;
|
||||
int retval;
|
||||
|
||||
if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
|
||||
return -EPERM;
|
||||
retval = copy_from_user(&seqno, (__u64 __user *)arg, sizeof(seqno));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
retval = 0;
|
||||
if (seqno == 0) {
|
||||
list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list)
|
||||
fcn(stream, task);
|
||||
} else {
|
||||
task = snd_compr_find_task(stream, seqno);
|
||||
if (task == NULL) {
|
||||
retval = -EINVAL;
|
||||
} else {
|
||||
fcn(stream, task);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int snd_compr_task_status(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_status *status)
|
||||
{
|
||||
struct snd_compr_task_runtime *task;
|
||||
|
||||
task = snd_compr_find_task(stream, status->seqno);
|
||||
if (task == NULL)
|
||||
return -EINVAL;
|
||||
status->input_size = task->input_size;
|
||||
status->output_size = task->output_size;
|
||||
status->state = task->state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_compr_task_status_ioctl(struct snd_compr_stream *stream, unsigned long arg)
|
||||
{
|
||||
struct snd_compr_task_status *status __free(kfree) = NULL;
|
||||
int retval;
|
||||
|
||||
if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
|
||||
return -EPERM;
|
||||
status = memdup_user((void __user *)arg, sizeof(*status));
|
||||
if (IS_ERR(status))
|
||||
return PTR_ERR(status);
|
||||
retval = snd_compr_task_status(stream, status);
|
||||
if (retval >= 0)
|
||||
if (copy_to_user((void __user *)arg, status, sizeof(*status)))
|
||||
retval = -EFAULT;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_compr_task_finished: Notify that the task was finished
|
||||
* @stream: pointer to stream
|
||||
* @task: runtime task structure
|
||||
*
|
||||
* Set the finished task state and notify waiters.
|
||||
*/
|
||||
void snd_compr_task_finished(struct snd_compr_stream *stream,
|
||||
struct snd_compr_task_runtime *task)
|
||||
{
|
||||
guard(mutex)(&stream->device->lock);
|
||||
if (!snd_BUG_ON(stream->runtime->active_tasks == 0))
|
||||
stream->runtime->active_tasks--;
|
||||
task->state = SND_COMPRESS_TASK_STATE_FINISHED;
|
||||
wake_up(&stream->runtime->sleep);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_compr_task_finished);
|
||||
|
||||
MODULE_IMPORT_NS("DMA_BUF");
|
||||
#endif /* CONFIG_SND_COMPRESS_ACCEL */
|
||||
|
||||
static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct snd_compr_file *data = f->private_data;
|
||||
|
@ -968,6 +1287,27 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
|||
return snd_compr_set_metadata(stream, arg);
|
||||
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
|
||||
return snd_compr_get_metadata(stream, arg);
|
||||
}
|
||||
|
||||
if (stream->direction == SND_COMPRESS_ACCEL) {
|
||||
#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case _IOC_NR(SNDRV_COMPRESS_TASK_CREATE):
|
||||
return snd_compr_task_create(stream, arg);
|
||||
case _IOC_NR(SNDRV_COMPRESS_TASK_FREE):
|
||||
return snd_compr_task_seq(stream, arg, snd_compr_task_free_one);
|
||||
case _IOC_NR(SNDRV_COMPRESS_TASK_START):
|
||||
return snd_compr_task_start_ioctl(stream, arg);
|
||||
case _IOC_NR(SNDRV_COMPRESS_TASK_STOP):
|
||||
return snd_compr_task_seq(stream, arg, snd_compr_task_stop_one);
|
||||
case _IOC_NR(SNDRV_COMPRESS_TASK_STATUS):
|
||||
return snd_compr_task_status_ioctl(stream, arg);
|
||||
}
|
||||
#endif
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
|
||||
return snd_compr_tstamp(stream, arg);
|
||||
case _IOC_NR(SNDRV_COMPRESS_AVAIL):
|
||||
|
@ -1140,6 +1480,11 @@ int snd_compress_new(struct snd_card *card, int device,
|
|||
};
|
||||
int ret;
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
|
||||
if (snd_BUG_ON(dirn == SND_COMPRESS_ACCEL))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
compr->card = card;
|
||||
compr->device = device;
|
||||
compr->direction = dirn;
|
||||
|
|
|
@ -3773,6 +3773,26 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
|
|||
}
|
||||
#endif /* coherent mmap */
|
||||
|
||||
/*
|
||||
* snd_pcm_mmap_data_open - increase the mmap counter
|
||||
*/
|
||||
static void snd_pcm_mmap_data_open(struct vm_area_struct *area)
|
||||
{
|
||||
struct snd_pcm_substream *substream = area->vm_private_data;
|
||||
|
||||
atomic_inc(&substream->mmap_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* snd_pcm_mmap_data_close - decrease the mmap counter
|
||||
*/
|
||||
static void snd_pcm_mmap_data_close(struct vm_area_struct *area)
|
||||
{
|
||||
struct snd_pcm_substream *substream = area->vm_private_data;
|
||||
|
||||
atomic_dec(&substream->mmap_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* fault callback for mmapping a RAM page
|
||||
*/
|
||||
|
|
|
@ -370,7 +370,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
|
|||
{
|
||||
struct snd_ump_block *fb, *p;
|
||||
|
||||
if (blk < 0 || blk >= SNDRV_UMP_MAX_BLOCKS)
|
||||
if (blk >= SNDRV_UMP_MAX_BLOCKS)
|
||||
return -EINVAL;
|
||||
|
||||
if (snd_ump_get_block(ump, blk))
|
||||
|
@ -391,7 +391,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
|
|||
fb->info.first_group = first_group;
|
||||
fb->info.num_groups = num_groups;
|
||||
/* fill the default name, may be overwritten to a better name */
|
||||
snprintf(fb->info.name, sizeof(fb->info.name), "Group %d-%d",
|
||||
snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u",
|
||||
first_group + 1, first_group + num_groups);
|
||||
|
||||
/* put the entry in the ordered list */
|
||||
|
|
|
@ -333,53 +333,6 @@ retry_after_bus_reset:
|
|||
}
|
||||
EXPORT_SYMBOL(cmp_connection_establish);
|
||||
|
||||
/**
|
||||
* cmp_connection_update - update the connection after a bus reset
|
||||
* @c: the connection manager
|
||||
*
|
||||
* This function must be called from the driver's .update handler to
|
||||
* reestablish any connection that might have been active.
|
||||
*
|
||||
* Returns zero on success, or a negative error code. On an error, the
|
||||
* connection is broken and the caller must stop transmitting iso packets.
|
||||
*/
|
||||
int cmp_connection_update(struct cmp_connection *c)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&c->mutex);
|
||||
|
||||
if (!c->connected) {
|
||||
mutex_unlock(&c->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = fw_iso_resources_update(&c->resources);
|
||||
if (err < 0)
|
||||
goto err_unconnect;
|
||||
|
||||
if (c->direction == CMP_OUTPUT)
|
||||
err = pcr_modify(c, opcr_set_modify, pcr_set_check,
|
||||
SUCCEED_ON_BUS_RESET);
|
||||
else
|
||||
err = pcr_modify(c, ipcr_set_modify, pcr_set_check,
|
||||
SUCCEED_ON_BUS_RESET);
|
||||
|
||||
if (err < 0)
|
||||
goto err_unconnect;
|
||||
|
||||
mutex_unlock(&c->mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unconnect:
|
||||
c->connected = false;
|
||||
mutex_unlock(&c->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cmp_connection_update);
|
||||
|
||||
static __be32 pcr_break_modify(struct cmp_connection *c, __be32 pcr)
|
||||
{
|
||||
return pcr & ~cpu_to_be32(PCR_BCAST_CONN | PCR_P2P_CONN_MASK);
|
||||
|
|
|
@ -47,7 +47,6 @@ int cmp_connection_reserve(struct cmp_connection *connection,
|
|||
void cmp_connection_release(struct cmp_connection *connection);
|
||||
|
||||
int cmp_connection_establish(struct cmp_connection *connection);
|
||||
int cmp_connection_update(struct cmp_connection *connection);
|
||||
void cmp_connection_break(struct cmp_connection *connection);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -464,7 +464,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
|
||||
hpi_stream_get_info_ex(dpcm->h_stream, NULL,
|
||||
&dpcm->hpi_buffer_attached, NULL, NULL, NULL);
|
||||
}
|
||||
bytes_per_sec = params_rate(params) * params_channels(params);
|
||||
|
|
|
@ -933,6 +933,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
|
|||
bool match_all_pins)
|
||||
{
|
||||
const struct snd_hda_pin_quirk *pq;
|
||||
const char *name = NULL;
|
||||
|
||||
if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
|
||||
return;
|
||||
|
@ -946,9 +947,10 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
|
|||
codec->fixup_id = pq->value;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
codec->fixup_name = pq->name;
|
||||
codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
|
||||
codec->core.chip_name, codec->fixup_name);
|
||||
name = pq->name;
|
||||
#endif
|
||||
codec_info(codec, "%s: picked fixup %s (pin match)\n",
|
||||
codec->core.chip_name, name ? name : "");
|
||||
codec->fixup_list = fixlist;
|
||||
return;
|
||||
}
|
||||
|
@ -1015,8 +1017,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
|
|||
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
|
||||
id = HDA_FIXUP_ID_NO_FIXUP;
|
||||
fixlist = NULL;
|
||||
codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
|
||||
codec->core.chip_name);
|
||||
codec_info(codec, "%s: picked no fixup (nofixup specified)\n",
|
||||
codec->core.chip_name);
|
||||
goto found;
|
||||
}
|
||||
|
||||
|
@ -1026,8 +1028,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
|
|||
if (!strcmp(codec->modelname, models->name)) {
|
||||
id = models->id;
|
||||
name = models->name;
|
||||
codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
|
||||
codec->core.chip_name, codec->fixup_name);
|
||||
codec_info(codec, "%s: picked fixup %s (model specified)\n",
|
||||
codec->core.chip_name, name);
|
||||
goto found;
|
||||
}
|
||||
models++;
|
||||
|
@ -1085,9 +1087,9 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
|
|||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
name = q->name;
|
||||
#endif
|
||||
codec_dbg(codec, "%s: picked fixup %s for %s %04x:%04x\n",
|
||||
codec->core.chip_name, name ? name : "",
|
||||
type, q->subvendor, q->subdevice);
|
||||
codec_info(codec, "%s: picked fixup %s for %s %04x:%04x\n",
|
||||
codec->core.chip_name, name ? name : "",
|
||||
type, q->subvendor, q->subdevice);
|
||||
found:
|
||||
codec->fixup_id = id;
|
||||
codec->fixup_list = fixlist;
|
||||
|
|
|
@ -772,6 +772,14 @@ static void azx_clear_irq_pending(struct azx *chip)
|
|||
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
||||
{
|
||||
struct hdac_bus *bus = azx_bus(chip);
|
||||
int ret;
|
||||
|
||||
if (!chip->msi || pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_MSI) < 0) {
|
||||
ret = pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_INTX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
chip->msi = 0;
|
||||
}
|
||||
|
||||
if (request_irq(chip->pci->irq, azx_interrupt,
|
||||
chip->msi ? 0 : IRQF_SHARED,
|
||||
|
@ -785,7 +793,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
|
|||
}
|
||||
bus->irq = chip->pci->irq;
|
||||
chip->card->sync_irq = bus->irq;
|
||||
pci_intx(chip->pci, !chip->msi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1031,22 +1038,12 @@ static int azx_suspend(struct device *dev)
|
|||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hdac_bus *bus;
|
||||
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
bus = azx_bus(chip);
|
||||
azx_shutdown_chip(chip);
|
||||
if (bus->irq >= 0) {
|
||||
free_irq(bus->irq, chip);
|
||||
bus->irq = -1;
|
||||
chip->card->sync_irq = -1;
|
||||
}
|
||||
|
||||
if (chip->msi)
|
||||
pci_disable_msi(chip->pci);
|
||||
|
||||
trace_azx_suspend(chip);
|
||||
return 0;
|
||||
|
@ -1061,11 +1058,6 @@ static int __maybe_unused azx_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
if (chip->msi)
|
||||
if (pci_enable_msi(chip->pci) < 0)
|
||||
chip->msi = 0;
|
||||
if (azx_acquire_irq(chip, 1) < 0)
|
||||
return -EIO;
|
||||
|
||||
__azx_runtime_resume(chip);
|
||||
|
||||
|
@ -1866,6 +1858,8 @@ static int azx_first_init(struct azx *chip)
|
|||
bus->polling_mode = 1;
|
||||
bus->not_use_interrupts = 1;
|
||||
bus->access_sdnctl_in_dword = 1;
|
||||
if (!chip->jackpoll_interval)
|
||||
chip->jackpoll_interval = msecs_to_jiffies(1500);
|
||||
}
|
||||
|
||||
err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio");
|
||||
|
@ -1891,13 +1885,9 @@ static int azx_first_init(struct azx *chip)
|
|||
chip->gts_present = true;
|
||||
#endif
|
||||
|
||||
if (chip->msi) {
|
||||
if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
|
||||
dev_dbg(card->dev, "Disabling 64bit MSI\n");
|
||||
pci->no_64bit_msi = true;
|
||||
}
|
||||
if (pci_enable_msi(pci) < 0)
|
||||
chip->msi = 0;
|
||||
if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) {
|
||||
dev_dbg(card->dev, "Disabling 64bit MSI\n");
|
||||
pci->no_64bit_msi = true;
|
||||
}
|
||||
|
||||
pci_set_master(pci);
|
||||
|
@ -2049,7 +2039,7 @@ static int disable_msi_reset_irq(struct azx *chip)
|
|||
free_irq(bus->irq, chip);
|
||||
bus->irq = -1;
|
||||
chip->card->sync_irq = -1;
|
||||
pci_disable_msi(chip->pci);
|
||||
pci_free_irq_vectors(chip->pci);
|
||||
chip->msi = 0;
|
||||
err = azx_acquire_irq(chip, 1);
|
||||
if (err < 0)
|
||||
|
|
|
@ -6491,6 +6491,16 @@ static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */
|
||||
static void alc294_fixup_bass_speaker_15(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
||||
static const hda_nid_t conn[] = { 0x02, 0x03 };
|
||||
snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hook to update amp GPIO4 for automute */
|
||||
static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
|
||||
struct hda_jack_callback *jack)
|
||||
|
@ -7780,6 +7790,7 @@ enum {
|
|||
ALC245_FIXUP_CLEVO_NOISY_MIC,
|
||||
ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
|
||||
ALC233_FIXUP_MEDION_MTL_SPK,
|
||||
ALC294_FIXUP_BASS_SPEAKER_15,
|
||||
};
|
||||
|
||||
/* A special fixup for Lenovo C940 and Yoga Duet 7;
|
||||
|
@ -10114,6 +10125,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
{ }
|
||||
},
|
||||
},
|
||||
[ALC294_FIXUP_BASS_SPEAKER_15] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc294_fixup_bass_speaker_15,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
|
@ -10633,6 +10648,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
|
||||
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
|
@ -10930,8 +10946,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/hda_codec.h>
|
||||
|
@ -110,10 +111,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };
|
||||
|
||||
static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
|
||||
{ "speakerid-gpios", &speakerid_gpios, 1 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
struct device *physdev;
|
||||
LIST_HEAD(resources);
|
||||
const char *sub;
|
||||
uint32_t subid;
|
||||
int ret;
|
||||
|
||||
adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
|
||||
|
@ -123,18 +134,50 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
physdev = get_device(acpi_get_first_physical_node(adev));
|
||||
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(p->dev, "Failed to get ACPI resource.\n");
|
||||
goto err;
|
||||
}
|
||||
sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
|
||||
if (IS_ERR(sub)) {
|
||||
/* No subsys id in older tas2563 projects. */
|
||||
if (!strncmp(hid, "INT8866", sizeof("INT8866")))
|
||||
goto end_2563;
|
||||
dev_err(p->dev, "Failed to get SUBSYS ID.\n");
|
||||
ret = PTR_ERR(sub);
|
||||
goto err;
|
||||
}
|
||||
/* Speaker id was needed for ASUS projects. */
|
||||
ret = kstrtou32(sub, 16, &subid);
|
||||
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
||||
ret = devm_acpi_dev_add_driver_gpios(p->dev,
|
||||
tas2781_speaker_id_gpios);
|
||||
if (ret < 0)
|
||||
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
||||
ret);
|
||||
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
|
||||
if (IS_ERR(p->speaker_id)) {
|
||||
dev_err(p->dev, "Failed to get Speaker id.\n");
|
||||
ret = PTR_ERR(p->speaker_id);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
p->speaker_id = NULL;
|
||||
}
|
||||
|
||||
end_2563:
|
||||
acpi_dev_free_resource_list(&resources);
|
||||
strscpy(p->dev_name, hid, sizeof(p->dev_name));
|
||||
put_device(physdev);
|
||||
acpi_dev_put(adev);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev_err(p->dev, "read acpi error, ret: %d\n", ret);
|
||||
put_device(physdev);
|
||||
acpi_dev_put(adev);
|
||||
|
||||
return ret;
|
||||
|
@ -615,7 +658,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
|
|||
struct tasdevice_priv *tas_priv = context;
|
||||
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
|
||||
struct hda_codec *codec = tas_priv->codec;
|
||||
int i, ret;
|
||||
int i, ret, spk_id;
|
||||
|
||||
pm_runtime_get_sync(tas_priv->dev);
|
||||
mutex_lock(&tas_priv->codec_lock);
|
||||
|
@ -648,8 +691,25 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
|
|||
tasdevice_dsp_remove(tas_priv);
|
||||
|
||||
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
||||
scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin",
|
||||
codec->core.subsystem_id & 0xffff);
|
||||
if (tas_priv->speaker_id != NULL) {
|
||||
// Speaker id need to be checked for ASUS only.
|
||||
spk_id = gpiod_get_value(tas_priv->speaker_id);
|
||||
if (spk_id < 0) {
|
||||
// Speaker id is not valid, use default.
|
||||
dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
|
||||
spk_id = 0;
|
||||
}
|
||||
snprintf(tas_priv->coef_binaryname,
|
||||
sizeof(tas_priv->coef_binaryname),
|
||||
"TAS2XXX%04X%d.bin",
|
||||
lower_16_bits(codec->core.subsystem_id),
|
||||
spk_id);
|
||||
} else {
|
||||
snprintf(tas_priv->coef_binaryname,
|
||||
sizeof(tas_priv->coef_binaryname),
|
||||
"TAS2XXX%04X.bin",
|
||||
lower_16_bits(codec->core.subsystem_id));
|
||||
}
|
||||
ret = tasdevice_dsp_parser(tas_priv);
|
||||
if (ret) {
|
||||
dev_err(tas_priv->dev, "dspfw load %s error\n",
|
||||
|
|
|
@ -170,14 +170,9 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
|
|||
tmp = stac9460_get(ice, idx);
|
||||
ovol = 0x7f - (tmp & 0x7f);
|
||||
change = (ovol != nvol);
|
||||
if (change) {
|
||||
ovol = (0x7f - nvol) | (tmp & 0x80);
|
||||
/*
|
||||
dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n",
|
||||
idx, ovol);
|
||||
*/
|
||||
if (change)
|
||||
stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
|
|
@ -312,8 +312,6 @@ static void aica_period_elapsed(struct timer_list *t)
|
|||
static void spu_begin_dma(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_card_aica *dreamcastcard;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
runtime = substream->runtime;
|
||||
dreamcastcard = substream->pcm->private_data;
|
||||
/*get the queue to do the work */
|
||||
schedule_work(&(dreamcastcard->spu_dma_work));
|
||||
|
|
|
@ -95,6 +95,7 @@ source "sound/soc/pxa/Kconfig"
|
|||
source "sound/soc/qcom/Kconfig"
|
||||
source "sound/soc/rockchip/Kconfig"
|
||||
source "sound/soc/samsung/Kconfig"
|
||||
source "sound/soc/sdca/Kconfig"
|
||||
source "sound/soc/sh/Kconfig"
|
||||
source "sound/soc/sof/Kconfig"
|
||||
source "sound/soc/spear/Kconfig"
|
||||
|
|
|
@ -59,6 +59,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
|
|||
obj-$(CONFIG_SND_SOC) += qcom/
|
||||
obj-$(CONFIG_SND_SOC) += rockchip/
|
||||
obj-$(CONFIG_SND_SOC) += samsung/
|
||||
obj-$(CONFIG_SND_SOC) += sdca/
|
||||
obj-$(CONFIG_SND_SOC) += sh/
|
||||
obj-$(CONFIG_SND_SOC) += sof/
|
||||
obj-$(CONFIG_SND_SOC) += spear/
|
||||
|
|
|
@ -163,6 +163,7 @@ config SND_SOC_AMD_SOUNDWIRE
|
|||
config SND_SOC_AMD_PS
|
||||
tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
|
||||
select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
|
||||
select SND_SOC_ACPI_AMD_MATCH
|
||||
depends on X86 && PCI && ACPI
|
||||
help
|
||||
This option enables Audio Coprocessor i.e ACP v6.3 support on
|
||||
|
|
|
@ -542,7 +542,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.init = cz_da7219_init,
|
||||
.dpcm_playback = 1,
|
||||
.playback_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_da7219_play_ops,
|
||||
SND_SOC_DAILINK_REG(designware1, dlgs, platform),
|
||||
|
@ -552,7 +552,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
.stream_name = "Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_da7219_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware2, dlgs, platform),
|
||||
|
@ -562,7 +562,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
.stream_name = "HiFi Playback",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_playback = 1,
|
||||
.playback_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_max_play_ops,
|
||||
SND_SOC_DAILINK_REG(designware3, mx, platform),
|
||||
|
@ -573,7 +573,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
.stream_name = "DMIC0 Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_dmic0_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware3, adau, platform),
|
||||
|
@ -584,7 +584,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
|
|||
.stream_name = "DMIC1 Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_dmic1_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware2, adau, platform),
|
||||
|
@ -598,7 +598,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
|
|||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.init = cz_rt5682_init,
|
||||
.dpcm_playback = 1,
|
||||
.playback_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_rt5682_play_ops,
|
||||
SND_SOC_DAILINK_REG(designware1, rt5682, platform),
|
||||
|
@ -608,7 +608,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
|
|||
.stream_name = "Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_rt5682_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware2, rt5682, platform),
|
||||
|
@ -618,7 +618,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
|
|||
.stream_name = "HiFi Playback",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_playback = 1,
|
||||
.playback_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_rt5682_max_play_ops,
|
||||
SND_SOC_DAILINK_REG(designware3, mx, platform),
|
||||
|
@ -629,7 +629,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
|
|||
.stream_name = "DMIC0 Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_rt5682_dmic0_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware3, adau, platform),
|
||||
|
@ -640,7 +640,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
|
|||
.stream_name = "DMIC1 Capture",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.dpcm_capture = 1,
|
||||
.capture_only = 1,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.ops = &cz_rt5682_dmic1_cap_ops,
|
||||
SND_SOC_DAILINK_REG(designware2, adau, platform),
|
||||
|
|
|
@ -150,8 +150,6 @@ static struct snd_soc_dai_link st_dai_es8336[] = {
|
|||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP,
|
||||
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
|
||||
.dpcm_capture = 1,
|
||||
.dpcm_playback = 1,
|
||||
.init = st_es8336_init,
|
||||
.ops = &st_es8336_ops,
|
||||
SND_SOC_DAILINK_REG(designware1, codec, platform),
|
||||
|
|
|
@ -119,10 +119,17 @@ config SND_SOC_AMD_SOF_MACH
|
|||
help
|
||||
This option enables SOF sound card support for ACP audio.
|
||||
|
||||
config SND_SOC_AMD_SDW_MACH_COMMON
|
||||
tristate
|
||||
help
|
||||
This option enables common SoundWire Machine driver module for
|
||||
AMD platforms.
|
||||
|
||||
config SND_SOC_AMD_SOF_SDW_MACH
|
||||
tristate "AMD SOF Soundwire Machine Driver Support"
|
||||
depends on X86 && PCI && ACPI
|
||||
depends on SOUNDWIRE
|
||||
select SND_SOC_AMD_SDW_MACH_COMMON
|
||||
select SND_SOC_SDW_UTILS
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_RT711_SDW
|
||||
|
@ -137,6 +144,28 @@ config SND_SOC_AMD_SOF_SDW_MACH
|
|||
on AMD platform.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_AMD_LEGACY_SDW_MACH
|
||||
tristate "AMD Legacy(No DSP) Soundwire Machine Driver Support"
|
||||
depends on X86 && PCI && ACPI
|
||||
depends on SOUNDWIRE
|
||||
select SND_SOC_AMD_SDW_MACH_COMMON
|
||||
select SND_SOC_SDW_UTILS
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_RT711_SDW
|
||||
select SND_SOC_RT711_SDCA_SDW
|
||||
select SND_SOC_RT712_SDCA_SDW
|
||||
select SND_SOC_RT712_SDCA_DMIC_SDW
|
||||
select SND_SOC_RT1316_SDW
|
||||
select SND_SOC_RT715_SDW
|
||||
select SND_SOC_RT715_SDCA_SDW
|
||||
select SND_SOC_RT722_SDCA_SDW
|
||||
help
|
||||
This option enables Legacy(No DSP) sound card support for SoundWire
|
||||
enabled AMD platforms along with ACP PDM controller.
|
||||
Say Y if you want to enable SoundWire based machine driver support
|
||||
on AMD platform.
|
||||
If unsure select "N".
|
||||
|
||||
endif # SND_SOC_AMD_ACP_COMMON
|
||||
|
||||
config SND_AMD_SOUNDWIRE_ACPI
|
||||
|
|
|
@ -23,7 +23,9 @@ snd-acp-mach-y := acp-mach-common.o
|
|||
snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o
|
||||
snd-acp-sof-mach-y := acp-sof-mach.o
|
||||
snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o
|
||||
snd-acp-sdw-mach-y := acp-sdw-mach-common.o
|
||||
snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o
|
||||
snd-acp-sdw-legacy-mach-y += acp-sdw-legacy-mach.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o
|
||||
|
@ -41,4 +43,6 @@ obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
|
|||
obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o
|
||||
obj-$(CONFIG_SND_SOC_ACPI_AMD_MATCH) += snd-soc-acpi-amd-match.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_SDW_MACH_COMMON) += snd-acp-sdw-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH) += snd-acp-sdw-legacy-mach.o
|
||||
|
|
|
@ -59,9 +59,9 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
|
|||
val |= BIT(1);
|
||||
|
||||
switch (chip->acp_rev) {
|
||||
case ACP63_DEV:
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div);
|
||||
val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div);
|
||||
break;
|
||||
|
@ -121,8 +121,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
|
|||
}
|
||||
|
||||
switch (chip->acp_rev) {
|
||||
case ACP3X_DEV:
|
||||
case ACP6X_DEV:
|
||||
case ACP_RN_PCI_ID:
|
||||
case ACP_RMB_PCI_ID:
|
||||
switch (slots) {
|
||||
case 1 ... 7:
|
||||
no_of_slots = slots;
|
||||
|
@ -135,9 +135,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
|
|||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case ACP63_DEV:
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
switch (slots) {
|
||||
case 1 ... 31:
|
||||
no_of_slots = slots;
|
||||
|
@ -160,8 +160,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
|
|||
spin_lock_irq(&adata->acp_lock);
|
||||
list_for_each_entry(stream, &adata->stream_list, list) {
|
||||
switch (chip->acp_rev) {
|
||||
case ACP3X_DEV:
|
||||
case ACP6X_DEV:
|
||||
case ACP_RN_PCI_ID:
|
||||
case ACP_RMB_PCI_ID:
|
||||
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
adata->tdm_tx_fmt[stream->dai_id - 1] =
|
||||
FRM_LEN | (slots << 15) | (slot_len << 18);
|
||||
|
@ -169,9 +169,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
|
|||
adata->tdm_rx_fmt[stream->dai_id - 1] =
|
||||
FRM_LEN | (slots << 15) | (slot_len << 18);
|
||||
break;
|
||||
case ACP63_DEV:
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
adata->tdm_tx_fmt[stream->dai_id - 1] =
|
||||
FRM_LEN | (slots << 13) | (slot_len << 18);
|
||||
|
@ -534,7 +534,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
|
||||
reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
@ -546,7 +546,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
|
||||
reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
@ -561,7 +561,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
|
||||
reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
@ -573,7 +573,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
|
||||
reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
@ -588,7 +588,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_HS_TX_FIFOADDR;
|
||||
reg_fifo_size = ACP_HS_TX_FIFOSIZE;
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
@ -600,7 +600,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
|
|||
reg_fifo_addr = ACP_HS_RX_FIFOADDR;
|
||||
reg_fifo_size = ACP_HS_RX_FIFOSIZE;
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
|
||||
else
|
||||
phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
|
||||
|
|
|
@ -257,20 +257,20 @@ static int acp_power_on(struct acp_chip_info *chip)
|
|||
|
||||
base = chip->base;
|
||||
switch (chip->acp_rev) {
|
||||
case ACP3X_DEV:
|
||||
case ACP_RN_PCI_ID:
|
||||
acp_pgfsm_stat_reg = ACP_PGFSM_STATUS;
|
||||
acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL;
|
||||
break;
|
||||
case ACP6X_DEV:
|
||||
case ACP_RMB_PCI_ID:
|
||||
acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;
|
||||
acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;
|
||||
break;
|
||||
case ACP63_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS;
|
||||
acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL;
|
||||
break;
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS;
|
||||
acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL;
|
||||
break;
|
||||
|
@ -322,7 +322,7 @@ int acp_init(struct acp_chip_info *chip)
|
|||
pr_err("ACP reset failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
writel(0, chip->base + ACP_ZSC_DSP_CTRL);
|
||||
return 0;
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ int acp_deinit(struct acp_chip_info *chip)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (chip->acp_rev < ACP70_DEV)
|
||||
if (chip->acp_rev < ACP70_PCI_ID)
|
||||
writel(0, chip->base + ACP_CONTROL);
|
||||
else
|
||||
writel(0x01, chip->base + ACP_ZSC_DSP_CTRL);
|
||||
|
@ -448,20 +448,20 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
|
|||
u32 pdm_addr;
|
||||
|
||||
switch (chip->acp_rev) {
|
||||
case ACP3X_DEV:
|
||||
case ACP_RN_PCI_ID:
|
||||
pdm_addr = ACP_RENOIR_PDM_ADDR;
|
||||
check_acp3x_config(chip);
|
||||
break;
|
||||
case ACP6X_DEV:
|
||||
case ACP_RMB_PCI_ID:
|
||||
pdm_addr = ACP_REMBRANDT_PDM_ADDR;
|
||||
check_acp6x_config(chip);
|
||||
break;
|
||||
case ACP63_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
pdm_addr = ACP63_PDM_ADDR;
|
||||
check_acp6x_config(chip);
|
||||
break;
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
pdm_addr = ACP70_PDM_ADDR;
|
||||
check_acp70_config(chip);
|
||||
break;
|
||||
|
|
|
@ -57,7 +57,6 @@ static struct acp_card_drvdata es83xx_rn_data = {
|
|||
.dmic_cpu_id = DMIC,
|
||||
.hs_codec_id = ES83XX,
|
||||
.dmic_codec_id = DMIC,
|
||||
.platform = RENOIR,
|
||||
};
|
||||
|
||||
static struct acp_card_drvdata max_nau8825_data = {
|
||||
|
@ -68,7 +67,6 @@ static struct acp_card_drvdata max_nau8825_data = {
|
|||
.amp_codec_id = MAX98360A,
|
||||
.dmic_codec_id = DMIC,
|
||||
.soc_mclk = true,
|
||||
.platform = REMBRANDT,
|
||||
.tdm_mode = false,
|
||||
};
|
||||
|
||||
|
@ -80,7 +78,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
|
|||
.amp_codec_id = RT1019,
|
||||
.dmic_codec_id = DMIC,
|
||||
.soc_mclk = true,
|
||||
.platform = REMBRANDT,
|
||||
.tdm_mode = false,
|
||||
};
|
||||
|
||||
|
@ -126,6 +123,7 @@ static int acp_asoc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_card *card = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
struct acp_card_drvdata *acp_card_drvdata;
|
||||
int ret;
|
||||
|
@ -171,7 +169,9 @@ static int acp_asoc_probe(struct platform_device *pdev)
|
|||
goto out;
|
||||
}
|
||||
if (!strcmp(pdev->name, "acp-pdm-mach"))
|
||||
acp_card_drvdata->platform = *((int *)dev->platform_data);
|
||||
acp_card_drvdata->acp_rev = *((int *)dev->platform_data);
|
||||
else
|
||||
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
|
||||
|
||||
dmi_id = dmi_first_match(acp_quirk_table);
|
||||
if (dmi_id && dmi_id->driver_data)
|
||||
|
|
|
@ -1407,8 +1407,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(sof_sp);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->hs_codec_id) {
|
||||
|
@ -1444,8 +1442,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(sof_hs);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->hs_codec_id) {
|
||||
|
@ -1471,7 +1467,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
if (drv_data->amp_cpu_id == I2S_SP) {
|
||||
links[i].name = "acp-amp-codec";
|
||||
links[i].id = AMP_BE_ID;
|
||||
if (drv_data->platform == RENOIR) {
|
||||
if (drv_data->acp_rev == ACP_RN_PCI_ID) {
|
||||
links[i].cpus = sof_sp;
|
||||
links[i].num_cpus = ARRAY_SIZE(sof_sp);
|
||||
} else {
|
||||
|
@ -1480,7 +1476,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
}
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].playback_only = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
|
@ -1512,7 +1508,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].playback_only = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
|
@ -1527,7 +1523,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].init = acp_card_maxim_init;
|
||||
}
|
||||
if (drv_data->amp_codec_id == MAX98388) {
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].playback_only = 0;
|
||||
links[i].codecs = max98388;
|
||||
links[i].num_codecs = ARRAY_SIZE(max98388);
|
||||
links[i].ops = &acp_max98388_ops;
|
||||
|
@ -1553,8 +1549,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(sof_bt);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->bt_codec_id) {
|
||||
|
@ -1574,7 +1568,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(sof_dmic);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].capture_only = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
}
|
||||
|
@ -1613,8 +1607,6 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
if (!drv_data->hs_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = &snd_soc_dummy_dlc;
|
||||
|
@ -1647,18 +1639,21 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].id = HEADSET_BE_ID;
|
||||
links[i].cpus = i2s_hs;
|
||||
links[i].num_cpus = ARRAY_SIZE(i2s_hs);
|
||||
if (drv_data->platform == REMBRANDT) {
|
||||
switch (drv_data->acp_rev) {
|
||||
case ACP_RMB_PCI_ID:
|
||||
links[i].platforms = platform_rmb_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
|
||||
} else if (drv_data->platform == ACP63) {
|
||||
break;
|
||||
case ACP63_PCI_ID:
|
||||
links[i].platforms = platform_acp63_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
break;
|
||||
}
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
|
||||
if (!drv_data->hs_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = &snd_soc_dummy_dlc;
|
||||
|
@ -1686,7 +1681,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].playback_only = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = &snd_soc_dummy_dlc;
|
||||
|
@ -1714,17 +1709,22 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
links[i].id = AMP_BE_ID;
|
||||
links[i].cpus = i2s_hs;
|
||||
links[i].num_cpus = ARRAY_SIZE(i2s_hs);
|
||||
if (drv_data->platform == REMBRANDT) {
|
||||
switch (drv_data->acp_rev) {
|
||||
case ACP_RMB_PCI_ID:
|
||||
links[i].platforms = platform_rmb_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
|
||||
} else if (drv_data->platform == ACP63) {
|
||||
break;
|
||||
case ACP63_PCI_ID:
|
||||
links[i].platforms = platform_acp63_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
break;
|
||||
}
|
||||
links[i].dpcm_playback = 1;
|
||||
|
||||
links[i].playback_only = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = &snd_soc_dummy_dlc;
|
||||
|
@ -1749,6 +1749,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
|
||||
if (drv_data->dmic_cpu_id == DMIC) {
|
||||
links[i].name = "acp-dmic-codec";
|
||||
links[i].stream_name = "DMIC capture";
|
||||
links[i].id = DMIC_BE_ID;
|
||||
if (drv_data->dmic_codec_id == DMIC) {
|
||||
links[i].codecs = dmic_codec;
|
||||
|
@ -1760,21 +1761,27 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
|||
}
|
||||
links[i].cpus = pdm_dmic;
|
||||
links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
|
||||
if (drv_data->platform == REMBRANDT) {
|
||||
switch (drv_data->acp_rev) {
|
||||
case ACP_RMB_PCI_ID:
|
||||
links[i].platforms = platform_rmb_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
|
||||
} else if (drv_data->platform == ACP63) {
|
||||
break;
|
||||
case ACP63_PCI_ID:
|
||||
links[i].platforms = platform_acp63_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
|
||||
} else if ((drv_data->platform == ACP70) || (drv_data->platform == ACP71)) {
|
||||
break;
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
links[i].platforms = platform_acp70_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_acp70_component);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
break;
|
||||
}
|
||||
links[i].ops = &acp_card_dmic_ops;
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].capture_only = 1;
|
||||
}
|
||||
|
||||
card->dai_link = links;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "acp_common.h"
|
||||
|
||||
#define TDM_CHANNELS 8
|
||||
|
||||
#define ACP_OPS(priv, cb) ((priv)->ops.cb)
|
||||
|
@ -51,14 +53,6 @@ enum codec_endpoints {
|
|||
ES83XX,
|
||||
};
|
||||
|
||||
enum platform_end_point {
|
||||
RENOIR = 0,
|
||||
REMBRANDT,
|
||||
ACP63,
|
||||
ACP70,
|
||||
ACP71,
|
||||
};
|
||||
|
||||
struct acp_mach_ops {
|
||||
int (*probe)(struct snd_soc_card *card);
|
||||
int (*configure_link)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
|
||||
|
@ -77,7 +71,7 @@ struct acp_card_drvdata {
|
|||
unsigned int bt_codec_id;
|
||||
unsigned int dmic_codec_id;
|
||||
unsigned int dai_fmt;
|
||||
unsigned int platform;
|
||||
unsigned int acp_rev;
|
||||
struct clk *wclk;
|
||||
struct clk *bclk;
|
||||
struct acp_mach_ops ops;
|
||||
|
|
|
@ -77,27 +77,22 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
|
|||
|
||||
res_acp = acp_res;
|
||||
num_res = ARRAY_SIZE(acp_res);
|
||||
|
||||
chip->acp_rev = pci->revision;
|
||||
switch (pci->revision) {
|
||||
case 0x01:
|
||||
chip->name = "acp_asoc_renoir";
|
||||
chip->acp_rev = ACP3X_DEV;
|
||||
break;
|
||||
case 0x6f:
|
||||
chip->name = "acp_asoc_rembrandt";
|
||||
chip->acp_rev = ACP6X_DEV;
|
||||
break;
|
||||
case 0x63:
|
||||
chip->name = "acp_asoc_acp63";
|
||||
chip->acp_rev = ACP63_DEV;
|
||||
break;
|
||||
case 0x70:
|
||||
chip->name = "acp_asoc_acp70";
|
||||
chip->acp_rev = ACP70_DEV;
|
||||
break;
|
||||
case 0x71:
|
||||
chip->name = "acp_asoc_acp70";
|
||||
chip->acp_rev = ACP71_DEV;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
|
||||
|
|
|
@ -47,7 +47,7 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream,
|
|||
size_dmic = frames_to_bytes(substream->runtime,
|
||||
substream->runtime->buffer_size);
|
||||
|
||||
if (chip->acp_rev >= ACP70_DEV)
|
||||
if (chip->acp_rev >= ACP70_PCI_ID)
|
||||
physical_addr = ACP7x_DMIC_MEM_WINDOW_START;
|
||||
else
|
||||
physical_addr = stream->reg_offset + MEM_WINDOW_START;
|
||||
|
|
|
@ -114,7 +114,7 @@ int acp_machine_select(struct acp_dev_data *adata)
|
|||
int size, platform;
|
||||
|
||||
if (adata->flag == FLAG_AMD_LEGACY_ONLY_DMIC) {
|
||||
platform = adata->platform;
|
||||
platform = adata->acp_rev;
|
||||
adata->mach_dev = platform_device_register_data(adata->dev, "acp-pdm-mach",
|
||||
PLATFORM_DEVID_NONE, &platform,
|
||||
sizeof(platform));
|
||||
|
@ -125,6 +125,7 @@ int acp_machine_select(struct acp_dev_data *adata)
|
|||
dev_err(adata->dev, "warning: No matching ASoC machine driver found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mach->mach_params.subsystem_rev = adata->acp_rev;
|
||||
adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name,
|
||||
PLATFORM_DEVID_NONE, mach, size);
|
||||
}
|
||||
|
@ -142,9 +143,6 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
|
|||
u16 i2s_flag = 0;
|
||||
u32 ext_intr_stat, ext_intr_stat1;
|
||||
|
||||
if (!adata)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (adata->rsrc->no_of_ctrls == 2)
|
||||
ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
|
||||
|
||||
|
@ -204,9 +202,9 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s
|
|||
u32 low, high, val;
|
||||
u16 page_idx;
|
||||
|
||||
switch (adata->platform) {
|
||||
case ACP70:
|
||||
case ACP71:
|
||||
switch (adata->acp_rev) {
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
switch (stream->dai_id) {
|
||||
case I2S_SP_INSTANCE:
|
||||
if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
@ -270,9 +268,9 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
|
|||
stream->substream = substream;
|
||||
chip = dev_get_platdata(dev);
|
||||
switch (chip->acp_rev) {
|
||||
case ACP63_DEV:
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP63_PCI_ID:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
runtime->hw = acp6x_pcm_hardware_playback;
|
||||
else
|
||||
|
|
|
@ -197,7 +197,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (chip->acp_rev != ACP6X_DEV) {
|
||||
if (chip->acp_rev != ACP_RMB_PCI_ID) {
|
||||
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
|
|||
adata->dai_driver = acp_rmb_dai;
|
||||
adata->num_dai = ARRAY_SIZE(acp_rmb_dai);
|
||||
adata->rsrc = &rsrc;
|
||||
adata->platform = REMBRANDT;
|
||||
adata->acp_rev = chip->acp_rev;
|
||||
adata->flag = chip->flag;
|
||||
adata->is_i2s_config = chip->is_i2s_config;
|
||||
adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
|
||||
|
|
|
@ -157,7 +157,7 @@ static int renoir_audio_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (chip->acp_rev != ACP3X_DEV) {
|
||||
if (chip->acp_rev != ACP_RN_PCI_ID) {
|
||||
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ static int renoir_audio_probe(struct platform_device *pdev)
|
|||
adata->dai_driver = acp_renoir_dai;
|
||||
adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
|
||||
adata->rsrc = &rsrc;
|
||||
adata->platform = RENOIR;
|
||||
adata->acp_rev = chip->acp_rev;
|
||||
adata->flag = chip->flag;
|
||||
|
||||
adata->machines = snd_soc_acpi_amd_acp_machines;
|
||||
|
|
|
@ -0,0 +1,486 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2024 Advanced Micro Devices, Inc.
|
||||
|
||||
/*
|
||||
* acp-sdw-legacy-mach - ASoC legacy Machine driver for AMD SoundWire platforms
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include "soc_amd_sdw_common.h"
|
||||
#include "../../codecs/rt711.h"
|
||||
|
||||
static unsigned long soc_sdw_quirk = RT711_JD1;
|
||||
static int quirk_override = -1;
|
||||
module_param_named(quirk, quirk_override, int, 0444);
|
||||
MODULE_PARM_DESC(quirk, "Board-specific quirk override");
|
||||
|
||||
static void log_quirks(struct device *dev)
|
||||
{
|
||||
if (SOC_JACK_JDSRC(soc_sdw_quirk))
|
||||
dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
|
||||
SOC_JACK_JDSRC(soc_sdw_quirk));
|
||||
if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC)
|
||||
dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n");
|
||||
}
|
||||
|
||||
static int soc_sdw_quirk_cb(const struct dmi_system_id *id)
|
||||
{
|
||||
soc_sdw_quirk = (unsigned long)id->driver_data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id soc_sdw_quirk_table[] = {
|
||||
{
|
||||
.callback = soc_sdw_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "AMD"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"),
|
||||
},
|
||||
.driver_data = (void *)RT711_JD2,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_ops sdw_ops = {
|
||||
.startup = asoc_sdw_startup,
|
||||
.prepare = asoc_sdw_prepare,
|
||||
.trigger = asoc_sdw_trigger,
|
||||
.hw_params = asoc_sdw_hw_params,
|
||||
.hw_free = asoc_sdw_hw_free,
|
||||
.shutdown = asoc_sdw_shutdown,
|
||||
};
|
||||
|
||||
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
|
||||
|
||||
static int create_sdw_dailink(struct snd_soc_card *card,
|
||||
struct asoc_sdw_dailink *soc_dai,
|
||||
struct snd_soc_dai_link **dai_links,
|
||||
int *be_id, struct snd_soc_codec_conf **codec_conf,
|
||||
struct snd_soc_dai_link_component *sdw_platform_component)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
|
||||
struct asoc_sdw_endpoint *soc_end;
|
||||
int cpu_pin_id;
|
||||
int stream;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
|
||||
if (soc_end->name_prefix) {
|
||||
(*codec_conf)->dlc.name = soc_end->codec_name;
|
||||
(*codec_conf)->name_prefix = soc_end->name_prefix;
|
||||
(*codec_conf)++;
|
||||
}
|
||||
|
||||
if (soc_end->include_sidecar) {
|
||||
ret = soc_end->codec_info->add_sidecar(card, dai_links, codec_conf);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_pcm_streams(stream) {
|
||||
static const char * const sdw_stream_name[] = {
|
||||
"SDW%d-PIN%d-PLAYBACK",
|
||||
"SDW%d-PIN%d-CAPTURE",
|
||||
"SDW%d-PIN%d-PLAYBACK-%s",
|
||||
"SDW%d-PIN%d-CAPTURE-%s",
|
||||
};
|
||||
struct snd_soc_dai_link_ch_map *codec_maps;
|
||||
struct snd_soc_dai_link_component *codecs;
|
||||
struct snd_soc_dai_link_component *cpus;
|
||||
int num_cpus = hweight32(soc_dai->link_mask[stream]);
|
||||
int num_codecs = soc_dai->num_devs[stream];
|
||||
int playback, capture;
|
||||
int j = 0;
|
||||
char *name;
|
||||
|
||||
if (!soc_dai->num_devs[stream])
|
||||
continue;
|
||||
|
||||
soc_end = list_first_entry(&soc_dai->endpoints,
|
||||
struct asoc_sdw_endpoint, list);
|
||||
|
||||
*be_id = soc_end->dai_info->dailink[stream];
|
||||
if (*be_id < 0) {
|
||||
dev_err(dev, "Invalid dailink id %d\n", *be_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (amd_ctx->acp_rev) {
|
||||
case ACP63_PCI_REV:
|
||||
ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask - 1),
|
||||
*be_id, &cpu_pin_id, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* create stream name according to first link id */
|
||||
if (ctx->append_dai_type) {
|
||||
name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
sdw_stream_name[stream + 2],
|
||||
ffs(soc_end->link_mask) - 1,
|
||||
cpu_pin_id,
|
||||
type_strings[soc_end->dai_info->dai_type]);
|
||||
} else {
|
||||
name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
sdw_stream_name[stream],
|
||||
ffs(soc_end->link_mask) - 1,
|
||||
cpu_pin_id);
|
||||
}
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
|
||||
if (!cpus)
|
||||
return -ENOMEM;
|
||||
|
||||
codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
|
||||
if (!codecs)
|
||||
return -ENOMEM;
|
||||
|
||||
codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
|
||||
if (!codec_maps)
|
||||
return -ENOMEM;
|
||||
|
||||
list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
|
||||
if (!soc_end->dai_info->direction[stream])
|
||||
continue;
|
||||
|
||||
int link_num = ffs(soc_end->link_mask) - 1;
|
||||
|
||||
cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"SDW%d Pin%d",
|
||||
link_num, cpu_pin_id);
|
||||
dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name);
|
||||
if (!cpus->dai_name)
|
||||
return -ENOMEM;
|
||||
|
||||
codec_maps[j].cpu = 0;
|
||||
codec_maps[j].codec = j;
|
||||
|
||||
codecs[j].name = soc_end->codec_name;
|
||||
codecs[j].dai_name = soc_end->dai_info->dai_name;
|
||||
j++;
|
||||
}
|
||||
|
||||
WARN_ON(j != num_codecs);
|
||||
|
||||
playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
|
||||
capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
|
||||
|
||||
asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
|
||||
cpus, num_cpus, sdw_platform_component,
|
||||
1, codecs, num_codecs,
|
||||
0, asoc_sdw_rtd_init, &sdw_ops);
|
||||
/*
|
||||
* SoundWire DAILINKs use 'stream' functions and Bank Switch operations
|
||||
* based on wait_for_completion(), tag them as 'nonatomic'.
|
||||
*/
|
||||
(*dai_links)->nonatomic = true;
|
||||
(*dai_links)->ch_maps = codec_maps;
|
||||
|
||||
list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
|
||||
if (soc_end->dai_info->init)
|
||||
soc_end->dai_info->init(card, *dai_links,
|
||||
soc_end->codec_info,
|
||||
playback);
|
||||
}
|
||||
|
||||
(*dai_links)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_sdw_dailinks(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link **dai_links, int *be_id,
|
||||
struct asoc_sdw_dailink *soc_dais,
|
||||
struct snd_soc_codec_conf **codec_conf)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
|
||||
struct snd_soc_dai_link_component *sdw_platform_component;
|
||||
int ret;
|
||||
|
||||
sdw_platform_component = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
|
||||
GFP_KERNEL);
|
||||
if (!sdw_platform_component)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (amd_ctx->acp_rev) {
|
||||
case ACP63_PCI_REV:
|
||||
sdw_platform_component->name = "amd_ps_sdw_dma.0";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* generate DAI links by each sdw link */
|
||||
while (soc_dais->initialised) {
|
||||
int current_be_id;
|
||||
|
||||
ret = create_sdw_dailink(card, soc_dais, dai_links,
|
||||
¤t_be_id, codec_conf, sdw_platform_component);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update the be_id to match the highest ID used for SDW link */
|
||||
if (*be_id < current_be_id)
|
||||
*be_id = current_be_id;
|
||||
|
||||
soc_dais++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_dmic_dailinks(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
|
||||
struct snd_soc_dai_link_component *pdm_cpu;
|
||||
struct snd_soc_dai_link_component *pdm_platform;
|
||||
int ret;
|
||||
|
||||
pdm_cpu = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
|
||||
if (!pdm_cpu)
|
||||
return -ENOMEM;
|
||||
|
||||
pdm_platform = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
|
||||
if (!pdm_platform)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (amd_ctx->acp_rev) {
|
||||
case ACP63_PCI_REV:
|
||||
pdm_cpu->name = "acp_ps_pdm_dma.0";
|
||||
pdm_platform->name = "acp_ps_pdm_dma.0";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*be_id = ACP_DMIC_BE_ID;
|
||||
ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec",
|
||||
0, 1, // DMIC only supports capture
|
||||
pdm_cpu->name, pdm_platform->name, 1,
|
||||
"dmic-codec.0", "dmic-hifi", no_pcm,
|
||||
asoc_sdw_dmic_init, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
(*dai_links)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int soc_card_dai_links_create(struct snd_soc_card *card)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
|
||||
int sdw_be_num = 0, dmic_num = 0;
|
||||
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
|
||||
struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL;
|
||||
struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL;
|
||||
struct snd_soc_codec_conf *codec_conf;
|
||||
struct snd_soc_dai_link *dai_links;
|
||||
int num_devs = 0;
|
||||
int num_ends = 0;
|
||||
int num_links;
|
||||
int be_id = 0;
|
||||
int ret;
|
||||
|
||||
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* One per DAI link, worst case is a DAI link for every endpoint */
|
||||
soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL);
|
||||
if (!soc_dais)
|
||||
return -ENOMEM;
|
||||
|
||||
/* One per endpoint, ie. each DAI on each codec/amp */
|
||||
soc_ends = kcalloc(num_ends, sizeof(*soc_ends), GFP_KERNEL);
|
||||
if (!soc_ends)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
sdw_be_num = ret;
|
||||
|
||||
/* enable dmic */
|
||||
if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num)
|
||||
dmic_num = 1;
|
||||
|
||||
dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
|
||||
|
||||
codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
|
||||
if (!codec_conf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate BE dailinks */
|
||||
num_links = sdw_be_num + dmic_num;
|
||||
dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
|
||||
if (!dai_links)
|
||||
return -ENOMEM;
|
||||
|
||||
card->codec_conf = codec_conf;
|
||||
card->num_configs = num_devs;
|
||||
card->dai_link = dai_links;
|
||||
card->num_links = num_links;
|
||||
|
||||
/* SDW */
|
||||
if (sdw_be_num) {
|
||||
ret = create_sdw_dailinks(card, &dai_links, &be_id,
|
||||
soc_dais, &codec_conf);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* dmic */
|
||||
if (dmic_num > 0) {
|
||||
if (ctx->ignore_internal_dmic) {
|
||||
dev_warn(dev, "Ignoring ACP DMIC\n");
|
||||
} else {
|
||||
ret = create_dmic_dailinks(card, &dai_links, &be_id, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON(codec_conf != card->codec_conf + card->num_configs);
|
||||
WARN_ON(dai_links != card->dai_link + card->num_links);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
|
||||
struct snd_soc_card *card;
|
||||
struct amd_mc_ctx *amd_ctx;
|
||||
struct asoc_sdw_mc_private *ctx;
|
||||
int amp_num = 0, i;
|
||||
int ret;
|
||||
|
||||
amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL);
|
||||
if (!amd_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
amd_ctx->acp_rev = mach->mach_params.subsystem_rev;
|
||||
amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS;
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
|
||||
ctx->private = amd_ctx;
|
||||
card = &ctx->card;
|
||||
card->dev = &pdev->dev;
|
||||
card->name = "amd-soundwire";
|
||||
card->owner = THIS_MODULE;
|
||||
card->late_probe = asoc_sdw_card_late_probe;
|
||||
|
||||
snd_soc_card_set_drvdata(card, ctx);
|
||||
|
||||
dmi_check_system(soc_sdw_quirk_table);
|
||||
|
||||
if (quirk_override != -1) {
|
||||
dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
|
||||
soc_sdw_quirk, quirk_override);
|
||||
soc_sdw_quirk = quirk_override;
|
||||
}
|
||||
|
||||
log_quirks(card->dev);
|
||||
|
||||
ctx->mc_quirk = soc_sdw_quirk;
|
||||
dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
|
||||
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
|
||||
for (i = 0; i < ctx->codec_info_list_count; i++)
|
||||
codec_info_list[i].amp_num = 0;
|
||||
|
||||
ret = soc_card_dai_links_create(card);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* the default amp_num is zero for each codec and
|
||||
* amp_num will only be increased for active amp
|
||||
* codecs on used platform
|
||||
*/
|
||||
for (i = 0; i < ctx->codec_info_list_count; i++)
|
||||
amp_num += codec_info_list[i].amp_num;
|
||||
|
||||
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
|
||||
" cfg-amp:%d", amp_num);
|
||||
if (!card->components)
|
||||
return -ENOMEM;
|
||||
if (mach->mach_params.dmic_num) {
|
||||
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
|
||||
"%s mic:dmic cfg-mics:%d",
|
||||
card->components,
|
||||
mach->mach_params.dmic_num);
|
||||
if (!card->components)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Register the card */
|
||||
ret = devm_snd_soc_register_card(card->dev, card);
|
||||
if (ret) {
|
||||
dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
|
||||
asoc_sdw_mc_dailink_exit_loop(card);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
asoc_sdw_mc_dailink_exit_loop(card);
|
||||
}
|
||||
|
||||
static const struct platform_device_id mc_id_table[] = {
|
||||
{ "amd_sdw", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mc_id_table);
|
||||
|
||||
static struct platform_driver soc_sdw_driver = {
|
||||
.driver = {
|
||||
.name = "amd_sdw",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = mc_probe,
|
||||
.remove_new = mc_remove,
|
||||
.id_table = mc_id_table,
|
||||
};
|
||||
|
||||
module_platform_driver(soc_sdw_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AMD SoundWire Legacy Generic Machine driver");
|
||||
MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SDW_UTILS);
|
||||
MODULE_IMPORT_NS(SND_SOC_AMD_SDW_MACH);
|
|
@ -0,0 +1,64 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2024 Advanced Micro Devices, Inc.
|
||||
|
||||
/*
|
||||
* acp-sdw-mach-common - Common machine driver helper functions for
|
||||
* legacy(No DSP) stack and SOF stack.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include "soc_amd_sdw_common.h"
|
||||
|
||||
int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev)
|
||||
{
|
||||
switch (sdw_link_id) {
|
||||
case AMD_SDW0:
|
||||
switch (be_id) {
|
||||
case SOC_SDW_JACK_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO0_TX;
|
||||
break;
|
||||
case SOC_SDW_JACK_IN_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO0_RX;
|
||||
break;
|
||||
case SOC_SDW_AMP_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO1_TX;
|
||||
break;
|
||||
case SOC_SDW_AMP_IN_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO1_RX;
|
||||
break;
|
||||
case SOC_SDW_DMIC_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO2_RX;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid be id:%d\n", be_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMD_SDW1:
|
||||
switch (be_id) {
|
||||
case SOC_SDW_JACK_OUT_DAI_ID:
|
||||
case SOC_SDW_AMP_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW1_AUDIO0_TX;
|
||||
break;
|
||||
case SOC_SDW_JACK_IN_DAI_ID:
|
||||
case SOC_SDW_AMP_IN_DAI_ID:
|
||||
case SOC_SDW_DMIC_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW1_AUDIO0_RX;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid be_id:%d\n", be_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid link id:%d\n", sdw_link_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(get_acp63_cpu_pin_id, SND_SOC_AMD_SDW_MACH);
|
||||
|
||||
MODULE_DESCRIPTION("AMD SoundWire Common Machine driver");
|
||||
MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -64,54 +64,6 @@ static const struct snd_soc_ops sdw_ops = {
|
|||
.shutdown = asoc_sdw_shutdown,
|
||||
};
|
||||
|
||||
static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev)
|
||||
{
|
||||
switch (sdw_link_id) {
|
||||
case AMD_SDW0:
|
||||
switch (be_id) {
|
||||
case SOC_SDW_JACK_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO0_TX;
|
||||
break;
|
||||
case SOC_SDW_JACK_IN_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO0_RX;
|
||||
break;
|
||||
case SOC_SDW_AMP_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO1_TX;
|
||||
break;
|
||||
case SOC_SDW_AMP_IN_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO1_RX;
|
||||
break;
|
||||
case SOC_SDW_DMIC_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW0_AUDIO2_RX;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid be id:%d\n", be_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AMD_SDW1:
|
||||
switch (be_id) {
|
||||
case SOC_SDW_JACK_OUT_DAI_ID:
|
||||
case SOC_SDW_AMP_OUT_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW1_AUDIO0_TX;
|
||||
break;
|
||||
case SOC_SDW_JACK_IN_DAI_ID:
|
||||
case SOC_SDW_AMP_IN_DAI_ID:
|
||||
case SOC_SDW_DMIC_DAI_ID:
|
||||
*cpu_pin_id = ACP63_SW1_AUDIO0_RX;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid be_id:%d\n", be_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid link id:%d\n", sdw_link_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
|
||||
|
||||
static int create_sdw_dailink(struct snd_soc_card *card,
|
||||
|
@ -236,7 +188,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
|
|||
asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
|
||||
cpus, num_cpus, platform_component,
|
||||
ARRAY_SIZE(platform_component), codecs, num_codecs,
|
||||
asoc_sdw_rtd_init, &sdw_ops);
|
||||
1, asoc_sdw_rtd_init, &sdw_ops);
|
||||
|
||||
/*
|
||||
* SoundWire DAILINKs use 'stream' functions and Bank Switch operations
|
||||
|
@ -285,7 +237,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
|
|||
}
|
||||
|
||||
static int create_dmic_dailinks(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link **dai_links, int *be_id)
|
||||
struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm)
|
||||
{
|
||||
struct device *dev = card->dev;
|
||||
int ret;
|
||||
|
@ -294,7 +246,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card,
|
|||
0, 1, // DMIC only supports capture
|
||||
"acp-sof-dmic", platform_component->name,
|
||||
ARRAY_SIZE(platform_component),
|
||||
"dmic-codec", "dmic-hifi",
|
||||
"dmic-codec", "dmic-hifi", no_pcm,
|
||||
asoc_sdw_dmic_init, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -377,7 +329,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
if (ctx->ignore_internal_dmic) {
|
||||
dev_warn(dev, "Ignoring ACP DMIC\n");
|
||||
} else {
|
||||
ret = create_dmic_dailinks(card, &dai_links, &be_id);
|
||||
ret = create_dmic_dailinks(card, &dai_links, &be_id, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -491,3 +443,4 @@ MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver");
|
|||
MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SDW_UTILS);
|
||||
MODULE_IMPORT_NS(SND_SOC_AMD_SDW_MACH);
|
||||
|
|
|
@ -46,7 +46,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
|
|||
.hs_codec_id = RT5682S,
|
||||
.amp_codec_id = RT1019,
|
||||
.dmic_codec_id = DMIC,
|
||||
.platform = RENOIR,
|
||||
};
|
||||
|
||||
static struct acp_card_drvdata sof_rt5682s_max_data = {
|
||||
|
@ -56,7 +55,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
|
|||
.hs_codec_id = RT5682S,
|
||||
.amp_codec_id = MAX98360A,
|
||||
.dmic_codec_id = DMIC,
|
||||
.platform = RENOIR,
|
||||
};
|
||||
|
||||
static struct acp_card_drvdata sof_nau8825_data = {
|
||||
|
@ -66,7 +64,6 @@ static struct acp_card_drvdata sof_nau8825_data = {
|
|||
.hs_codec_id = NAU8825,
|
||||
.amp_codec_id = MAX98360A,
|
||||
.dmic_codec_id = DMIC,
|
||||
.platform = REMBRANDT,
|
||||
.soc_mclk = true,
|
||||
};
|
||||
|
||||
|
@ -77,7 +74,6 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
|
|||
.hs_codec_id = RT5682S,
|
||||
.amp_codec_id = RT1019,
|
||||
.dmic_codec_id = DMIC,
|
||||
.platform = REMBRANDT,
|
||||
.soc_mclk = true,
|
||||
};
|
||||
|
||||
|
@ -94,6 +90,7 @@ static int acp_sof_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_card *card = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
|
||||
const struct dmi_system_id *dmi_id;
|
||||
struct acp_card_drvdata *acp_card_drvdata;
|
||||
int ret;
|
||||
|
@ -116,6 +113,7 @@ static int acp_sof_probe(struct platform_device *pdev)
|
|||
if (dmi_id && dmi_id->driver_data)
|
||||
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
|
||||
|
||||
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
|
||||
ret = acp_sofdsp_dai_links_create(card);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n");
|
||||
|
|
|
@ -207,7 +207,7 @@ static int acp63_audio_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (chip->acp_rev != ACP63_DEV) {
|
||||
if (chip->acp_rev != ACP63_PCI_ID) {
|
||||
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ static int acp63_audio_probe(struct platform_device *pdev)
|
|||
adata->dai_driver = acp63_dai;
|
||||
adata->num_dai = ARRAY_SIZE(acp63_dai);
|
||||
adata->rsrc = &rsrc;
|
||||
adata->platform = ACP63;
|
||||
adata->acp_rev = chip->acp_rev;
|
||||
adata->flag = chip->flag;
|
||||
adata->is_i2s_config = chip->is_i2s_config;
|
||||
adata->machines = snd_soc_acpi_amd_acp63_acp_machines;
|
||||
|
|
|
@ -142,9 +142,9 @@ static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata)
|
|||
struct pci_dev *smn_dev;
|
||||
u32 device_id;
|
||||
|
||||
if (adata->platform == ACP70)
|
||||
if (adata->acp_rev == ACP70_PCI_ID)
|
||||
device_id = 0x1507;
|
||||
else if (adata->platform == ACP71)
|
||||
else if (adata->acp_rev == ACP71_PCI_ID)
|
||||
device_id = 0x1122;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
@ -175,8 +175,8 @@ static int acp_acp70_audio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
switch (chip->acp_rev) {
|
||||
case ACP70_DEV:
|
||||
case ACP71_DEV:
|
||||
case ACP70_PCI_ID:
|
||||
case ACP71_PCI_ID:
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
|
||||
|
@ -209,11 +209,7 @@ static int acp_acp70_audio_probe(struct platform_device *pdev)
|
|||
adata->num_dai = ARRAY_SIZE(acp70_dai);
|
||||
adata->rsrc = &rsrc;
|
||||
adata->machines = snd_soc_acpi_amd_acp70_acp_machines;
|
||||
if (chip->acp_rev == ACP70_DEV)
|
||||
adata->platform = ACP70;
|
||||
else
|
||||
adata->platform = ACP71;
|
||||
|
||||
adata->acp_rev = chip->acp_rev;
|
||||
adata->flag = chip->flag;
|
||||
acp_machine_select(adata);
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* acp_common.h - acp common header file
|
||||
*/
|
||||
|
||||
#ifndef __ACP_COMMON_H
|
||||
#define __ACP_COMMON_H
|
||||
|
||||
#define ACP_RN_PCI_ID 0x01
|
||||
#define ACP_VANGOGH_PCI_ID 0x50
|
||||
#define ACP_RMB_PCI_ID 0x6F
|
||||
#define ACP63_PCI_ID 0x63
|
||||
#define ACP70_PCI_ID 0x70
|
||||
#define ACP71_PCI_ID 0x71
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue